auto import from //branches/cupcake_rel/...@141571

This commit is contained in:
The Android Open Source Project
2009-03-19 23:08:36 -07:00
parent 6ffae015b4
commit b0bdccc71a
36 changed files with 2967 additions and 198 deletions

190
apps/CustomLocale/NOTICE Normal file
View File

@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

190
apps/Development/NOTICE Normal file
View File

@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

190
apps/SdkSetup/NOTICE Normal file
View File

@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

190
apps/SpareParts/NOTICE Normal file
View File

@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

190
apps/launchperf/NOTICE Normal file
View File

@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -41,7 +41,9 @@ Require-Bundle: com.android.ide.eclipse.ddms,
org.eclipse.wst.xml.core,
org.eclipse.wst.xml.ui,
org.eclipse.jdt.junit,
org.eclipse.jdt.junit.runtime
org.eclipse.jdt.junit.runtime,
org.eclipse.ltk.core.refactoring,
org.eclipse.ltk.ui.refactoring
Eclipse-LazyStart: true
Export-Package: com.android.ide.eclipse.adt,
com.android.ide.eclipse.adt.build;x-friends:="com.android.ide.eclipse.tests",

View File

@@ -470,7 +470,7 @@
point="org.eclipse.ui.actionSets">
<actionSet
description="Android Wizards"
id="adt.actionSet1"
id="adt.actionSet.wizards"
label="Android Wizards"
visible="true">
<action
@@ -481,12 +481,6 @@
style="push"
toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android XML file">
<enablement>
<objectState
name="projectNature"
value="com.android.ide.eclipse.adt.AndroidNature">
</objectState>
</enablement>
</action>
<action
class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
@@ -498,6 +492,21 @@
tooltip="Opens a wizard to help create a new Android project">
</action>
</actionSet>
<actionSet
description="Refactorings for Android"
id="adt.actionSet.refactorings"
label="Android Refactorings"
visible="true">
<action
class="com.android.ide.eclipse.adt.refactorings.extractstring.ExtractStringAction"
definitionId="com.android.ide.eclipse.adt.refactoring.extract.string"
id="com.android.ide.eclipse.adt.actions.ExtractString"
label="Extract Android String"
menubarPath="org.eclipse.jdt.ui.refactoring.menu/codingGroup"
style="push"
tooltip="Extracts a string into Android resource string">
</action>
</actionSet>
</extension>
<extension
point="org.eclipse.debug.core.launchDelegates">
@@ -506,7 +515,7 @@
delegateDescription="Removes the Android JAR from the Bootstrap Classpath"
id="com.android.ide.eclipse.adt.launch.JUnitLaunchConfigDelegate.launchAndroidJunit"
modes="run,debug"
name="Android JUnit"
name="Android JUnit Test"
type="org.eclipse.jdt.junit.launchconfig">
</launchDelegate>
</extension>
@@ -516,7 +525,7 @@
delegate="com.android.ide.eclipse.adt.launch.junit.AndroidJUnitLaunchConfigDelegate"
id="com.android.ide.eclipse.adt.junit.launchConfigurationType"
modes="run,debug"
name="Android Instrumentation"
name="Android JUnit Test"
public="true"
sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer">
@@ -534,7 +543,7 @@
point="org.eclipse.debug.ui.launchConfigurationTabGroups">
<launchConfigurationTabGroup
class="com.android.ide.eclipse.adt.launch.junit.AndroidJUnitTabGroup"
description="Android Instrumentation"
description="Android JUnit Test"
id="com.android.ide.eclipse.adt.junit.AndroidJUnitLaunchConfigTabGroup"
type="com.android.ide.eclipse.adt.junit.launchConfigurationType"/>
</extension>
@@ -544,7 +553,7 @@
class="com.android.ide.eclipse.adt.launch.junit.AndroidJUnitLaunchShortcut"
icon="icons/android.png"
id="com.android.ide.eclipse.adt.junit.launchShortcut"
label="Android Instrumentation"
label="Android JUnit Test"
modes="run,debug">
<contextualLaunch>
<enablement>
@@ -565,4 +574,25 @@
</configurationType>
</shortcut>
</extension>
<extension
point="org.eclipse.ui.commands">
<category
description="Refactorings for Android Projects"
id="com.android.ide.eclipse.adt.refactoring.category"
name="Android Refactorings">
</category>
<command
categoryId="com.android.ide.eclipse.adt.refactoring.category"
description="Extract Strings into Android String Resources"
id="com.android.ide.eclipse.adt.refactoring.extract.string"
name="Extract Android String">
</command>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.refactoringContributions">
<contribution
class="com.android.ide.eclipse.adt.refactorings.extractstring.ExtractStringContribution"
id="com.android.ide.eclipse.adt.refactoring.extract.string">
</contribution>
</extension>
</plugin>

View File

@@ -1282,7 +1282,7 @@ public class AdtPlugin extends AbstractUIPlugin {
AdtPlugin.PLUGIN_ID,
UNKNOWN_EDITOR);
try {
file.setPersistentProperty(qname, "1");
file.setPersistentProperty(qname, "1"); //$NON-NLS-1$
} catch (CoreException e) {
// pass
}

View File

@@ -196,7 +196,7 @@ public class ApkBuilder extends BaseBuilder {
}
// build() returns a list of project from which this project depends for future compilation.
@SuppressWarnings("unchecked") //$NON-NLS-1$
@SuppressWarnings("unchecked")
@Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {

View File

@@ -197,7 +197,7 @@ public class PreCompilerBuilder extends BaseBuilder {
}
// build() returns a list of project from which this project depends for future compilation.
@SuppressWarnings("unchecked") //$NON-NLS-1$
@SuppressWarnings("unchecked")
@Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {

View File

@@ -55,7 +55,7 @@ public class ResourceManagerBuilder extends BaseBuilder {
}
// build() returns a list of project from which this project depends for future compilation.
@SuppressWarnings("unchecked") //$NON-NLS-1$
@SuppressWarnings("unchecked")
@Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {

View File

@@ -32,7 +32,29 @@ public class AndroidLaunchConfiguration {
*/
public int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION;
public static final boolean AUTO_TARGET_MODE = true;
public enum TargetMode {
AUTO(true), MANUAL(false);
private boolean mValue;
TargetMode(boolean value) {
mValue = value;
}
public boolean getValue() {
return mValue;
}
public static TargetMode getMode(boolean value) {
for (TargetMode mode : values()) {
if (mode.mValue == value) {
return mode;
}
}
return null;
}
}
/**
* Target selection mode.
@@ -41,7 +63,7 @@ public class AndroidLaunchConfiguration {
* <li><code>false</code>: manual mode</li>
* </ul>
*/
public boolean mTargetMode = LaunchConfigDelegate.DEFAULT_TARGET_MODE;
public TargetMode mTargetMode = LaunchConfigDelegate.DEFAULT_TARGET_MODE;
/**
* Indicates whether the emulator should be called with -wipe-data
@@ -81,8 +103,9 @@ public class AndroidLaunchConfiguration {
}
try {
mTargetMode = config.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
mTargetMode);
boolean value = config.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
mTargetMode.getValue());
mTargetMode = TargetMode.getMode(value);
} catch (CoreException e) {
// nothing to be done here, we'll use the default value
}

View File

@@ -29,11 +29,15 @@ import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.SyncService;
import com.android.ddmlib.SyncService.SyncResult;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode;
import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo.InstallRetryMode;
import com.android.ide.eclipse.adt.launch.DeviceChooserDialog.DeviceChooserResponse;
import com.android.ide.eclipse.adt.project.ProjectHelper;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkManager;
import com.android.sdklib.avd.AvdManager;
@@ -52,6 +56,9 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IVMConnector;
import org.eclipse.jdt.launching.JavaRuntime;
@@ -64,6 +71,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -236,7 +244,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
// set default target mode
wc.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
LaunchConfigDelegate.DEFAULT_TARGET_MODE);
LaunchConfigDelegate.DEFAULT_TARGET_MODE.getValue());
// default AVD: None
wc.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String) null);
@@ -332,6 +340,16 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
Sdk currentSdk = Sdk.getCurrent();
AvdManager avdManager = currentSdk.getAvdManager();
// reload the AVDs to make sure we are up to date
try {
avdManager.reloadAvds();
} catch (AndroidLocationException e1) {
// this happens if the AVD Manager failed to find the folder in which the AVDs are
// stored. This is unlikely to happen, but if it does, we should force to go manual
// to allow using physical devices.
config.mTargetMode = TargetMode.MANUAL;
}
// get the project target
final IAndroidTarget projectTarget = currentSdk.getTarget(project);
@@ -356,7 +374,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
* If == 1, launch the application on this AVD/device.
*/
if (config.mTargetMode == AndroidLaunchConfiguration.AUTO_TARGET_MODE) {
if (config.mTargetMode == TargetMode.AUTO) {
// if we are in automatic target mode, we need to find the current devices
IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
@@ -795,6 +813,14 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
return false;
}
// The app is now installed, now try the dependent projects
for (DelayedLaunchInfo dependentLaunchInfo : getDependenciesLaunchInfo(launchInfo)) {
String msg = String.format("Project dependency found, syncing: %s",
dependentLaunchInfo.getProject().getName());
AdtPlugin.printToConsole(launchInfo.getProject(), msg);
syncApp(dependentLaunchInfo, device);
}
return installResult;
}
@@ -806,6 +832,81 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
return false;
}
/**
* For the current launchInfo, create additional DelayedLaunchInfo that should be used to
* sync APKs that we are dependent on to the device.
*
* @param launchInfo the original launch info that we want to find the
* @return a list of DelayedLaunchInfo (may be empty if no dependencies were found or error)
*/
public List<DelayedLaunchInfo> getDependenciesLaunchInfo(DelayedLaunchInfo launchInfo) {
List<DelayedLaunchInfo> dependencies = new ArrayList<DelayedLaunchInfo>();
// Convert to equivalent JavaProject
IJavaProject javaProject;
try {
//assuming this is an Android (and Java) project since it is attached to the launchInfo.
javaProject = BaseProjectHelper.getJavaProject(launchInfo.getProject());
} catch (CoreException e) {
// return empty dependencies
AdtPlugin.printErrorToConsole(launchInfo.getProject(), e);
return dependencies;
}
// Get all projects that this depends on
List<IJavaProject> androidProjectList;
try {
androidProjectList = ProjectHelper.getAndroidProjectDependencies(javaProject);
} catch (JavaModelException e) {
// return empty dependencies
AdtPlugin.printErrorToConsole(launchInfo.getProject(), e);
return dependencies;
}
// for each project, parse manifest and create launch information
for (IJavaProject androidProject : androidProjectList) {
// Parse the Manifest to get various required information
// copied from LaunchConfigDelegate
AndroidManifestParser manifestParser;
try {
manifestParser = AndroidManifestParser.parse(
androidProject, null /* errorListener */,
true /* gatherData */, false /* markErrors */);
} catch (CoreException e) {
AdtPlugin.printErrorToConsole(
launchInfo.getProject(),
String.format("Error parsing manifest of %s",
androidProject.getElementName()));
continue;
}
// Get the APK location (can return null)
IFile apk = ProjectHelper.getApplicationPackage(androidProject.getProject());
if (apk == null) {
// getApplicationPackage will have logged an error message
continue;
}
// Create new launchInfo as an hybrid between parent and dependency information
DelayedLaunchInfo delayedLaunchInfo = new DelayedLaunchInfo(
androidProject.getProject(),
manifestParser.getPackage(),
launchInfo.getLaunchAction(),
apk,
manifestParser.getDebuggable(),
manifestParser.getApiLevelRequirement(),
launchInfo.getLaunch(),
launchInfo.getMonitor());
// Add to the list
dependencies.add(delayedLaunchInfo);
}
return dependencies;
}
/**
* Installs the application package that was pushed to a temporary location on the device.
* @param launchInfo The launch information

View File

@@ -17,6 +17,7 @@
package com.android.ide.eclipse.adt.launch;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.ide.eclipse.ddms.DdmsPlugin;
@@ -292,14 +293,15 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
public void initializeFrom(ILaunchConfiguration configuration) {
AvdManager avdManager = Sdk.getCurrent().getAvdManager();
boolean value = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic
TargetMode mode = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic
try {
value = configuration.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, value);
mode = TargetMode.getMode(configuration.getAttribute(
LaunchConfigDelegate.ATTR_TARGET_MODE, mode.getValue()));
} catch (CoreException e) {
// let's not do anything here, we'll use the default value
}
mAutoTargetButton.setSelection(value);
mManualTargetButton.setSelection(!value);
mAutoTargetButton.setSelection(mode.getValue());
mManualTargetButton.setSelection(!mode.getValue());
// look for the project name to get its target.
String stringValue = "";
@@ -354,7 +356,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
mPreferredAvdSelector.setSelection(null);
}
value = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
boolean value = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
try {
value = configuration.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, value);
} catch (CoreException e) {
@@ -440,7 +442,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
*/
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
LaunchConfigDelegate.DEFAULT_TARGET_MODE);
LaunchConfigDelegate.DEFAULT_TARGET_MODE.getValue());
configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
LaunchConfigDelegate.DEFAULT_SPEED);
configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY,

View File

@@ -18,15 +18,14 @@ package com.android.ide.eclipse.adt.launch;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode;
import com.android.ide.eclipse.adt.project.ProjectHelper;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
@@ -51,7 +50,7 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
/** Target mode parameters: true is automatic, false is manual */
public static final String ATTR_TARGET_MODE = AdtPlugin.PLUGIN_ID + ".target"; //$NON-NLS-1$
public static final boolean DEFAULT_TARGET_MODE = true; //automatic mode
public static final TargetMode DEFAULT_TARGET_MODE = TargetMode.AUTO;
/**
* Launch action:
@@ -152,7 +151,7 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
AdtPlugin.printToConsole(project, "Android Launch!");
// check if the project is using the proper sdk.
// if that throws an exception, we simply let it propage to the caller.
// if that throws an exception, we simply let it propagate to the caller.
if (checkAndroidProject(project) == false) {
AdtPlugin.printErrorToConsole(project, "Project is not an Android Project. Aborting!");
androidLaunch.stopLaunch();
@@ -215,7 +214,7 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
AndroidLaunchController controller = AndroidLaunchController.getInstance();
// get the application package
IFile applicationPackage = getApplicationPackage(project);
IFile applicationPackage = ProjectHelper.getApplicationPackage(project);
if (applicationPackage == null) {
androidLaunch.stopLaunch();
return;
@@ -387,39 +386,6 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
}
/**
* Returns the android package file as an IFile object for the specified
* project.
* @param project The project
* @return The android package as an IFile object or null if not found.
*/
private IFile getApplicationPackage(IProject project) {
// get the output folder
IFolder outputLocation = BaseProjectHelper.getOutputFolder(project);
if (outputLocation == null) {
AdtPlugin.printErrorToConsole(project,
"Failed to get the output location of the project. Check build path properties"
);
return null;
}
// get the package path
String packageName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
IResource r = outputLocation.findMember(packageName);
// check the package is present
if (r instanceof IFile && r.exists()) {
return (IFile)r;
}
String msg = String.format("Could not find %1$s!", packageName);
AdtPlugin.printErrorToConsole(project, msg);
return null;
}
/**
* Returns the name of the activity.
*/

View File

@@ -58,7 +58,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
/**
*
*/
public static final String LAUNCH_TAB_IMAGE = "mainLaunchTab.png";
public static final String LAUNCH_TAB_IMAGE = "mainLaunchTab.png"; //$NON-NLS-1$
protected static final String EMPTY_STRING = ""; //$NON-NLS-1$

View File

@@ -20,7 +20,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo;
import com.android.ide.eclipse.adt.launch.IAndroidLaunchAction;
import com.android.ide.eclipse.adt.launch.junit.runtime.AndroidJUnitLaunchInfo;
import com.android.ide.eclipse.adt.launch.junit.runtime.RemoteADTTestRunner;
import com.android.ide.eclipse.adt.launch.junit.runtime.RemoteAdtTestRunner;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -166,7 +166,7 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction {
private final VMRunnerConfiguration mRunConfig;
private final ILaunch mLaunch;
private final AndroidJUnitLaunchInfo mJUnitInfo;
private RemoteADTTestRunner mTestRunner = null;
private RemoteAdtTestRunner mTestRunner = null;
private boolean mIsTerminated = false;
TestRunnerProcess(VMRunnerConfiguration runConfig, ILaunch launch,
@@ -256,7 +256,7 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction {
*/
@Override
public void run() {
mTestRunner = new RemoteADTTestRunner();
mTestRunner = new RemoteAdtTestRunner();
mTestRunner.runTests(mRunConfig.getProgramArguments(), mJUnitInfo);
}
}

View File

@@ -18,10 +18,11 @@ package com.android.ide.eclipse.adt.launch.junit;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.launch.AndroidLaunch;
import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration;
import com.android.ide.eclipse.adt.launch.AndroidLaunchController;
import com.android.ide.eclipse.adt.launch.IAndroidLaunchAction;
import com.android.ide.eclipse.adt.launch.LaunchConfigDelegate;
import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
@@ -31,6 +32,7 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
@@ -46,6 +48,7 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
/** Launch config attribute that stores instrumentation runner */
static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$
static final String INSTRUMENTATION_OK = null;
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
@Override
@@ -87,7 +90,8 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
* Helper method to return the set of instrumentations for the Android project
*
* @param project the {@link IProject} to get instrumentations for
* @return null if no error occurred parsing instrumentations
* @return null if error occurred parsing instrumentations, otherwise returns array of
* instrumentation class names
*/
static String[] getInstrumentationsForProject(IProject project) {
if (project != null) {
@@ -117,4 +121,56 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {
config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND,
TestKindRegistry.JUNIT3_TEST_KIND_ID);
}
/**
* Helper method to determine if specified instrumentation can be used as a test runner
*
* @param project the {@link IJavaProject} to validate
* @param instrumentation the instrumentation class name to validate
* @return <code>INSTRUMENTATION_OK</code> if valid, otherwise returns error message
*/
static String validateInstrumentationRunner(IJavaProject project, String instrumentation) {
AndroidManifestParser manifestParser;
try {
manifestParser = AndroidManifestParser.parse(
project, null /* errorListener */,
true /* gatherData */, false /* markErrors */);
// check if this instrumentation is the standard test runner
if (!instrumentation.equals(AndroidConstants.CLASS_INSTRUMENTATION_RUNNER)) {
// check if it extends the standard test runner
String result = BaseProjectHelper.testClassForManifest(project,
instrumentation, AndroidConstants.CLASS_INSTRUMENTATION_RUNNER, true);
if (result != BaseProjectHelper.TEST_CLASS_OK) {
return String.format("The instrumentation runner must be of type %s",
AndroidConstants.CLASS_INSTRUMENTATION_RUNNER);
}
}
if (!hasTestRunnerLibrary(manifestParser)) {
return String.format("%s does not not use the %s library",
project.getProject().getName(), AndroidConstants.LIBRARY_TEST_RUNNER);
}
} catch (CoreException e) {
String err = String.format("Error parsing AndroidManifest for %s",
project.getProject().getName());
AdtPlugin.log(e, err);
return err;
}
return INSTRUMENTATION_OK;
}
/**
* Helper method to determine if given manifest has a <code>AndroidConstants.LIBRARY_TEST_RUNNER
* </code> library reference
*
* @param manifestParser the {@link AndroidManifestParser} to search
* @return true if test runner library found, false otherwise
*/
static boolean hasTestRunnerLibrary(AndroidManifestParser manifestParser) {
for (String lib : manifestParser.getUsesLibraries()) {
if (lib.equals(AndroidConstants.LIBRARY_TEST_RUNNER)) {
return true;
}
}
return false;
}
}

View File

@@ -691,10 +691,18 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
private void validateInstrumentation(IJavaProject javaProject) {
if (mInstrumentations == null || mInstrumentations.length < 1) {
setErrorMessage("Specified project has no defined instrumentations");
return;
}
String instrumentation = getSelectedInstrumentation();
if (instrumentation == null) {
setErrorMessage("Instrumentation not specified");
return;
}
String result = AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner(
javaProject, instrumentation);
if (result != AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) {
setErrorMessage(result);
return;
}
}

View File

@@ -16,6 +16,9 @@
package com.android.ide.eclipse.adt.launch.junit;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.common.AndroidConstants;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
@@ -43,10 +46,27 @@ public class AndroidJUnitLaunchShortcut extends JUnitLaunchShortcut {
IProject project = element.getResource().getProject();
String[] instrumentations =
AndroidJUnitLaunchConfigDelegate.getInstrumentationsForProject(project);
if (instrumentations != null && instrumentations.length > 0) {
// just pick the first runner
boolean runnerFound = false;
if (instrumentations != null) {
// just pick the first valid runner
for (String instr : instrumentations) {
if (AndroidJUnitLaunchConfigDelegate.validateInstrumentationRunner(
element.getJavaProject(), instr) ==
AndroidJUnitLaunchConfigDelegate.INSTRUMENTATION_OK) {
config.setAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_INSTR_NAME,
instrumentations[0]);
instr);
runnerFound = true;
break;
}
}
}
if (!runnerFound) {
// TODO: put this in a string properties
String msg = String.format("ERROR: Application does not specify a %s instrumentation or does not declare uses-library %s",
AndroidConstants.CLASS_INSTRUMENTATION_RUNNER,
AndroidConstants.LIBRARY_TEST_RUNNER);
AdtPlugin.printErrorToConsole(project, msg);
}
AndroidJUnitLaunchConfigDelegate.setJUnitDefaults(config);

View File

@@ -34,7 +34,7 @@ import org.eclipse.jdt.internal.junit.runner.TestReferenceFailure;
* @see org.eclipse.jdt.internal.junit.runner.RemoteTestRunner for more details on the protocol
*/
@SuppressWarnings("restriction")
public class RemoteADTTestRunner extends RemoteTestRunner {
public class RemoteAdtTestRunner extends RemoteTestRunner {
private AndroidJUnitLaunchInfo mLaunchInfo;
private TestExecution mExecution;
@@ -97,6 +97,8 @@ public class RemoteADTTestRunner extends RemoteTestRunner {
// error occurred during test collection.
reportError(collector.getErrorMessage());
// abort here
notifyTestRunEnded(0);
return;
}
notifyTestRunStarted(collector.getTestCaseCount());
collector.sendTrees(this);

View File

@@ -20,8 +20,10 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
@@ -34,12 +36,14 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.JavaRuntime;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class to manipulate Project parameters/properties.
@@ -679,4 +683,71 @@ public final class ProjectHelper {
return project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
}
/**
* Find the list of projects on which this JavaProject is dependent on at the compilation level.
*
* @param javaProject Java project that we are looking for the dependencies.
* @return A list of Java projects for which javaProject depend on.
* @throws JavaModelException
*/
public static List<IJavaProject> getAndroidProjectDependencies(IJavaProject javaProject)
throws JavaModelException {
String[] requiredProjectNames = javaProject.getRequiredProjectNames();
// Go from java project name to JavaProject name
IJavaModel javaModel = javaProject.getJavaModel();
// loop through all dependent projects and keep only those that are Android projects
List<IJavaProject> projectList = new ArrayList<IJavaProject>(requiredProjectNames.length);
for (String javaProjectName : requiredProjectNames) {
IJavaProject androidJavaProject = javaModel.getJavaProject(javaProjectName);
//Verify that the project has also the Android Nature
try {
if (!androidJavaProject.getProject().hasNature(AndroidConstants.NATURE)) {
continue;
}
} catch (CoreException e) {
continue;
}
projectList.add(androidJavaProject);
}
return projectList;
}
/**
* Returns the android package file as an IFile object for the specified
* project.
* @param project The project
* @return The android package as an IFile object or null if not found.
*/
public static IFile getApplicationPackage(IProject project) {
// get the output folder
IFolder outputLocation = BaseProjectHelper.getOutputFolder(project);
if (outputLocation == null) {
AdtPlugin.printErrorToConsole(project,
"Failed to get the output location of the project. Check build path properties"
);
return null;
}
// get the package path
String packageName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
IResource r = outputLocation.findMember(packageName);
// check the package is present
if (r instanceof IFile && r.exists()) {
return (IFile)r;
}
String msg = String.format("Could not find %1$s!", packageName);
AdtPlugin.printErrorToConsole(project, msg);
return null;
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.refactorings.extractstring;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PlatformUI;
/*
* Quick Reference Link:
* http://www.eclipse.org/articles/article.php?file=Article-Unleashing-the-Power-of-Refactoring/index.html
* and
* http://www.ibm.com/developerworks/opensource/library/os-ecjdt/
*/
/**
* Action executed when the "Extract String" menu item is invoked.
* <p/>
* The intent of the action is to start a refactoring that extracts a source string and
* replaces it by an Android string resource ID.
* <p/>
* Workflow:
* <ul>
* <li> The action is currently located in the Refactoring menu in the main menu.
* <li> TODO: extend the popup refactoring menu in a Java or Android XML file.
* <li> The action is only enabled if the selection is 1 character or more. That is at least part
* of the string must be selected, it's not enough to just move the insertion point. This is
* a limitation due to {@link #selectionChanged(IAction, ISelection)} not being called when
* the insertion point is merely moved. TODO: address this limitation.
* <ul> The action gets the current {@link ISelection}. It also knows the current
* {@link IWorkbenchWindow}. However for the refactoring we are also interested in having the
* actual resource file. By looking at the Active Window > Active Page > Active Editor we
* can get the {@link IEditorInput} and find the {@link ICompilationUnit} (aka Java file)
* that is being edited.
* <ul> TODO: change this to find the {@link IFile} being manipulated. The {@link ICompilationUnit}
* can be inferred using {@link JavaCore#createCompilationUnitFrom(IFile)}. This will allow
* us to be able to work with a selection from an Android XML file later.
* <li> The action creates a new {@link ExtractStringRefactoring} and make it run on in a new
* {@link ExtractStringWizard}.
* <ul>
*/
public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
/** Keep track of the current workbench window. */
private IWorkbenchWindow mWindow;
private ITextSelection mSelection;
private ICompilationUnit mUnit;
/**
* Keep track of the current workbench window.
*/
public void init(IWorkbenchWindow window) {
mWindow = window;
}
public void dispose() {
// Nothing to do
}
/**
* Examine the selection to determine if the action should be enabled or not.
* <p/>
* Keep a link to the relevant selection structure (i.e. a part of the Java AST).
*/
public void selectionChanged(IAction action, ISelection selection) {
// Note, two kinds of selections are returned here:
// ITextSelection on a Java source window
// IStructuredSelection in the outline or navigator
// This simply deals with the refactoring based on a non-empty selection.
// At that point, just enable the action and later decide if it's valid when it actually
// runs since we don't have access to the AST yet.
mSelection = null;
mUnit = null;
if (selection instanceof ITextSelection) {
mSelection = (ITextSelection) selection;
if (mSelection.getLength() > 0) {
mUnit = getCompilationUnit();
}
// Keep for debugging purposes
//System.out.println(String.format("-- Selection: %d + %d = %s",
// mSelection.getOffset(),
// mSelection.getLength(),
// mSelection.getText()));
}
action.setEnabled(mSelection != null && mUnit != null);
}
/**
* Create a new instance of our refactoring and a wizard to configure it.
*/
public void run(IAction action) {
if (mSelection != null && mUnit != null) {
ExtractStringRefactoring ref = new ExtractStringRefactoring(mUnit, mSelection);
RefactoringWizard wizard = new ExtractStringWizard(ref, "Extract Android String");
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
try {
op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
} catch (InterruptedException e) {
// Interrupted. Pass.
}
}
}
/**
* Returns the active {@link ICompilationUnit} or null.
*/
private ICompilationUnit getCompilationUnit() {
IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (wwin != null) {
IWorkbenchPage page = wwin.getActivePage();
if (page != null) {
IEditorPart editor = page.getActiveEditor();
if (editor != null) {
IEditorInput input = editor.getEditorInput();
if (input != null) {
ITypeRoot typeRoot = JavaUI.getEditorInputTypeRoot(input);
// The type root can be either a .class or a .java (aka compilation unit).
// We want the compilation unit kind.
if (typeRoot instanceof ICompilationUnit) {
return (ICompilationUnit) typeRoot;
}
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.refactorings.extractstring;
import org.eclipse.ltk.core.refactoring.RefactoringContribution;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import java.util.Map;
/**
* @see ExtractStringDescriptor
*/
public class ExtractStringContribution extends RefactoringContribution {
/* (non-Javadoc)
* @see org.eclipse.ltk.core.refactoring.RefactoringContribution#createDescriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.Map, int)
*/
@SuppressWarnings("unchecked")
@Override
public RefactoringDescriptor createDescriptor(
String id,
String project,
String description,
String comment,
Map arguments,
int flags)
throws IllegalArgumentException {
return new ExtractStringDescriptor(project, description, comment, arguments);
}
@SuppressWarnings("unchecked")
@Override
public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
if (descriptor instanceof ExtractStringDescriptor) {
return ((ExtractStringDescriptor) descriptor).getArguments();
}
return super.retrieveArgumentMap(descriptor);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.refactorings.extractstring;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import java.util.Map;
/**
* A descriptor that allows an {@link ExtractStringRefactoring} to be created from
* a previous instance of itself.
*/
public class ExtractStringDescriptor extends RefactoringDescriptor {
public static final String ID =
"com.android.ide.eclipse.adt.refactoring.extract.string"; //$NON-NLS-1$
private final Map<String, String> mArguments;
public ExtractStringDescriptor(String project, String description, String comment,
Map<String, String> arguments) {
super(ID, project, description, comment,
RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE //flags
);
mArguments = arguments;
}
public Map<String, String> getArguments() {
return mArguments;
}
/**
* Creates a new refactoring instance for this refactoring descriptor based on
* an argument map. The argument map is created by the refactoring itself in
* {@link ExtractStringRefactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)}
* <p/>
* This is apparently used to replay a refactoring.
*
* {@inheritDoc}
*
* @throws CoreException
*/
@Override
public Refactoring createRefactoring(RefactoringStatus status) throws CoreException {
try {
ExtractStringRefactoring ref = new ExtractStringRefactoring(mArguments);
return ref;
} catch (NullPointerException e) {
status.addFatalError("Failed to recreate ExtractStringRefactoring from descriptor");
return null;
}
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.refactorings.extractstring;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
/**
* @see ExtractStringRefactoring
*/
class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage {
public ExtractStringInputPage() {
super("ExtractStringInputPage"); //$NON-NLS-1$
}
private Label mStringLabel;
private Text mNewIdTextField;
private Label mFileLabel;
/**
* Create the UI for the refactoring wizard.
* <p/>
* Note that at that point the initial conditions have been checked in
* {@link ExtractStringRefactoring}.
*/
public void createControl(Composite parent) {
final ExtractStringRefactoring ref = getOurRefactoring();
Composite content = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
content.setLayout(layout);
// line 1: String found in selection
Label label = new Label(content, SWT.NONE);
label.setText("String:");
String selectedString = ref.getTokenString();
mStringLabel = new Label(content, SWT.NONE);
mStringLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mStringLabel.setText(selectedString != null ? selectedString : "");
// TODO provide an option to replace all occurences of this string instead of
// just the one.
// line 2 : Textfield for new ID
label = new Label(content, SWT.NONE);
label.setText("Replace by R.string.");
mNewIdTextField = new Text(content, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
mNewIdTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mNewIdTextField.setText(guessId(selectedString));
ref.setReplacementStringId(mNewIdTextField.getText().trim());
mNewIdTextField.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (validatePage(ref)) {
ref.setReplacementStringId(mNewIdTextField.getText().trim());
}
}
});
// line 3: selection of the output file
// TODO add a file field/chooser combo to let the user select the file to edit.
label = new Label(content, SWT.NONE);
label.setText("Resource file:");
mFileLabel = new Label(content, SWT.NONE);
mFileLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mFileLabel.setText("/res/values/strings.xml");
ref.setTargetFile(mFileLabel.getText());
// line 4: selection of the res config
// TODO add the Configuration Selector to decide with strings.xml to change
label = new Label(content, SWT.NONE);
label.setText("Configuration:");
label = new Label(content, SWT.NONE);
label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
label.setText("default");
validatePage(ref);
setControl(content);
}
private String guessId(String text) {
// make lower case
text = text.toLowerCase();
// everything not alphanumeric becomes an underscore
text = text.replaceAll("[^a-zA-Z0-9]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
// the id must be a proper Java identifier, so it can't start with a number
if (text.length() > 0 && !Character.isJavaIdentifierStart(text.charAt(0))) {
text = "_" + text; //$NON-NLS-1$
}
return text;
}
private ExtractStringRefactoring getOurRefactoring() {
return (ExtractStringRefactoring) getRefactoring();
}
private boolean validatePage(ExtractStringRefactoring ref) {
String text = mNewIdTextField.getText().trim();
boolean success = true;
// Analyze fatal errors.
if (text == null || text.length() < 1) {
setErrorMessage("Please provide a resource ID to replace with.");
success = false;
} else {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
boolean ok = i == 0 ?
Character.isJavaIdentifierStart(c) :
Character.isJavaIdentifierPart(c);
if (!ok) {
setErrorMessage(String.format(
"The resource ID must be a valid Java identifier. The character %1$c at position %2$d is not acceptable.",
c, i+1));
success = false;
break;
}
}
}
// Analyze info & warnings.
if (success) {
if (ref.isResIdDuplicate(mFileLabel.getText(), text)) {
setErrorMessage(null);
setMessage(
String.format("Warning: There's already a string item called '%1$s' in %2$s.",
text, mFileLabel.getText()));
} else {
setMessage(null);
setErrorMessage(null);
}
}
setPageComplete(success);
return success;
}
}

View File

@@ -0,0 +1,890 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.refactorings.extractstring;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.AndroidXPathFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditGroup;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
/**
* This refactoring extracts a string from a file and replaces it by an Android resource ID
* such as R.string.foo.
* <p/>
* There are a number of scenarios, which are not all supported yet. The workflow works as
* such:
* <ul>
* <li> User selects a string in a Java (TODO: or XML file) and invokes
* the {@link ExtractStringAction}.
* <li> The action finds the {@link ICompilationUnit} being edited as well as the current
* {@link ITextSelection}. The action creates a new instance of this refactoring as
* well as an {@link ExtractStringWizard} and runs the operation.
* <li> TODO: to support refactoring from an XML file, the action should give the {@link IFile}
* and then here we would have to determine whether it's a suitable Android XML file or a
* suitable Java file.
* TODO: enumerate the exact valid contexts in Android XML files, e.g. attributes in layout
* files or text elements (e.g. <string>foo</string>) for values, etc.
* <li> Step 1 of the refactoring is to check the preliminary conditions. Right now we check
* that the java source is not read-only and is in sync. We also try to find a string under
* the selection. If this fails, the refactoring is aborted.
* <li> TODO: Find the string in an XML file based on selection.
* <li> On success, the wizard is shown, which let the user input the new ID to use.
* <li> The wizard sets the user input values into this refactoring instance, e.g. the new string
* ID, the XML file to update, etc. The wizard does use the utility method
* {@link #isResIdDuplicate(String, String)} to check whether the new ID is already defined
* in the target XML file.
* <li> Once Preview or Finish is selected in the wizard, the
* {@link #checkFinalConditions(IProgressMonitor)} is called to double-check the user input
* and compute the actual changes.
* <li> When all changes are computed, {@link #createChange(IProgressMonitor)} is invoked.
* </ul>
*
* The list of changes are:
* <ul>
* <li> If the target XML does not exist, create it with the new string ID.
* <li> If the target XML exists, find the <resources> node and add the new string ID right after.
* If the node is <resources/>, it needs to be opened.
* <li> Create an AST rewriter to edit the source Java file and replace all occurences by the
* new computed R.string.foo. Also need to rewrite imports to import R as needed.
* If there's already a conflicting R included, we need to insert the FQCN instead.
* <li> TODO: If the source is an XML file, determine if we need to change an attribute or a
* a text element.
* <li> TODO: Have a pref in the wizard: [x] Change other XML Files
* <li> TODO: Have a pref in the wizard: [x] Change other Java Files
* </ul>
*/
class ExtractStringRefactoring extends Refactoring {
/** The compilation unit, a.k.a. the Java file model. */
private final ICompilationUnit mUnit;
private final int mSelectionStart;
private final int mSelectionEnd;
/** The actual string selected, after UTF characters have been escaped, good for display. */
private String mTokenString;
/** Start position of the string token in the source buffer. */
private int mTokenStart;
/** End position of the string token in the source buffer. */
private int mTokenEnd;
private String mXmlStringId;
private String mTargetXmlFileWsPath;
private HashMap<String,HashSet<String>> mResIdCache;
private XPath mXPath;
private ArrayList<Change> mChanges;
public ExtractStringRefactoring(Map<String, String> arguments)
throws NullPointerException {
mUnit = (ICompilationUnit) JavaCore.create(arguments.get("CU")); //$NON-NLS-1$
mSelectionStart = Integer.parseInt(arguments.get("sel-start")); //$NON-NLS-1$
mSelectionEnd = Integer.parseInt(arguments.get("sel-end")); //$NON-NLS-1$
mTokenStart = Integer.parseInt(arguments.get("tok-start")); //$NON-NLS-1$
mTokenEnd = Integer.parseInt(arguments.get("tok-end")); //$NON-NLS-1$
mTokenString = arguments.get("tok-esc"); //$NON-NLS-1$
}
private Map<String, String> createArgumentMap() {
HashMap<String, String> args = new HashMap<String, String>();
args.put("CU", mUnit.getHandleIdentifier()); //$NON-NLS-1$
args.put("sel-start", Integer.toString(mSelectionStart)); //$NON-NLS-1$
args.put("sel-end", Integer.toString(mSelectionEnd)); //$NON-NLS-1$
args.put("tok-start", Integer.toString(mTokenStart)); //$NON-NLS-1$
args.put("tok-end", Integer.toString(mTokenEnd)); //$NON-NLS-1$
args.put("tok-esc", mTokenString); //$NON-NLS-1$
return args;
}
public ExtractStringRefactoring(ICompilationUnit unit, ITextSelection selection) {
mUnit = unit;
mSelectionStart = selection.getOffset();
mSelectionEnd = mSelectionStart + selection.getLength();
}
/**
* @see org.eclipse.ltk.core.refactoring.Refactoring#getName()
*/
@Override
public String getName() {
return "Extract Android String";
}
/**
* Gets the actual string selected, after UTF characters have been escaped,
* good for display.
*/
public String getTokenString() {
return mTokenString;
}
/**
* Step 1 of 3 of the refactoring:
* Checks that the current selection meets the initial condition before the ExtractString
* wizard is shown. The check is supposed to be lightweight and quick. Note that at that
* point the wizard has not been created yet.
* <p/>
* Here we scan the source buffer to find the token matching the selection.
* The check is successful is a Java string literal is selected, the source is in sync
* and is not read-only.
* <p/>
* This is also used to extract the string to be modified, so that we can display it in
* the refactoring wizard.
*
* @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
*
* @throws CoreException
*/
@Override
public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
throws CoreException, OperationCanceledException {
mTokenString = null;
mTokenStart = -1;
mTokenEnd = -1;
RefactoringStatus status = new RefactoringStatus();
try {
monitor.beginTask("Checking preconditions...", 3);
if (!extraChecks(monitor, status)) {
return status;
}
try {
IBuffer buffer = mUnit.getBuffer();
IScanner scanner = ToolFactory.createScanner(
false, //tokenizeComments
false, //tokenizeWhiteSpace
false, //assertMode
false //recordLineSeparator
);
scanner.setSource(buffer.getCharacters());
monitor.worked(1);
for(int token = scanner.getNextToken();
token != ITerminalSymbols.TokenNameEOF;
token = scanner.getNextToken()) {
if (scanner.getCurrentTokenStartPosition() <= mSelectionStart &&
scanner.getCurrentTokenEndPosition() >= mSelectionEnd) {
// found the token, but only keep of the right type
if (token == ITerminalSymbols.TokenNameStringLiteral) {
mTokenString = new String(scanner.getCurrentTokenSource());
mTokenStart = scanner.getCurrentTokenStartPosition();
mTokenEnd = scanner.getCurrentTokenEndPosition();
}
break;
} else if (scanner.getCurrentTokenStartPosition() > mSelectionEnd) {
// scanner is past the selection, abort.
break;
}
}
} catch (JavaModelException e1) {
// Error in mUnit.getBuffer. Ignore.
} catch (InvalidInputException e2) {
// Error in scanner.getNextToken. Ignore.
} finally {
monitor.worked(1);
}
if (mTokenString != null) {
// As a literal string, the token should have surrounding quotes. Remove them.
int len = mTokenString.length();
if (len > 0 &&
mTokenString.charAt(0) == '"' &&
mTokenString.charAt(len - 1) == '"') {
mTokenString = mTokenString.substring(1, len - 1);
}
// We need a non-empty string literal
if (mTokenString.length() == 0) {
mTokenString = null;
}
}
if (mTokenString == null) {
status.addFatalError("Please select a Java string literal.");
}
monitor.worked(1);
} finally {
monitor.done();
}
return status;
}
/**
* Tests from org.eclipse.jdt.internal.corext.refactoringChecks#validateEdit()
* Might not be useful.
*
* @return False if caller should abort, true if caller should continue.
*/
private boolean extraChecks(IProgressMonitor monitor, RefactoringStatus status) {
//
IResource res = mUnit.getPrimary().getResource();
if (res == null || res.getType() != IResource.FILE) {
status.addFatalError("Cannot access resource; only regular files can be used.");
return false;
}
monitor.worked(1);
// check whether the source file is in sync
if (!res.isSynchronized(IResource.DEPTH_ZERO)) {
status.addFatalError("The file is not synchronized. Please save it first.");
return false;
}
monitor.worked(1);
// make sure we can write to it.
ResourceAttributes resAttr = res.getResourceAttributes();
if (mUnit.isReadOnly() || resAttr == null || resAttr.isReadOnly()) {
status.addFatalError("The file is read-only, please make it writeable first.");
return false;
}
monitor.worked(1);
return true;
}
/**
* Step 2 of 3 of the refactoring:
* Check the conditions once the user filled values in the refactoring wizard,
* then prepare the changes to be applied.
* <p/>
* In this case, most of the sanity checks are done by the wizard so essentially this
* should only be called if the wizard positively validated the user input.
*
* Here we do check that the target resource XML file either does not exists or
* is not read-only.
*
* @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(IProgressMonitor)
*
* @throws CoreException
*/
@Override
public RefactoringStatus checkFinalConditions(IProgressMonitor monitor)
throws CoreException, OperationCanceledException {
RefactoringStatus status = new RefactoringStatus();
try {
monitor.beginTask("Checking post-conditions...", 3);
if (mXmlStringId == null || mXmlStringId.length() <= 0) {
// this is not supposed to happen
status.addFatalError("Missing replacement string ID");
} else if (mTargetXmlFileWsPath == null || mTargetXmlFileWsPath.length() <= 0) {
// this is not supposed to happen
status.addFatalError("Missing target xml file path");
}
monitor.worked(1);
// Either that resource must not exist or it must be a writeable file.
IResource targetXml = getTargetXmlResource(mTargetXmlFileWsPath);
if (targetXml != null) {
if (targetXml.getType() != IResource.FILE) {
status.addFatalError(
String.format("XML file '%1$s' is not a file.", mTargetXmlFileWsPath));
} else {
ResourceAttributes attr = targetXml.getResourceAttributes();
if (attr != null && attr.isReadOnly()) {
status.addFatalError(
String.format("XML file '%1$s' is read-only.",
mTargetXmlFileWsPath));
}
}
}
monitor.worked(1);
if (status.hasError()) {
return status;
}
mChanges = new ArrayList<Change>();
// Prepare the change for the XML file.
if (!isResIdDuplicate(mTargetXmlFileWsPath, mXmlStringId)) {
// We actually change it only if the ID doesn't exist yet
TextFileChange xmlChange = new TextFileChange(getName(), (IFile) targetXml);
xmlChange.setTextType("xml"); //$NON-NLS-1$
TextEdit edit = createXmlEdit((IFile) targetXml, mXmlStringId, mTokenString);
if (edit == null) {
status.addFatalError(String.format("Failed to modify file %1$s",
mTargetXmlFileWsPath));
}
xmlChange.setEdit(edit);
mChanges.add(xmlChange);
}
monitor.worked(1);
if (status.hasError()) {
return status;
}
// Prepare the change to the Java compilation unit
List<Change> changes = computeJavaChanges(mUnit, mXmlStringId, mTokenString, status,
SubMonitor.convert(monitor, 1));
if (changes != null) {
mChanges.addAll(changes);
}
monitor.worked(1);
} finally {
monitor.done();
}
return status;
}
/**
* Internal helper that actually prepares the {@link TextEdit} that adds the given
* ID to the given XML File.
* <p/>
* This does not actually modify the file.
*
* @param xmlFile The file resource to modify.
* @param replacementStringId The new ID to insert.
* @param oldString The old string, which will be the value in the XML string.
* @return A new {@link TextEdit} that describes how to change the file.
*/
private TextEdit createXmlEdit(IFile xmlFile, String replacementStringId, String oldString) {
if (!xmlFile.exists()) {
// The XML file does not exist. Simply create it.
StringBuilder content = new StringBuilder();
content.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$
content.append("<resources>\n"); //$NON-NLS-1$
content.append(" <string name=\""). //$NON-NLS-1$
append(replacementStringId).
append("\">"). //$NON-NLS-1$
append(oldString).
append("</string>\n"); //$NON-NLS-1$
content.append("<resources>\n"); //$NON-NLS-1$
return new InsertEdit(0, content.toString());
}
// The file exist. Attempt to parse it as a valid XML document.
try {
int[] indices = new int[2];
if (findXmlOpeningTagPos(xmlFile.getContents(), "resources", indices)) { //$NON-NLS-1$
// Indices[1] indicates whether we found > or />. It can only be 1 or 2.
// Indices[0] is the position of the first character of either > or />.
//
// Note: we don't even try to adapt our formatting to the existing structure (we
// could by capturing whatever whitespace is after the closing bracket and
// applying it here before our tag, unless we were dealing with an empty
// resource tag.)
int offset = indices[0];
int len = indices[1];
StringBuilder content = new StringBuilder();
content.append(">\n"); //$NON-NLS-1$
content.append(" <string name=\""). //$NON-NLS-1$
append(replacementStringId).
append("\">"). //$NON-NLS-1$
append(oldString).
append("</string>"); //$NON-NLS-1$
if (len == 2) {
content.append("\n</resources>"); //$NON-NLS-1$
}
return new ReplaceEdit(offset, len, content.toString());
}
} catch (CoreException e) {
// Failed to read file. Ignore. Will return null below.
}
return null;
}
/**
* Parse an XML input stream, looking for an opening tag.
* <p/>
* If found, returns the character offet in the buffer of the closing bracket of that
* tag, e.g. the position of > in "<resources>". The first character is at offset 0.
* <p/>
* The implementation here relies on a simple character-based parser. No DOM nor SAX
* parsing is used, due to the simplified nature of the task: we just want the first
* opening tag, which in our case should be the document root. We deal however with
* with the tag being commented out, so comments are skipped. We assume the XML doc
* is sane, e.g. we don't expect the tag to appear in the middle of a string. But
* again since in fact we want the root element, that's unlikely to happen.
* <p/>
* We need to deal with the case where the element is written as <resources/>, in
* which case the caller will want to replace /> by ">...</...>". To do that we return
* two values: the first offset of the closing tag (e.g. / or >) and the length, which
* can only be 1 or 2. If it's 2, the caller have to deal with /> instead of just >.
*
* @param contents An existing buffer to parse.
* @param tag The tag to look for.
* @param indices The return values: [0] is the offset of the closing bracket and [1] is
* the length which can be only 1 for > and 2 for />
* @return True if we found the tag, in which case <code>indices</code> can be used.
*/
private boolean findXmlOpeningTagPos(InputStream contents, String tag, int[] indices) {
BufferedReader br = new BufferedReader(new InputStreamReader(contents));
StringBuilder sb = new StringBuilder(); // scratch area
tag = "<" + tag;
int tagLen = tag.length();
int maxLen = tagLen < 3 ? 3 : tagLen;
try {
int offset = 0;
int i = 0;
char searching = '<'; // we want opening tags
boolean capture = false;
boolean inComment = false;
boolean inTag = false;
while ((i = br.read()) != -1) {
char c = (char) i;
if (c == searching) {
capture = true;
}
if (capture) {
sb.append(c);
int len = sb.length();
if (inComment && c == '>') {
// is the comment being closed?
if (len >= 3 && sb.substring(len-3).equals("-->")) { //$NON-NLS-1$
// yes, comment is closing, stop capturing
capture = false;
inComment = false;
sb.setLength(0);
}
} else if (inTag && c == '>') {
// we're capturing in our tag, waiting for the closing >, we just got it
// so we're totally done here. Simply detect whether it's /> or >.
indices[0] = offset;
indices[1] = 1;
if (sb.charAt(len - 2) == '/') {
indices[0]--;
indices[1]++;
}
return true;
} else if (!inComment && !inTag) {
// not a comment and not our tag yet, so we're capturing because a
// tag is being opened but we don't know which one yet.
// look for either the opening or a comment or
// the opening of our tag.
if (len == 3 && sb.equals("<--")) { //$NON-NLS-1$
inComment = true;
} else if (len == tagLen && sb.toString().equals(tag)) {
inTag = true;
}
// if we're not interested in this tag yet, deal with when to stop
// capturing: the opening tag ends with either any kind of whitespace
// or with a > or maybe there's a PI that starts with <?
if (!inComment && !inTag) {
if (c == '>' || c == '?' || c == ' ' || c == '\n' || c == '\r') {
// stop capturing
capture = false;
sb.setLength(0);
}
}
}
if (capture && len > maxLen) {
// in any case we don't need to capture more than the size of our tag
// or the comment opening tag
sb.deleteCharAt(0);
}
}
offset++;
}
} catch (IOException e) {
// Ignore.
} finally {
try {
br.close();
} catch (IOException e) {
// oh come on...
}
}
return false;
}
private List<Change> computeJavaChanges(ICompilationUnit unit,
String xmlStringId,
String tokenString,
RefactoringStatus status,
SubMonitor subMonitor) {
// Get the Android package name from the Android Manifest. We need it to create
// the FQCN of the R class.
String packageName = null;
String error = null;
IProject proj = unit.getJavaProject().getProject();
IResource manifestFile = proj.findMember(AndroidConstants.FN_ANDROID_MANIFEST);
if (manifestFile == null || manifestFile.getType() != IResource.FILE) {
error = "File not found";
} else {
try {
AndroidManifestParser manifest = AndroidManifestParser.parseForData(
(IFile) manifestFile);
if (manifest == null) {
error = "Invalid content";
} else {
packageName = manifest.getPackage();
if (packageName == null) {
error = "Missing package definition";
}
}
} catch (CoreException e) {
error = e.getLocalizedMessage();
}
}
if (error != null) {
status.addFatalError(
String.format("Failed to parse file %1$s: %2$s.",
manifestFile.getFullPath(), error));
return null;
}
// TODO in a future version we might want to collect various Java files that
// need to be updated in the same project and process them all together.
// To do that we need to use an ASTRequestor and parser.createASTs, kind of
// like this:
//
// ASTRequestor requestor = new ASTRequestor() {
// @Override
// public void acceptAST(ICompilationUnit sourceUnit, CompilationUnit astNode) {
// super.acceptAST(sourceUnit, astNode);
// // TODO process astNode
// }
// };
// ...
// parser.createASTs(compilationUnits, bindingKeys, requestor, monitor)
//
// and then add multiple TextFileChange to the changes arraylist.
// Right now the changes array will contain one TextFileChange at most.
ArrayList<Change> changes = new ArrayList<Change>();
// This is the unit that will be modified.
TextFileChange change = new TextFileChange(getName(), (IFile) unit.getResource());
change.setTextType("java"); //$NON-NLS-1$
// Create an AST for this compilation unit
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setProject(unit.getJavaProject());
parser.setSource(unit);
parser.setResolveBindings(true);
ASTNode node = parser.createAST(subMonitor.newChild(1));
// The ASTNode must be a CompilationUnit, by design
if (!(node instanceof CompilationUnit)) {
status.addFatalError(String.format("Internal error: ASTNode class %s", //$NON-NLS-1$
node.getClass()));
return null;
}
// ImportRewrite will allow us to add the new type to the imports and will resolve
// what the Java source must reference, e.g. the FQCN or just the simple name.
ImportRewrite ir = ImportRewrite.create((CompilationUnit) node, true);
String Rqualifier = packageName + ".R"; //$NON-NLS-1$
Rqualifier = ir.addImport(Rqualifier);
// Rewrite the AST itself via an ASTVisitor
AST ast = node.getAST();
ASTRewrite ar = ASTRewrite.create(ast);
ReplaceStringsVisitor visitor = new ReplaceStringsVisitor(ast, ar,
tokenString, Rqualifier, xmlStringId);
node.accept(visitor);
// Finally prepare the change set
try {
MultiTextEdit edit = new MultiTextEdit();
// Create the edit to change the imports, only if anything changed
TextEdit subEdit = ir.rewriteImports(subMonitor.newChild(1));
if (subEdit.hasChildren()) {
edit.addChild(subEdit);
}
// Create the edit to change the Java source, only if anything changed
subEdit = ar.rewriteAST();
if (subEdit.hasChildren()) {
edit.addChild(subEdit);
}
// Only create a change set if any edit was collected
if (edit.hasChildren()) {
change.setEdit(edit);
changes.add(change);
}
// TODO to modify another Java source, loop back to the creation of the
// TextFileChange and accumulate in changes. Right now only one source is
// modified.
if (changes.size() > 0) {
return changes;
}
} catch (CoreException e) {
// ImportRewrite.rewriteImports failed.
status.addFatalError(e.getMessage());
}
return null;
}
public class ReplaceStringsVisitor extends ASTVisitor {
private final AST mAst;
private final ASTRewrite mRewriter;
private final String mOldString;
private final String mRQualifier;
private final String mXmlId;
public ReplaceStringsVisitor(AST ast,
ASTRewrite astRewrite,
String oldString,
String rQualifier,
String xmlId) {
mAst = ast;
mRewriter = astRewrite;
mOldString = oldString;
mRQualifier = rQualifier;
mXmlId = xmlId;
}
@Override
public boolean visit(StringLiteral node) {
if (node.getLiteralValue().equals(mOldString)) {
Name qualifierName = mAst.newName(mRQualifier + ".string"); //$NON-NLS-1$
SimpleName idName = mAst.newSimpleName(mXmlId);
QualifiedName newNode = mAst.newQualifiedName(qualifierName, idName);
TextEditGroup editGroup = new TextEditGroup(getName());
mRewriter.replace(node, newNode, editGroup);
}
return super.visit(node);
}
}
/**
* Step 3 of 3 of the refactoring: returns the {@link Change} that will be able to do the
* work and creates a descriptor that can be used to replay that refactoring later.
*
* @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
*
* @throws CoreException
*/
@Override
public Change createChange(IProgressMonitor monitor)
throws CoreException, OperationCanceledException {
try {
monitor.beginTask("Applying changes...", 1);
CompositeChange change = new CompositeChange(
getName(),
mChanges.toArray(new Change[mChanges.size()])) {
@Override
public ChangeDescriptor getDescriptor() {
String comment = String.format(
"Extracts string '%1$s' into R.string.%2$s",
mTokenString,
mXmlStringId);
ExtractStringDescriptor desc = new ExtractStringDescriptor(
mUnit.getJavaProject().getElementName(), //project
comment, //description
comment, //comment
createArgumentMap());
return new RefactoringChangeDescriptor(desc);
}
};
monitor.worked(1);
return change;
} finally {
monitor.done();
}
}
/**
* Utility method used by the wizard to check whether the given string ID is already
* defined in the XML file which path is given.
*
* @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
* The given file may or may not exist.
* @param stringId The string ID to find.
* @return True if such a string ID is already defined.
*/
public boolean isResIdDuplicate(String xmlFileWsPath, String stringId) {
// This is going to be called many times on the same file.
// Build a cache of the existing IDs for a given file.
if (mResIdCache == null) {
mResIdCache = new HashMap<String, HashSet<String>>();
}
HashSet<String> cache = mResIdCache.get(xmlFileWsPath);
if (cache == null) {
cache = getResIdsForFile(xmlFileWsPath);
mResIdCache.put(xmlFileWsPath, cache);
}
return cache.contains(stringId);
}
/**
* Extract all the defined string IDs from a given file using XPath.
*
* @param xmlFileWsPath The project path of the file to parse. It may not exist.
* @return The set of all string IDs defined in the file. The returned set is always non
* null. It is empty if the file does not exist.
*/
private HashSet<String> getResIdsForFile(String xmlFileWsPath) {
HashSet<String> ids = new HashSet<String>();
if (mXPath == null) {
mXPath = AndroidXPathFactory.newXPath();
}
// Access the project that contains the resource that contains the compilation unit
IResource resource = getTargetXmlResource(xmlFileWsPath);
if (resource != null && resource.exists() && resource.getType() == IResource.FILE) {
InputSource source;
try {
source = new InputSource(((IFile) resource).getContents());
// We want all the IDs in an XML structure like this:
// <resources>
// <string name="ID">something</string>
// </resources>
String xpathExpr = "/resources/string/@name"; //$NON-NLS-1$
Object result = mXPath.evaluate(xpathExpr, source, XPathConstants.NODESET);
if (result instanceof NodeList) {
NodeList list = (NodeList) result;
for (int n = list.getLength() - 1; n >= 0; n--) {
String id = list.item(n).getNodeValue();
ids.add(id);
}
}
} catch (CoreException e1) {
// IFile.getContents failed. Ignore.
} catch (XPathExpressionException e) {
// mXPath.evaluate failed. Ignore.
}
}
return ids;
}
/**
* Given a file project path, returns its resource in the same project than the
* compilation unit. The resource may not exist.
*/
private IResource getTargetXmlResource(String xmlFileWsPath) {
IProject proj = mUnit.getPrimary().getResource().getProject();
Path path = new Path(xmlFileWsPath);
IResource resource = proj.findMember(path);
return resource;
}
/**
* Sets the replacement string ID. Used by the wizard to set the user input.
*/
public void setReplacementStringId(String replacementStringId) {
mXmlStringId = replacementStringId;
}
/**
* Sets the target file. This is a project path, e.g. "/res/values/strings.xml".
* Used by the wizard to set the user input.
*/
public void setTargetFile(String targetXmlFileWsPath) {
mTargetXmlFileWsPath = targetXmlFileWsPath;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.refactorings.extractstring;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
/**
* A wizard for ExtractString based on a simple dialog with one page.
*
* @see ExtractStringInputPage
* @see ExtractStringRefactoring
*/
class ExtractStringWizard extends RefactoringWizard {
/**
* Create a wizard for ExtractString based on a simple dialog with one page.
*/
public ExtractStringWizard(ExtractStringRefactoring ref, String title) {
super(ref, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
setDefaultPageTitle(title);
}
@Override
protected void addUserInputPages() {
addPage(new ExtractStringInputPage());
}
}

View File

@@ -180,6 +180,8 @@ public class AndroidConstants {
public final static String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$
public final static String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$
public final static String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$
public final static String CLASS_INSTRUMENTATION_RUNNER =
"android.test.InstrumentationTestRunner"; //$NON-NLS-1$
public final static String CLASS_BUNDLE = "android.os.Bundle"; //$NON-NLS-1$
public final static String CLASS_R = "android.R"; //$NON-NLS-1$
public final static String CLASS_MANIFEST_PERMISSION = "android.Manifest$permission"; //$NON-NLS-1$
@@ -215,4 +217,5 @@ public class AndroidConstants {
/** The base URL where to find the Android class & manifest documentation */
public static final String CODESITE_BASE_URL = "http://code.google.com/android"; //$NON-NLS-1$
public static final String LIBRARY_TEST_RUNNER = "android.test.runner"; // $NON-NLS-1$
}

View File

@@ -16,6 +16,7 @@
package com.android.ide.eclipse.common.project;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener;
import com.android.sdklib.SdkConstants;
@@ -256,11 +257,7 @@ public class AndroidManifestParser {
handleError(e, -1 /* lineNumber */);
}
} else if (NODE_INSTRUMENTATION.equals(localName)) {
value = getAttributeValue(attributes, ATTRIBUTE_NAME,
true /* hasNamespace */);
if (value != null) {
mInstrumentations.add(value);
}
processInstrumentationNode(attributes);
}
break;
case LEVEL_ACTIVITY:
@@ -450,6 +447,25 @@ public class AndroidManifestParser {
}
}
/**
* Processes the instrumentation nodes.
* @param attributes the attributes for the activity node.
* node is representing
*/
private void processInstrumentationNode(Attributes attributes) {
// lets get the class name, and check it if required.
String instrumentationName = getAttributeValue(attributes, ATTRIBUTE_NAME,
true /* hasNamespace */);
if (instrumentationName != null) {
String instrClassName = combinePackageAndClassName(mPackage, instrumentationName);
mInstrumentations.add(instrClassName);
if (mMarkErrors) {
checkClass(instrClassName, AndroidConstants.CLASS_INSTRUMENTATION,
true /* testVisibility */);
}
}
}
/**
* Checks that a class is valid and can be used in the Android Manifest.
* <p/>
@@ -485,7 +501,6 @@ public class AndroidManifestParser {
}
}
}
}
/**
@@ -565,7 +580,6 @@ public class AndroidManifestParser {
ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
errorListener, gatherData, javaProject, markErrors);
parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
// get the result from the handler
@@ -576,9 +590,14 @@ public class AndroidManifestParser {
manifestHandler.getApiLevelRequirement(), manifestHandler.getInstrumentations(),
manifestHandler.getUsesLibraries());
} catch (ParserConfigurationException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s", manifestFile.getFullPath());
} catch (SAXException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s", manifestFile.getFullPath());
} catch (IOException e) {
} finally {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s", manifestFile.getFullPath());
}
return null;
@@ -619,11 +638,15 @@ public class AndroidManifestParser {
manifestHandler.getApiLevelRequirement(), manifestHandler.getInstrumentations(),
manifestHandler.getUsesLibraries());
} catch (ParserConfigurationException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s", manifestFile.getAbsolutePath());
} catch (SAXException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s", manifestFile.getAbsolutePath());
} catch (IOException e) {
} finally {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s", manifestFile.getAbsolutePath());
}
return null;
}
@@ -646,10 +669,12 @@ public class AndroidManifestParser {
boolean gatherData,
boolean markErrors)
throws CoreException {
IFile manifestFile = getManifest(javaProject.getProject());
try {
SAXParser parser = sParserFactory.newSAXParser();
IFile manifestFile = getManifest(javaProject.getProject());
if (manifestFile != null) {
ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
errorListener, gatherData, javaProject, markErrors);
@@ -664,9 +689,14 @@ public class AndroidManifestParser {
manifestHandler.getInstrumentations(), manifestHandler.getUsesLibraries());
}
} catch (ParserConfigurationException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s", manifestFile.getFullPath());
} catch (SAXException e) {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s", manifestFile.getFullPath());
} catch (IOException e) {
} finally {
AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s", manifestFile.getFullPath());
}
return null;

View File

@@ -61,8 +61,10 @@ import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.LanguageReg
import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.MobileCodeVerifier;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.api.ILayoutResult;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
import com.android.sdklib.IAndroidTarget;
@@ -222,7 +224,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
// updateUiFromFramework will reset language/region combo, so we must call
// setConfiguration after, or the settext on language/region will be lost.
if (mEditedConfig != null) {
setConfiguration(mEditedConfig);
setConfiguration(mEditedConfig, false /*force*/);
}
// make sure we remove the custom view loader, since its parent class loader is the
@@ -867,7 +869,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
@Override
void editNewFile(FolderConfiguration configuration) {
// update the configuration UI
setConfiguration(configuration);
setConfiguration(configuration, true /*force*/);
// enable the create button if the current and edited config are not equals
mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false);
@@ -976,17 +978,13 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (themeIndex != -1) {
String theme = mThemeCombo.getItem(themeIndex);
// change the string if it's a custom theme to make sure we can
// differentiate them
if (themeIndex >= mPlatformThemeCount) {
theme = "*" + theme; //$NON-NLS-1$
}
// Render a single object as described by the ViewElementDescriptor.
WidgetPullParser parser = new WidgetPullParser(descriptor);
ILayoutResult result = bridge.bridge.computeLayout(parser,
ILayoutResult result = computeLayout(bridge, parser,
null /* projectKey */,
300 /* width */, 300 /* height */, theme,
300 /* width */, 300 /* height */, 160 /*density*/,
160.f /*xdpi*/, 160.f /*ydpi*/, theme,
themeIndex >= mPlatformThemeCount /*isProjectTheme*/,
configuredProjectResources, frameworkResources, projectCallback,
null /* logger */);
@@ -1073,11 +1071,14 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
/**
* Update the UI controls state with a given {@link FolderConfiguration}.
* <p/>If a qualifier is not present in the {@link FolderConfiguration} object, the UI control
* is not modified. However if the value in the control is not the default value, a warning
* icon is showed.
* <p/>If <var>force</var> is set to <code>true</code> the UI will be changed to exactly reflect
* <var>config</var>, otherwise, if a qualifier is not present in <var>config</var>,
* the UI control is not modified. However if the value in the control is not the default value,
* a warning icon is shown.
* @param config The {@link FolderConfiguration} to set.
* @param force Whether the UI should be changed to exactly match the received configuration.
*/
void setConfiguration(FolderConfiguration config) {
void setConfiguration(FolderConfiguration config, boolean force) {
mDisableUpdates = true; // we do not want to trigger onXXXChange when setting new values in the widgets.
mEditedConfig = config;
@@ -1088,6 +1089,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (countryQualifier != null) {
mCountry.setText(String.format("%1$d", countryQualifier.getCode()));
mCurrentConfig.setCountryCodeQualifier(countryQualifier);
} else if (force) {
mCountry.setText(""); //$NON-NLS-1$
mCurrentConfig.setCountryCodeQualifier(null);
} else if (mCountry.getText().length() > 0) {
mCountryIcon.setImage(mWarningImage);
}
@@ -1097,6 +1101,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (networkQualifier != null) {
mNetwork.setText(String.format("%1$d", networkQualifier.getCode()));
mCurrentConfig.setNetworkCodeQualifier(networkQualifier);
} else if (force) {
mNetwork.setText(""); //$NON-NLS-1$
mCurrentConfig.setNetworkCodeQualifier(null);
} else if (mNetwork.getText().length() > 0) {
mNetworkIcon.setImage(mWarningImage);
}
@@ -1106,6 +1113,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (languageQualifier != null) {
mLanguage.setText(languageQualifier.getValue());
mCurrentConfig.setLanguageQualifier(languageQualifier);
} else if (force) {
mLanguage.setText(""); //$NON-NLS-1$
mCurrentConfig.setLanguageQualifier(null);
} else if (mLanguage.getText().length() > 0) {
mLanguageIcon.setImage(mWarningImage);
}
@@ -1115,6 +1125,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (regionQualifier != null) {
mRegion.setText(regionQualifier.getValue());
mCurrentConfig.setRegionQualifier(regionQualifier);
} else if (force) {
mRegion.setText(""); //$NON-NLS-1$
mCurrentConfig.setRegionQualifier(null);
} else if (mRegion.getText().length() > 0) {
mRegionIcon.setImage(mWarningImage);
}
@@ -1125,6 +1138,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
mOrientation.select(
ScreenOrientation.getIndex(orientationQualifier.getValue()) + 1);
mCurrentConfig.setScreenOrientationQualifier(orientationQualifier);
} else if (force) {
mOrientation.select(0);
mCurrentConfig.setScreenOrientationQualifier(null);
} else if (mOrientation.getSelectionIndex() != 0) {
mOrientationIcon.setImage(mWarningImage);
}
@@ -1134,6 +1150,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (densityQualifier != null) {
mDensity.setText(String.format("%1$d", densityQualifier.getValue()));
mCurrentConfig.setPixelDensityQualifier(densityQualifier);
} else if (force) {
mDensity.setText(""); //$NON-NLS-1$
mCurrentConfig.setPixelDensityQualifier(null);
} else if (mDensity.getText().length() > 0) {
mDensityIcon.setImage(mWarningImage);
}
@@ -1143,6 +1162,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (touchQualifier != null) {
mTouch.select(TouchScreenType.getIndex(touchQualifier.getValue()) + 1);
mCurrentConfig.setTouchTypeQualifier(touchQualifier);
} else if (force) {
mTouch.select(0);
mCurrentConfig.setTouchTypeQualifier(null);
} else if (mTouch.getSelectionIndex() != 0) {
mTouchIcon.setImage(mWarningImage);
}
@@ -1152,6 +1174,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (keyboardQualifier != null) {
mKeyboard.select(KeyboardState.getIndex(keyboardQualifier.getValue()) + 1);
mCurrentConfig.setKeyboardStateQualifier(keyboardQualifier);
} else if (force) {
mKeyboard.select(0);
mCurrentConfig.setKeyboardStateQualifier(null);
} else if (mKeyboard.getSelectionIndex() != 0) {
mKeyboardIcon.setImage(mWarningImage);
}
@@ -1161,6 +1186,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
if (inputQualifier != null) {
mTextInput.select(TextInputMethod.getIndex(inputQualifier.getValue()) + 1);
mCurrentConfig.setTextInputMethodQualifier(inputQualifier);
} else if (force) {
mTextInput.select(0);
mCurrentConfig.setTextInputMethodQualifier(null);
} else if (mTextInput.getSelectionIndex() != 0) {
mTextInputIcon.setImage(mWarningImage);
}
@@ -1171,6 +1199,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
mNavigation.select(
NavigationMethod.getIndex(navigationQualifiter.getValue()) + 1);
mCurrentConfig.setNavigationMethodQualifier(navigationQualifiter);
} else if (force) {
mNavigation.select(0);
mCurrentConfig.setNavigationMethodQualifier(null);
} else if (mNavigation.getSelectionIndex() != 0) {
mNavigationIcon.setImage(mWarningImage);
}
@@ -1181,6 +1212,10 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
mSize1.setText(String.format("%1$d", sizeQualifier.getValue1()));
mSize2.setText(String.format("%1$d", sizeQualifier.getValue2()));
mCurrentConfig.setScreenDimensionQualifier(sizeQualifier);
} else if (force) {
mSize1.setText(""); //$NON-NLS-1$
mSize2.setText(""); //$NON-NLS-1$
mCurrentConfig.setScreenDimensionQualifier(null);
} else if (mSize1.getText().length() > 0 && mSize2.getText().length() > 0) {
mSizeIcon.setImage(mWarningImage);
}
@@ -1607,7 +1642,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
// at this point, we have not opened a new file.
// update the configuration icons with the new edited config.
setConfiguration(mEditedConfig);
setConfiguration(mEditedConfig, false /*force*/);
// enable the create button if the current and edited config are not equals
mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false);
@@ -1794,44 +1829,15 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
// Compute the layout
UiElementPullParser parser = new UiElementPullParser(getModel());
Rectangle rect = getBounds();
ILayoutResult result = null;
if (bridge.apiLevel >= 3) {
// call the new api with proper theme differentiator and
// density/dpi support.
boolean isProjectTheme = themeIndex >= mPlatformThemeCount;
// FIXME pass the density/dpi from somewhere (resource config or skin).
result = bridge.bridge.computeLayout(parser,
ILayoutResult result = computeLayout(bridge, parser,
iProject /* projectKey */,
rect.width, rect.height, 160, 160.f, 160.f,
theme, isProjectTheme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
} else if (bridge.apiLevel == 2) {
// api with boolean for separation of project/framework theme
boolean isProjectTheme = themeIndex >= mPlatformThemeCount;
result = bridge.bridge.computeLayout(parser,
iProject /* projectKey */,
rect.width, rect.height, theme, isProjectTheme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
} else {
// oldest api with no density/dpi, and project theme boolean mixed
// into the theme name.
// change the string if it's a custom theme to make sure we can
// differentiate them
if (themeIndex >= mPlatformThemeCount) {
theme = "*" + theme; //$NON-NLS-1$
}
result = bridge.bridge.computeLayout(parser,
iProject /* projectKey */,
rect.width, rect.height, theme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
}
// update the UiElementNode with the layout info.
if (result.getSuccess() == ILayoutResult.SUCCESS) {
@@ -2383,4 +2389,48 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
return null;
}
/**
* Computes a layout by calling the correct computeLayout method of ILayoutBridge based on
* the implementation API level.
*/
@SuppressWarnings("deprecation")
private ILayoutResult computeLayout(LayoutBridge bridge,
IXmlPullParser layoutDescription, Object projectKey,
int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
String themeName, boolean isProjectTheme,
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback projectCallback, ILayoutLog logger) {
if (bridge.apiLevel >= 3) {
// newer api with boolean for separation of project/framework theme,
// and density support.
return bridge.bridge.computeLayout(layoutDescription,
projectKey, screenWidth, screenHeight, density, xdpi, ydpi,
themeName, isProjectTheme,
projectResources, frameworkResources, projectCallback,
logger);
} else if (bridge.apiLevel == 2) {
// api with boolean for separation of project/framework theme
return bridge.bridge.computeLayout(layoutDescription,
projectKey, screenWidth, screenHeight, themeName, isProjectTheme,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
} else {
// oldest api with no density/dpi, and project theme boolean mixed
// into the theme name.
// change the string if it's a custom theme to make sure we can
// differentiate them
if (isProjectTheme) {
themeName = "*" + themeName; //$NON-NLS-1$
}
return bridge.bridge.computeLayout(layoutDescription,
projectKey, screenWidth, screenHeight, themeName,
mConfiguredProjectRes, frameworkResources, mProjectCallback,
mLogger);
}
}
}

View File

@@ -15,7 +15,13 @@
*/
package com.android.ide.eclipse.tests;
import com.android.ide.eclipse.common.AndroidConstants;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Logger;
@@ -45,12 +51,29 @@ public class AdtTestData {
// accessed normally
mOsRootDataPath = System.getProperty("test_data");
if (mOsRootDataPath == null) {
sLogger.info("Cannot find test_data directory, init to class loader");
sLogger.info("Cannot find test_data environment variable, init to class loader");
URL url = this.getClass().getClassLoader().getResource("data"); //$NON-NLS-1$
if (Platform.isRunning()) {
sLogger.info("Running as an Eclipse Plug-in JUnit test, using FileLocator");
try {
mOsRootDataPath = FileLocator.resolve(url).getFile();
} catch (IOException e) {
sLogger.warning("IOException while using FileLocator, reverting to url");
mOsRootDataPath = url.getFile();
}
} else {
sLogger.info("Running as an plain JUnit test, using url as-is");
mOsRootDataPath = url.getFile();
}
}
if (mOsRootDataPath.equals(AndroidConstants.WS_SEP + "data")) {
sLogger.warning("Resource data not found using class loader!, Defaulting to no path");
}
if (!mOsRootDataPath.endsWith(File.separator)) {
sLogger.info("Fixing test_data env variable does not end with path separator");
sLogger.info("Fixing test_data env variable (does not end with path separator)");
mOsRootDataPath = mOsRootDataPath.concat(File.separator);
}
}

View File

@@ -16,16 +16,19 @@
package com.android.ide.eclipse.common.project;
import junit.framework.TestCase;
import com.android.ide.eclipse.tests.AdtTestData;
import com.android.ide.eclipse.mock.FileMock;
import junit.framework.TestCase;
/**
* Tests for {@link AndroidManifestParser}
*/
public class AndroidManifestParserTest extends TestCase {
private AndroidManifestParser mManifest;
private AndroidManifestParser mManifestTestApp;
private AndroidManifestParser mManifestInstrumentation;
private static final String INSTRUMENTATION_XML = "AndroidManifest-instrumentation.xml"; //$NON-NLS-1$
private static final String TESTAPP_XML = "AndroidManifest-testapp.xml"; //$NON-NLS-1$
private static final String PACKAGE_NAME = "com.android.testapp"; //$NON-NLS-1$
private static final String ACTIVITY_NAME = "com.android.testapp.MainActivity"; //$NON-NLS-1$
private static final String LIBRARY_NAME = "android.test.runner"; //$NON-NLS-1$
@@ -35,60 +38,46 @@ public class AndroidManifestParserTest extends TestCase {
protected void setUp() throws Exception {
super.setUp();
// create the test data
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$
sb.append("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"); //$NON-NLS-1$
sb.append(" package=\""); //$NON-NLS-1$
sb.append(PACKAGE_NAME);
sb.append("\">\n"); //$NON-NLS-1$
sb.append(" <application android:icon=\"@drawable/icon\">\n"); //$NON-NLS-1$
sb.append(" <activity android:name=\""); //$NON-NLS-1$
sb.append(ACTIVITY_NAME);
sb.append("\" android:label=\"@string/app_name\">\n"); //$NON-NLS-1$
sb.append(" <intent-filter>\n"); //$NON-NLS-1$
sb.append(" <action android:name=\"android.intent.action.MAIN\" />\n"); //$NON-NLS-1$
sb.append(" <category android:name=\"android.intent.category.LAUNCHER\" />\"\n"); //$NON-NLS-1$
sb.append(" <category android:name=\"android.intent.category.DEFAULT\" />\n"); //$NON-NLS-1$
sb.append(" </intent-filter>\n"); //$NON-NLS-1$
sb.append(" </activity>\n"); //$NON-NLS-1$
sb.append(" <uses-library android:name=\""); //$NON-NLS-1$
sb.append(LIBRARY_NAME);
sb.append("\" />\n"); //$NON-NLS-1$
sb.append(" </application>"); //$NON-NLS-1$
sb.append(" <instrumentation android:name=\""); //$NON-NLS-1$
sb.append(INSTRUMENTATION_NAME);
sb.append("\"\n");
sb.append(" android:targetPackage=\"com.example.android.apis\"\n");
sb.append(" android:label=\"Tests for Api Demos.\"/>\n");
sb.append("</manifest>\n"); //$NON-NLS-1$
String testFilePath = AdtTestData.getInstance().getTestFilePath(
TESTAPP_XML);
mManifestTestApp = AndroidManifestParser.parseForData(testFilePath);
assertNotNull(mManifestTestApp);
FileMock mockFile = new FileMock("AndroidManifest.xml", sb.toString().getBytes());
testFilePath = AdtTestData.getInstance().getTestFilePath(
INSTRUMENTATION_XML);
mManifestInstrumentation = AndroidManifestParser.parseForData(testFilePath);
assertNotNull(mManifestInstrumentation);
}
mManifest = AndroidManifestParser.parseForData(mockFile);
assertNotNull(mManifest);
public void testGetInstrumentationInformation() {
assertEquals(1, mManifestInstrumentation.getInstrumentations().length);
assertEquals(INSTRUMENTATION_NAME, mManifestTestApp.getInstrumentations()[0]);
}
public void testGetPackage() {
assertEquals("com.android.testapp", mManifest.getPackage());
assertEquals(PACKAGE_NAME, mManifestTestApp.getPackage());
}
public void testGetActivities() {
assertEquals(1, mManifest.getActivities().length);
assertEquals(ACTIVITY_NAME, mManifest.getActivities()[0]);
assertEquals(1, mManifestTestApp.getActivities().length);
assertEquals(ACTIVITY_NAME, mManifestTestApp.getActivities()[0]);
}
public void testGetLauncherActivity() {
assertEquals(ACTIVITY_NAME, mManifest.getLauncherActivity());
assertEquals(ACTIVITY_NAME, mManifestTestApp.getLauncherActivity());
}
public void testGetUsesLibraries() {
assertEquals(1, mManifest.getUsesLibraries().length);
assertEquals(LIBRARY_NAME, mManifest.getUsesLibraries()[0]);
assertEquals(1, mManifestTestApp.getUsesLibraries().length);
assertEquals(LIBRARY_NAME, mManifestTestApp.getUsesLibraries()[0]);
}
public void testGetInstrumentations() {
assertEquals(1, mManifest.getInstrumentations().length);
assertEquals(INSTRUMENTATION_NAME, mManifest.getInstrumentations()[0]);
assertEquals(1, mManifestTestApp.getInstrumentations().length);
assertEquals(INSTRUMENTATION_NAME, mManifestTestApp.getInstrumentations()[0]);
}
public void testGetPackageName() {
assertEquals(PACKAGE_NAME, mManifestTestApp.getPackage());
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.AndroidProject.tests">
<!--
This declares that this app uses the instrumentation test runner targeting
the package of com.android.samples. To run the tests use the command:
"adb shell am instrument -w com.android.samples.tests/android.test.InstrumentationTestRunner"
-->
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.AndroidProject"
android:label="Sample test for deployment."/>
<application>
<uses-library android:name="android.test.runner" />
</application>
</manifest>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.testapp">
<application android:icon="@drawable/icon">
<activity android:name="com.android.testapp.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />"
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<uses-library android:name="android.test.runner"/>
</application>"
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.android.apis"
android:label="Tests for Api Demos."/>
</manifest>

View File

@@ -177,7 +177,7 @@ public final class AvdManager {
public AvdManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
mSdk = sdk;
mSdkLog = sdkLog;
buildAvdList();
buildAvdList(mAvdList);
}
/**
@@ -202,6 +202,20 @@ public final class AvdManager {
return null;
}
/**
* Reloads the AVD list.
* @throws AndroidLocationException if there was an error finding the location of the
* AVD folder.
*/
public void reloadAvds() throws AndroidLocationException {
// build the list in a temp list first, in case the method throws an exception.
// It's better than deleting the whole list before reading the new one.
ArrayList<AvdInfo> list = new ArrayList<AvdInfo>();
buildAvdList(list);
mAvdList.clear();
mAvdList.addAll(list);
}
/**
* Creates a new AVD. It is expected that there is no existing AVD with this name already.
* @param avdFolder the data folder for the AVD. It will be created as needed.
@@ -620,7 +634,7 @@ public final class AvdManager {
}
}
private void buildAvdList() throws AndroidLocationException {
private void buildAvdList(ArrayList<AvdInfo> list) throws AndroidLocationException {
// get the Android prefs location.
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
@@ -664,7 +678,7 @@ public final class AvdManager {
for (File avd : avds) {
AvdInfo info = parseAvdInfo(avd);
if (info != null) {
mAvdList.add(info);
list.add(info);
if (avdListDebug) {
mSdkLog.printf("[AVD LIST DEBUG] Added AVD '%s'\n", info.getPath());
}