merge from donut
This commit is contained in:
21
apps/Fallback/res/values-da/strings.xml
Normal file
21
apps/Fallback/res/values-da/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Reserve"</string>
|
||||||
|
<string name="title">"Ikke understøttet handling"</string>
|
||||||
|
<string name="error">"Handlingen er ikke understøttet i øjeblikket."</string>
|
||||||
|
</resources>
|
||||||
21
apps/Fallback/res/values-el/strings.xml
Normal file
21
apps/Fallback/res/values-el/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Εναλλακτική"</string>
|
||||||
|
<string name="title">"Ενέργεια που δεν υποστηρίζεται"</string>
|
||||||
|
<string name="error">"Αυτή η ενέργεια δεν υποστηρίζεται αυτήν τη στιγμή."</string>
|
||||||
|
</resources>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="appTitle">"Fallback"</string>
|
<string name="appTitle">"폴백"</string>
|
||||||
<string name="title">"지원되지 않는 작업"</string>
|
<string name="title">"지원되지 않는 작업"</string>
|
||||||
<string name="error">"이 작업은 현재 지원되지 않습니다."</string>
|
<string name="error">"이 작업은 현재 지원되지 않습니다."</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
21
apps/Fallback/res/values-pt-rPT/strings.xml
Normal file
21
apps/Fallback/res/values-pt-rPT/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Fallback"</string>
|
||||||
|
<string name="title">"Acção não suportada"</string>
|
||||||
|
<string name="error">"Esta·acção·ainda·não·é·suportada."</string>
|
||||||
|
</resources>
|
||||||
@@ -17,5 +17,5 @@
|
|||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="appTitle">"Fallback"</string>
|
<string name="appTitle">"Fallback"</string>
|
||||||
<string name="title">"Ação não suportada"</string>
|
<string name="title">"Ação não suportada"</string>
|
||||||
<string name="error">"Esta ação não é suportada no momento."</string>
|
<string name="error">"Essa ação não é suportada no momento."</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="appTitle">"Fallback"</string>
|
<string name="appTitle">"Переход в обходной режим"</string>
|
||||||
<string name="title">"Действие не поддерживается"</string>
|
<string name="title">"Неподдерживаемое действие"</string>
|
||||||
<string name="error">"В настоящее время это действие не поддерживается."</string>
|
<string name="error">"В настоящее время это действие не поддерживается."</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
21
apps/Fallback/res/values-sv/strings.xml
Normal file
21
apps/Fallback/res/values-sv/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Reserv"</string>
|
||||||
|
<string name="title">"Åtgärden stöds inte"</string>
|
||||||
|
<string name="error">"Den här åtgärden stöds inte för närvarande."</string>
|
||||||
|
</resources>
|
||||||
21
apps/Fallback/res/values-tr/strings.xml
Normal file
21
apps/Fallback/res/values-tr/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Fallback"</string>
|
||||||
|
<string name="title">"Desteklenmeyen işlem"</string>
|
||||||
|
<string name="error">"Bu işlem şu an desteklenmiyor."</string>
|
||||||
|
</resources>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="appTitle">"Fallback"</string>
|
<string name="appTitle">"后备"</string>
|
||||||
<string name="title">"不支持的操作"</string>
|
<string name="title">"不支持此操作"</string>
|
||||||
<string name="error">"当前不支持该操作。"</string>
|
<string name="error">"目前不支持该操作。"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
25
apps/GestureBuilder/Android.mk
Normal file
25
apps/GestureBuilder/Android.mk
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2009 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.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := GestureBuilder
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
43
apps/GestureBuilder/AndroidManifest.xml
Normal file
43
apps/GestureBuilder/AndroidManifest.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.gesture.builder">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<application>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="GestureBuilderActivity"
|
||||||
|
android:label="@string/application_name"
|
||||||
|
android:icon="@drawable/ic_gesturebuilder">
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="CreateGestureActivity"
|
||||||
|
android:label="@string/label_create_gesture" />
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
190
apps/GestureBuilder/NOTICE
Normal file
190
apps/GestureBuilder/NOTICE
Normal 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
|
||||||
|
|
||||||
2100
apps/GestureBuilder/graphics/gesturebuilder.ai
Normal file
2100
apps/GestureBuilder/graphics/gesturebuilder.ai
Normal file
File diff suppressed because one or more lines are too long
BIN
apps/GestureBuilder/graphics/gesturebuilder.eps
Normal file
BIN
apps/GestureBuilder/graphics/gesturebuilder.eps
Normal file
Binary file not shown.
BIN
apps/GestureBuilder/res/drawable/ic_gesturebuilder.png
Normal file
BIN
apps/GestureBuilder/res/drawable/ic_gesturebuilder.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
88
apps/GestureBuilder/res/layout/create_gesture.xml
Normal file
88
apps/GestureBuilder/res/layout/create_gesture.xml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="6dip"
|
||||||
|
|
||||||
|
android:text="@string/prompt_gesture_name"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/gesture_name"
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_weight="1.0"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
android:maxLength="40"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<android.gesture.GestureOverlayView
|
||||||
|
android:id="@+id/gestures_overlay"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="0dip"
|
||||||
|
android:layout_weight="1.0"
|
||||||
|
|
||||||
|
android:gestureStrokeType="multiple" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@android:style/ButtonBar"
|
||||||
|
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/done"
|
||||||
|
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
|
||||||
|
android:enabled="false"
|
||||||
|
|
||||||
|
android:onClick="addGesture"
|
||||||
|
android:text="@string/button_done" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
|
||||||
|
android:onClick="cancelGesture"
|
||||||
|
android:text="@string/button_discard" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
41
apps/GestureBuilder/res/layout/dialog_rename.xml
Normal file
41
apps/GestureBuilder/res/layout/dialog_rename.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="20dip"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/gestures_rename_label"
|
||||||
|
android:gravity="left"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:autoText="false"
|
||||||
|
android:capitalize="none"
|
||||||
|
android:gravity="fill_horizontal"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
31
apps/GestureBuilder/res/layout/gestures_item.xml
Normal file
31
apps/GestureBuilder/res/layout/gestures_item.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@android:id/text1"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
|
||||||
|
android:drawablePadding="12dip"
|
||||||
|
android:paddingLeft="6dip"
|
||||||
|
android:paddingRight="6dip"
|
||||||
|
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
75
apps/GestureBuilder/res/layout/gestures_list.xml
Normal file
75
apps/GestureBuilder/res/layout/gestures_list.xml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@android:id/list"
|
||||||
|
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="0dip"
|
||||||
|
android:layout_weight="1.0" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/empty"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="0dip"
|
||||||
|
android:layout_weight="1.0"
|
||||||
|
|
||||||
|
android:gravity="center"
|
||||||
|
|
||||||
|
android:text="@string/gestures_loading"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@android:style/ButtonBar"
|
||||||
|
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/addButton"
|
||||||
|
android:onClick="addGesture"
|
||||||
|
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/button_add" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/reloadButton"
|
||||||
|
android:onClick="reloadGestures"
|
||||||
|
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/button_reload" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
22
apps/GestureBuilder/res/values/colors.xml
Normal file
22
apps/GestureBuilder/res/values/colors.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/* //device/apps/common/assets/res/any/colors.xml
|
||||||
|
**
|
||||||
|
** Copyright 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.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<color name="gesture_color">#FFFFFF00</color>
|
||||||
|
</resources>
|
||||||
20
apps/GestureBuilder/res/values/dimens.xml
Normal file
20
apps/GestureBuilder/res/values/dimens.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<dimen name="gesture_thumbnail_inset">8dip</dimen>
|
||||||
|
<dimen name="gesture_thumbnail_size">64dip</dimen>
|
||||||
|
</resources>
|
||||||
69
apps/GestureBuilder/res/values/strings.xml
Normal file
69
apps/GestureBuilder/res/values/strings.xml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<!-- General -->
|
||||||
|
<skip />
|
||||||
|
<!-- Application name -->
|
||||||
|
<string name="application_name">Gestures Builder</string>
|
||||||
|
<!-- Title, name of the activity used to create a gesture -->
|
||||||
|
<string name="label_create_gesture">Create a gesture</string>
|
||||||
|
|
||||||
|
<!-- Buttons -->
|
||||||
|
<skip />
|
||||||
|
<!-- Label, button used to add a gesture -->
|
||||||
|
<string name="button_add">Add gesture</string>
|
||||||
|
<!-- Label, button used to reload all gestures -->
|
||||||
|
<string name="button_reload">Reload</string>
|
||||||
|
<!-- Label, button used to cancel the operation of adding a gesture -->
|
||||||
|
<string name="button_discard">Discard</string>
|
||||||
|
<!-- Label, button used to save a gesture newly created -->
|
||||||
|
<string name="button_done">Done</string>
|
||||||
|
|
||||||
|
<!-- Gestures -->
|
||||||
|
<skip />
|
||||||
|
<!-- Label, prompt asking the user to enter the name of the gesture -->
|
||||||
|
<string name="prompt_gesture_name">Name</string>
|
||||||
|
<!-- Error message, informs the user he needs to enter a name before saving a gesture -->
|
||||||
|
<string name="error_missing_name">You must enter a name</string>
|
||||||
|
<!-- success message, tells the user where the gesture was saved -->
|
||||||
|
<string name="save_success">Gesture saved in %s</string>
|
||||||
|
<!-- Buttons in Rename gesture dialog box -->
|
||||||
|
<string name="rename_action">OK</string>
|
||||||
|
<!-- Buttons in Rename gesture dialog box -->
|
||||||
|
<string name="cancel_action">Cancel</string>
|
||||||
|
<!-- Message displayed when the user opens the gestures settings screen -->
|
||||||
|
<string name="gestures_loading">Loading gestures...</string>
|
||||||
|
<!-- Message displayed when the user has no gestures -->
|
||||||
|
<string name="gestures_empty">No gestures</string>
|
||||||
|
<!-- Title of the screen used to view/manage gestures -->
|
||||||
|
<string name="gestures_activity">Gestures</string>
|
||||||
|
<!-- Noun, menu item used to rename a gesture -->
|
||||||
|
<string name="gestures_rename">Rename</string>
|
||||||
|
<!-- Noun, menu item used to remove a gesture -->
|
||||||
|
<string name="gestures_delete">Delete</string>
|
||||||
|
<!-- Message displayed when a gesture is successfully deleted -->
|
||||||
|
<string name="gestures_delete_success">Gesture deleted</string>
|
||||||
|
<!-- Title of dialog box -->
|
||||||
|
<string name="gestures_rename_title">Rename gesture</string>
|
||||||
|
<!-- Label of gesture name field in Rename gesture dialog box -->
|
||||||
|
<string name="gestures_rename_label">Gesture name</string>
|
||||||
|
<!-- Message, displayed when the sdcard cannot be found, 1st parameter is the name of the file that stores the gestures -->
|
||||||
|
<string name="gestures_error_loading">Could not load %s. Make sure you have a mounted SD card.</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* 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.gesture.builder;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.gesture.GestureOverlayView;
|
||||||
|
import android.gesture.Gesture;
|
||||||
|
import android.gesture.GestureLibrary;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class CreateGestureActivity extends Activity {
|
||||||
|
private static final float LENGTH_THRESHOLD = 120.0f;
|
||||||
|
|
||||||
|
private Gesture mGesture;
|
||||||
|
private View mDoneButton;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.create_gesture);
|
||||||
|
|
||||||
|
mDoneButton = findViewById(R.id.done);
|
||||||
|
|
||||||
|
GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay);
|
||||||
|
overlay.addOnGestureListener(new GesturesProcessor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
|
if (mGesture != null) {
|
||||||
|
outState.putParcelable("gesture", mGesture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
|
||||||
|
mGesture = savedInstanceState.getParcelable("gesture");
|
||||||
|
if (mGesture != null) {
|
||||||
|
final GestureOverlayView overlay =
|
||||||
|
(GestureOverlayView) findViewById(R.id.gestures_overlay);
|
||||||
|
overlay.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
overlay.setGesture(mGesture);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mDoneButton.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
|
public void addGesture(View v) {
|
||||||
|
if (mGesture != null) {
|
||||||
|
final TextView input = (TextView) findViewById(R.id.gesture_name);
|
||||||
|
final CharSequence name = input.getText();
|
||||||
|
if (name.length() == 0) {
|
||||||
|
input.setError(getString(R.string.error_missing_name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final GestureLibrary store = GestureBuilderActivity.getStore();
|
||||||
|
store.addGesture(name.toString(), mGesture);
|
||||||
|
store.save();
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
|
||||||
|
final String path = new File(Environment.getExternalStorageDirectory(),
|
||||||
|
"gestures").getAbsolutePath();
|
||||||
|
Toast.makeText(this, getString(R.string.save_success, path), Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
setResult(RESULT_CANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
|
public void cancelGesture(View v) {
|
||||||
|
setResult(RESULT_CANCELED);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GesturesProcessor implements GestureOverlayView.OnGestureListener {
|
||||||
|
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
|
||||||
|
mDoneButton.setEnabled(false);
|
||||||
|
mGesture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
|
||||||
|
mGesture = overlay.getGesture();
|
||||||
|
if (mGesture.getLength() < LENGTH_THRESHOLD) {
|
||||||
|
overlay.clear(false);
|
||||||
|
}
|
||||||
|
mDoneButton.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,437 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* 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.gesture.builder;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.gesture.GestureLibrary;
|
||||||
|
import android.gesture.Gesture;
|
||||||
|
import android.gesture.GestureLibraries;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class GestureBuilderActivity extends ListActivity {
|
||||||
|
private static final int STATUS_SUCCESS = 0;
|
||||||
|
private static final int STATUS_CANCELLED = 1;
|
||||||
|
private static final int STATUS_NO_STORAGE = 2;
|
||||||
|
private static final int STATUS_NOT_LOADED = 3;
|
||||||
|
|
||||||
|
private static final int MENU_ID_RENAME = 1;
|
||||||
|
private static final int MENU_ID_REMOVE = 2;
|
||||||
|
|
||||||
|
private static final int DIALOG_RENAME_GESTURE = 1;
|
||||||
|
|
||||||
|
private static final int REQUEST_NEW_GESTURE = 1;
|
||||||
|
|
||||||
|
// Type: long (id)
|
||||||
|
private static final String GESTURES_INFO_ID = "gestures.info_id";
|
||||||
|
|
||||||
|
private final File mStoreFile = new File(Environment.getExternalStorageDirectory(), "gestures");
|
||||||
|
|
||||||
|
private final Comparator<NamedGesture> mSorter = new Comparator<NamedGesture>() {
|
||||||
|
public int compare(NamedGesture object1, NamedGesture object2) {
|
||||||
|
return object1.name.compareTo(object2.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static GestureLibrary sStore;
|
||||||
|
|
||||||
|
private GesturesAdapter mAdapter;
|
||||||
|
private GesturesLoadTask mTask;
|
||||||
|
private TextView mEmpty;
|
||||||
|
|
||||||
|
private Dialog mRenameDialog;
|
||||||
|
private EditText mInput;
|
||||||
|
private NamedGesture mCurrentRenameGesture;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.gestures_list);
|
||||||
|
|
||||||
|
mAdapter = new GesturesAdapter(this);
|
||||||
|
setListAdapter(mAdapter);
|
||||||
|
|
||||||
|
if (sStore == null) {
|
||||||
|
sStore = GestureLibraries.fromFile(mStoreFile);
|
||||||
|
}
|
||||||
|
mEmpty = (TextView) findViewById(android.R.id.empty);
|
||||||
|
loadGestures();
|
||||||
|
|
||||||
|
registerForContextMenu(getListView());
|
||||||
|
}
|
||||||
|
|
||||||
|
static GestureLibrary getStore() {
|
||||||
|
return sStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
|
public void reloadGestures(View v) {
|
||||||
|
loadGestures();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
|
public void addGesture(View v) {
|
||||||
|
Intent intent = new Intent(this, CreateGestureActivity.class);
|
||||||
|
startActivityForResult(intent, REQUEST_NEW_GESTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_NEW_GESTURE:
|
||||||
|
loadGestures();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadGestures() {
|
||||||
|
if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) {
|
||||||
|
mTask.cancel(true);
|
||||||
|
}
|
||||||
|
mTask = (GesturesLoadTask) new GesturesLoadTask().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) {
|
||||||
|
mTask.cancel(true);
|
||||||
|
mTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupRenameDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkForEmpty() {
|
||||||
|
if (mAdapter.getCount() == 0) {
|
||||||
|
mEmpty.setText(R.string.gestures_empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
|
if (mCurrentRenameGesture != null) {
|
||||||
|
outState.putLong(GESTURES_INFO_ID, mCurrentRenameGesture.gesture.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle state) {
|
||||||
|
super.onRestoreInstanceState(state);
|
||||||
|
|
||||||
|
long id = state.getLong(GESTURES_INFO_ID, -1);
|
||||||
|
if (id != -1) {
|
||||||
|
final Set<String> entries = sStore.getGestureEntries();
|
||||||
|
out: for (String name : entries) {
|
||||||
|
for (Gesture gesture : sStore.getGestures(name)) {
|
||||||
|
if (gesture.getID() == id) {
|
||||||
|
mCurrentRenameGesture = new NamedGesture();
|
||||||
|
mCurrentRenameGesture.name = name;
|
||||||
|
mCurrentRenameGesture.gesture = gesture;
|
||||||
|
break out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
|
ContextMenu.ContextMenuInfo menuInfo) {
|
||||||
|
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
|
||||||
|
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||||
|
menu.setHeaderTitle(((TextView) info.targetView).getText());
|
||||||
|
|
||||||
|
menu.add(0, MENU_ID_RENAME, 0, R.string.gestures_rename);
|
||||||
|
menu.add(0, MENU_ID_REMOVE, 0, R.string.gestures_delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
|
final AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)
|
||||||
|
item.getMenuInfo();
|
||||||
|
final NamedGesture gesture = (NamedGesture) menuInfo.targetView.getTag();
|
||||||
|
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case MENU_ID_RENAME:
|
||||||
|
renameGesture(gesture);
|
||||||
|
return true;
|
||||||
|
case MENU_ID_REMOVE:
|
||||||
|
deleteGesture(gesture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onContextItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renameGesture(NamedGesture gesture) {
|
||||||
|
mCurrentRenameGesture = gesture;
|
||||||
|
showDialog(DIALOG_RENAME_GESTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
if (id == DIALOG_RENAME_GESTURE) {
|
||||||
|
return createRenameDialog();
|
||||||
|
}
|
||||||
|
return super.onCreateDialog(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||||
|
super.onPrepareDialog(id, dialog);
|
||||||
|
if (id == DIALOG_RENAME_GESTURE) {
|
||||||
|
mInput.setText(mCurrentRenameGesture.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dialog createRenameDialog() {
|
||||||
|
final View layout = View.inflate(this, R.layout.dialog_rename, null);
|
||||||
|
mInput = (EditText) layout.findViewById(R.id.name);
|
||||||
|
((TextView) layout.findViewById(R.id.label)).setText(R.string.gestures_rename_label);
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setIcon(0);
|
||||||
|
builder.setTitle(getString(R.string.gestures_rename_title));
|
||||||
|
builder.setCancelable(true);
|
||||||
|
builder.setOnCancelListener(new Dialog.OnCancelListener() {
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
cleanupRenameDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(getString(R.string.cancel_action),
|
||||||
|
new Dialog.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
cleanupRenameDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
builder.setPositiveButton(getString(R.string.rename_action),
|
||||||
|
new Dialog.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
changeGestureName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
builder.setView(layout);
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeGestureName() {
|
||||||
|
final String name = mInput.getText().toString();
|
||||||
|
if (!TextUtils.isEmpty(name)) {
|
||||||
|
final NamedGesture renameGesture = mCurrentRenameGesture;
|
||||||
|
final GesturesAdapter adapter = mAdapter;
|
||||||
|
final int count = adapter.getCount();
|
||||||
|
|
||||||
|
// Simple linear search, there should not be enough items to warrant
|
||||||
|
// a more sophisticated search
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final NamedGesture gesture = adapter.getItem(i);
|
||||||
|
if (gesture.gesture.getID() == renameGesture.gesture.getID()) {
|
||||||
|
sStore.removeGesture(gesture.name, gesture.gesture);
|
||||||
|
gesture.name = mInput.getText().toString();
|
||||||
|
sStore.addGesture(gesture.name, gesture.gesture);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
mCurrentRenameGesture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanupRenameDialog() {
|
||||||
|
if (mRenameDialog != null) {
|
||||||
|
mRenameDialog.dismiss();
|
||||||
|
mRenameDialog = null;
|
||||||
|
}
|
||||||
|
mCurrentRenameGesture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteGesture(NamedGesture gesture) {
|
||||||
|
sStore.removeGesture(gesture.name, gesture.gesture);
|
||||||
|
sStore.save();
|
||||||
|
|
||||||
|
final GesturesAdapter adapter = mAdapter;
|
||||||
|
adapter.setNotifyOnChange(false);
|
||||||
|
adapter.remove(gesture);
|
||||||
|
adapter.sort(mSorter);
|
||||||
|
checkForEmpty();
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
Toast.makeText(this, R.string.gestures_delete_success, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GesturesLoadTask extends AsyncTask<Void, NamedGesture, Integer> {
|
||||||
|
private int mThumbnailSize;
|
||||||
|
private int mThumbnailInset;
|
||||||
|
private int mPathColor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
super.onPreExecute();
|
||||||
|
|
||||||
|
final Resources resources = getResources();
|
||||||
|
mPathColor = resources.getColor(R.color.gesture_color);
|
||||||
|
mThumbnailInset = (int) resources.getDimension(R.dimen.gesture_thumbnail_inset);
|
||||||
|
mThumbnailSize = (int) resources.getDimension(R.dimen.gesture_thumbnail_size);
|
||||||
|
|
||||||
|
findViewById(R.id.addButton).setEnabled(false);
|
||||||
|
findViewById(R.id.reloadButton).setEnabled(false);
|
||||||
|
|
||||||
|
mAdapter.setNotifyOnChange(false);
|
||||||
|
mAdapter.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer doInBackground(Void... params) {
|
||||||
|
if (isCancelled()) return STATUS_CANCELLED;
|
||||||
|
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
||||||
|
return STATUS_NO_STORAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
final GestureLibrary store = sStore;
|
||||||
|
|
||||||
|
if (store.load()) {
|
||||||
|
for (String name : store.getGestureEntries()) {
|
||||||
|
if (isCancelled()) break;
|
||||||
|
|
||||||
|
for (Gesture gesture : store.getGestures(name)) {
|
||||||
|
final Bitmap bitmap = gesture.toBitmap(mThumbnailSize, mThumbnailSize,
|
||||||
|
mThumbnailInset, mPathColor);
|
||||||
|
final NamedGesture namedGesture = new NamedGesture();
|
||||||
|
namedGesture.gesture = gesture;
|
||||||
|
namedGesture.name = name;
|
||||||
|
|
||||||
|
mAdapter.addBitmap(namedGesture.gesture.getID(), bitmap);
|
||||||
|
publishProgress(namedGesture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_NOT_LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(NamedGesture... values) {
|
||||||
|
super.onProgressUpdate(values);
|
||||||
|
|
||||||
|
final GesturesAdapter adapter = mAdapter;
|
||||||
|
adapter.setNotifyOnChange(false);
|
||||||
|
|
||||||
|
for (NamedGesture gesture : values) {
|
||||||
|
adapter.add(gesture);
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.sort(mSorter);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Integer result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
|
||||||
|
if (result == STATUS_NO_STORAGE) {
|
||||||
|
mList.setVisibility(View.GONE);
|
||||||
|
mEmpty.setVisibility(View.VISIBLE);
|
||||||
|
mEmpty.setText(getString(R.string.gestures_error_loading,
|
||||||
|
mStoreFile.getAbsolutePath()));
|
||||||
|
} else {
|
||||||
|
findViewById(R.id.addButton).setEnabled(true);
|
||||||
|
findViewById(R.id.reloadButton).setEnabled(true);
|
||||||
|
checkForEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NamedGesture {
|
||||||
|
String name;
|
||||||
|
Gesture gesture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GesturesAdapter extends ArrayAdapter<NamedGesture> {
|
||||||
|
private final LayoutInflater mInflater;
|
||||||
|
private final Map<Long, Drawable> mThumbnails = Collections.synchronizedMap(
|
||||||
|
new HashMap<Long, Drawable>());
|
||||||
|
|
||||||
|
public GesturesAdapter(Context context) {
|
||||||
|
super(context, 0);
|
||||||
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addBitmap(Long id, Bitmap bitmap) {
|
||||||
|
mThumbnails.put(id, new BitmapDrawable(bitmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = mInflater.inflate(R.layout.gestures_item, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
final NamedGesture gesture = getItem(position);
|
||||||
|
final TextView label = (TextView) convertView;
|
||||||
|
|
||||||
|
label.setTag(gesture);
|
||||||
|
label.setText(gesture.name);
|
||||||
|
label.setCompoundDrawablesWithIntrinsicBounds(mThumbnails.get(gesture.gesture.getID()),
|
||||||
|
null, null, null);
|
||||||
|
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,10 +45,6 @@
|
|||||||
<string name="summary_on_fancy_ime_animations">Use fancier animations for input method windows</string>
|
<string name="summary_on_fancy_ime_animations">Use fancier animations for input method windows</string>
|
||||||
<string name="summary_off_fancy_ime_animations">Use normal animations for input method windows</string>
|
<string name="summary_off_fancy_ime_animations">Use normal animations for input method windows</string>
|
||||||
|
|
||||||
<string name="title_fancy_rotation_animations">Fancy rotation animations</string>
|
|
||||||
<string name="summary_on_fancy_rotation_animations">Use fancier animations for screen rotation</string>
|
|
||||||
<string name="summary_off_fancy_rotation_animations">Use normal animations for screen rotation</string>
|
|
||||||
|
|
||||||
<string name="title_haptic_feedback">Haptic feedback</string>
|
<string name="title_haptic_feedback">Haptic feedback</string>
|
||||||
<string name="summary_on_haptic_feedback">Use haptic feedback with user interaction</string>
|
<string name="summary_on_haptic_feedback">Use haptic feedback with user interaction</string>
|
||||||
<string name="summary_off_haptic_feedback">Use haptic feedback with user interaction</string>
|
<string name="summary_off_haptic_feedback">Use haptic feedback with user interaction</string>
|
||||||
@@ -68,4 +64,11 @@
|
|||||||
<string name="summary_off_maps_compass">Compass is not displayed in Maps</string>
|
<string name="summary_off_maps_compass">Compass is not displayed in Maps</string>
|
||||||
|
|
||||||
<string name="development_settings_show_maps_compass_text">Show compass in Maps</string>
|
<string name="development_settings_show_maps_compass_text">Show compass in Maps</string>
|
||||||
|
|
||||||
|
<!-- Sound & display settings screen, compatibility mode check box label -->
|
||||||
|
<string name="compatibility_mode_title">Compatibility Mode</string>
|
||||||
|
<!-- Sound & display settings screen, compatibility mode option summary text when check box is selected -->
|
||||||
|
<string name="compatibility_mode_summary_on">Run older apps in Compatibility mode. This require rebooting. </string>
|
||||||
|
<!-- Sound & display settings screen, compatibility mode option summary text when check box is clear -->
|
||||||
|
<string name="compatibility_mode_summary_off">Run older apps in Compatibility mode. This require rebooting. </string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -72,12 +72,6 @@
|
|||||||
android:summaryOn="@string/summary_on_fancy_ime_animations"
|
android:summaryOn="@string/summary_on_fancy_ime_animations"
|
||||||
android:summaryOff="@string/summary_off_fancy_ime_animations"/>
|
android:summaryOff="@string/summary_off_fancy_ime_animations"/>
|
||||||
|
|
||||||
<CheckBoxPreference
|
|
||||||
android:key="fancy_rotation_animations"
|
|
||||||
android:title="@string/title_fancy_rotation_animations"
|
|
||||||
android:summaryOn="@string/summary_on_fancy_rotation_animations"
|
|
||||||
android:summaryOff="@string/summary_off_fancy_rotation_animations"/>
|
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="font_size"
|
android:key="font_size"
|
||||||
android:title="@string/title_font_size"
|
android:title="@string/title_font_size"
|
||||||
@@ -100,6 +94,12 @@
|
|||||||
android:summaryOn="@string/summary_on_haptic_feedback"
|
android:summaryOn="@string/summary_on_haptic_feedback"
|
||||||
android:summaryOff="@string/summary_off_haptic_feedback"/>
|
android:summaryOff="@string/summary_off_haptic_feedback"/>
|
||||||
|
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="compatibility_mode"
|
||||||
|
android:title="@string/compatibility_mode_title"
|
||||||
|
android:summaryOn="@string/compatibility_mode_summary_on"
|
||||||
|
android:summaryOff="@string/compatibility_mode_summary_off" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
|||||||
@@ -54,22 +54,22 @@ public class SpareParts extends PreferenceActivity
|
|||||||
private static final String WINDOW_ANIMATIONS_PREF = "window_animations";
|
private static final String WINDOW_ANIMATIONS_PREF = "window_animations";
|
||||||
private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations";
|
private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations";
|
||||||
private static final String FANCY_IME_ANIMATIONS_PREF = "fancy_ime_animations";
|
private static final String FANCY_IME_ANIMATIONS_PREF = "fancy_ime_animations";
|
||||||
private static final String FANCY_ROTATION_ANIMATIONS_PREF = "fancy_rotation_animations";
|
|
||||||
private static final String HAPTIC_FEEDBACK_PREF = "haptic_feedback";
|
private static final String HAPTIC_FEEDBACK_PREF = "haptic_feedback";
|
||||||
private static final String FONT_SIZE_PREF = "font_size";
|
private static final String FONT_SIZE_PREF = "font_size";
|
||||||
private static final String END_BUTTON_PREF = "end_button";
|
private static final String END_BUTTON_PREF = "end_button";
|
||||||
private static final String MAPS_COMPASS_PREF = "maps_compass";
|
private static final String MAPS_COMPASS_PREF = "maps_compass";
|
||||||
|
private static final String KEY_COMPATIBILITY_MODE = "compatibility_mode";
|
||||||
|
|
||||||
private final Configuration mCurConfig = new Configuration();
|
private final Configuration mCurConfig = new Configuration();
|
||||||
|
|
||||||
private ListPreference mWindowAnimationsPref;
|
private ListPreference mWindowAnimationsPref;
|
||||||
private ListPreference mTransitionAnimationsPref;
|
private ListPreference mTransitionAnimationsPref;
|
||||||
private CheckBoxPreference mFancyImeAnimationsPref;
|
private CheckBoxPreference mFancyImeAnimationsPref;
|
||||||
private CheckBoxPreference mFancyRotationAnimationsPref;
|
|
||||||
private CheckBoxPreference mHapticFeedbackPref;
|
private CheckBoxPreference mHapticFeedbackPref;
|
||||||
private ListPreference mFontSizePref;
|
private ListPreference mFontSizePref;
|
||||||
private ListPreference mEndButtonPref;
|
private ListPreference mEndButtonPref;
|
||||||
private CheckBoxPreference mShowMapsCompassPref;
|
private CheckBoxPreference mShowMapsCompassPref;
|
||||||
|
private CheckBoxPreference mCompatibilityMode;
|
||||||
|
|
||||||
private IWindowManager mWindowManager;
|
private IWindowManager mWindowManager;
|
||||||
|
|
||||||
@@ -120,13 +120,16 @@ public class SpareParts extends PreferenceActivity
|
|||||||
mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF);
|
mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF);
|
||||||
mTransitionAnimationsPref.setOnPreferenceChangeListener(this);
|
mTransitionAnimationsPref.setOnPreferenceChangeListener(this);
|
||||||
mFancyImeAnimationsPref = (CheckBoxPreference) prefSet.findPreference(FANCY_IME_ANIMATIONS_PREF);
|
mFancyImeAnimationsPref = (CheckBoxPreference) prefSet.findPreference(FANCY_IME_ANIMATIONS_PREF);
|
||||||
mFancyRotationAnimationsPref = (CheckBoxPreference) prefSet.findPreference(FANCY_ROTATION_ANIMATIONS_PREF);
|
|
||||||
mHapticFeedbackPref = (CheckBoxPreference) prefSet.findPreference(HAPTIC_FEEDBACK_PREF);
|
mHapticFeedbackPref = (CheckBoxPreference) prefSet.findPreference(HAPTIC_FEEDBACK_PREF);
|
||||||
mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF);
|
mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF);
|
||||||
mFontSizePref.setOnPreferenceChangeListener(this);
|
mFontSizePref.setOnPreferenceChangeListener(this);
|
||||||
mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF);
|
mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF);
|
||||||
mEndButtonPref.setOnPreferenceChangeListener(this);
|
mEndButtonPref.setOnPreferenceChangeListener(this);
|
||||||
mShowMapsCompassPref = (CheckBoxPreference) prefSet.findPreference(MAPS_COMPASS_PREF);
|
mShowMapsCompassPref = (CheckBoxPreference) prefSet.findPreference(MAPS_COMPASS_PREF);
|
||||||
|
mCompatibilityMode = (CheckBoxPreference) findPreference(KEY_COMPATIBILITY_MODE);
|
||||||
|
mCompatibilityMode.setPersistent(false);
|
||||||
|
mCompatibilityMode.setChecked(Settings.System.getInt(getContentResolver(),
|
||||||
|
Settings.System.COMPATIBILITY_MODE, 1) != 0);
|
||||||
|
|
||||||
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
|
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
|
||||||
|
|
||||||
@@ -146,9 +149,6 @@ public class SpareParts extends PreferenceActivity
|
|||||||
mFancyImeAnimationsPref.setChecked(Settings.System.getInt(
|
mFancyImeAnimationsPref.setChecked(Settings.System.getInt(
|
||||||
getContentResolver(),
|
getContentResolver(),
|
||||||
Settings.System.FANCY_IME_ANIMATIONS, 0) != 0);
|
Settings.System.FANCY_IME_ANIMATIONS, 0) != 0);
|
||||||
mFancyRotationAnimationsPref.setChecked(Settings.System.getInt(
|
|
||||||
getContentResolver(),
|
|
||||||
"fancy_rotation_anim", 0) != 0);
|
|
||||||
mHapticFeedbackPref.setChecked(Settings.System.getInt(
|
mHapticFeedbackPref.setChecked(Settings.System.getInt(
|
||||||
getContentResolver(),
|
getContentResolver(),
|
||||||
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0);
|
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0);
|
||||||
@@ -171,11 +171,21 @@ public class SpareParts extends PreferenceActivity
|
|||||||
} else if (preference == mEndButtonPref) {
|
} else if (preference == mEndButtonPref) {
|
||||||
writeEndButtonPreference(objValue);
|
writeEndButtonPreference(objValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// always let the preference setting proceed.
|
// always let the preference setting proceed.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
|
||||||
|
if (preference == mCompatibilityMode) {
|
||||||
|
Settings.System.putInt(getContentResolver(),
|
||||||
|
Settings.System.COMPATIBILITY_MODE,
|
||||||
|
mCompatibilityMode.isChecked() ? 1 : 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void writeAnimationPreference(int which, Object objValue) {
|
public void writeAnimationPreference(int which, Object objValue) {
|
||||||
try {
|
try {
|
||||||
float val = Float.parseFloat(objValue.toString());
|
float val = Float.parseFloat(objValue.toString());
|
||||||
@@ -247,10 +257,6 @@ public class SpareParts extends PreferenceActivity
|
|||||||
Settings.System.putInt(getContentResolver(),
|
Settings.System.putInt(getContentResolver(),
|
||||||
Settings.System.FANCY_IME_ANIMATIONS,
|
Settings.System.FANCY_IME_ANIMATIONS,
|
||||||
mFancyImeAnimationsPref.isChecked() ? 1 : 0);
|
mFancyImeAnimationsPref.isChecked() ? 1 : 0);
|
||||||
} else if (FANCY_ROTATION_ANIMATIONS_PREF.equals(key)) {
|
|
||||||
Settings.System.putInt(getContentResolver(),
|
|
||||||
"fancy_rotation_anim",
|
|
||||||
mFancyRotationAnimationsPref.isChecked() ? 1 : 0);
|
|
||||||
} else if (HAPTIC_FEEDBACK_PREF.equals(key)) {
|
} else if (HAPTIC_FEEDBACK_PREF.equals(key)) {
|
||||||
Settings.System.putInt(getContentResolver(),
|
Settings.System.putInt(getContentResolver(),
|
||||||
Settings.System.HAPTIC_FEEDBACK_ENABLED,
|
Settings.System.HAPTIC_FEEDBACK_ENABLED,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package com.android.commands.monkey;
|
|||||||
|
|
||||||
import android.app.ActivityManagerNative;
|
import android.app.ActivityManagerNative;
|
||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
import android.app.IActivityWatcher;
|
import android.app.IActivityController;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.IPackageManager;
|
import android.content.pm.IPackageManager;
|
||||||
@@ -88,10 +88,10 @@ public class Monkey {
|
|||||||
/** This is set when we would like to abort the running of the monkey. */
|
/** This is set when we would like to abort the running of the monkey. */
|
||||||
private boolean mAbort;
|
private boolean mAbort;
|
||||||
|
|
||||||
/** This is set by the ActivityWatcher thread to request collection of ANR trace files */
|
/** This is set by the ActivityController thread to request collection of ANR trace files */
|
||||||
private boolean mRequestAnrTraces = false;
|
private boolean mRequestAnrTraces = false;
|
||||||
|
|
||||||
/** This is set by the ActivityWatcher thread to request a "dumpsys meminfo" */
|
/** This is set by the ActivityController thread to request a "dumpsys meminfo" */
|
||||||
private boolean mRequestDumpsysMemInfo = false;
|
private boolean mRequestDumpsysMemInfo = false;
|
||||||
|
|
||||||
/** Kill the process after a timeout or crash. */
|
/** Kill the process after a timeout or crash. */
|
||||||
@@ -135,7 +135,7 @@ public class Monkey {
|
|||||||
/**
|
/**
|
||||||
* Monitor operations happening in the system.
|
* Monitor operations happening in the system.
|
||||||
*/
|
*/
|
||||||
private class ActivityWatcher extends IActivityWatcher.Stub {
|
private class ActivityController extends IActivityController.Stub {
|
||||||
public boolean activityStarting(Intent intent, String pkg) {
|
public boolean activityStarting(Intent intent, String pkg) {
|
||||||
boolean allow = checkEnteringPackage(pkg) || (DEBUG_ALLOW_ANY_STARTS != 0);
|
boolean allow = checkEnteringPackage(pkg) || (DEBUG_ALLOW_ANY_STARTS != 0);
|
||||||
if (mVerbose > 0) {
|
if (mVerbose > 0) {
|
||||||
@@ -246,7 +246,7 @@ public class Monkey {
|
|||||||
/**
|
/**
|
||||||
* Run "dumpsys meminfo"
|
* Run "dumpsys meminfo"
|
||||||
*
|
*
|
||||||
* NOTE: You cannot perform a dumpsys call from the ActivityWatcher callback, as it will
|
* NOTE: You cannot perform a dumpsys call from the ActivityController callback, as it will
|
||||||
* deadlock. This should only be called from the main loop of the monkey.
|
* deadlock. This should only be called from the main loop of the monkey.
|
||||||
*/
|
*/
|
||||||
private void reportDumpsysMemInfo() {
|
private void reportDumpsysMemInfo() {
|
||||||
@@ -425,7 +425,7 @@ public class Monkey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mAm.setActivityWatcher(null);
|
mAm.setActivityController(null);
|
||||||
mNetworkMonitor.unregister(mAm);
|
mNetworkMonitor.unregister(mAm);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// just in case this was latent (after mCount cycles), make sure
|
// just in case this was latent (after mCount cycles), make sure
|
||||||
@@ -608,7 +608,7 @@ public class Monkey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mAm.setActivityWatcher(new ActivityWatcher());
|
mAm.setActivityController(new ActivityController());
|
||||||
mNetworkMonitor.register(mAm);
|
mNetworkMonitor.register(mAm);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
System.err.println("** Failed talking with activity manager!");
|
System.err.println("** Failed talking with activity manager!");
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ compile-c-source = $(eval $(call ev-compile-c-source,$1,$(1:%.c=%.o)))
|
|||||||
# Usage : $(call compile-s-source,<srcfile>)
|
# Usage : $(call compile-s-source,<srcfile>)
|
||||||
# Rationale : Setup everything required to build a single Assembly source file
|
# Rationale : Setup everything required to build a single Assembly source file
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
compile-s-source = $(eval $(call ev-compile-s-source,$1,$(1:%.S=%.o)))
|
compile-s-source = $(eval $(call ev-compile-c-source,$1,$(1:%.S=%.o)))
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -30,5 +30,7 @@ current version
|
|||||||
|
|
||||||
- Add support for LOCAL_C_INCLUDES in Android.mk
|
- Add support for LOCAL_C_INCLUDES in Android.mk
|
||||||
|
|
||||||
|
- Fix compilation of assembler files (e.g. foo.S)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
android-1.5_r1 released.
|
android-1.5_r1 released.
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ function nothing() {}
|
|||||||
<li><a href="<?cs var:toroot ?>guide/instrumentation_testing.html">Instrumentation Testing</a></li>
|
<li><a href="<?cs var:toroot ?>guide/instrumentation_testing.html">Instrumentation Testing</a></li>
|
||||||
<li><a href="<?cs var:toroot ?>guide/debugging_gdb.html">Debugging with GDB</a></li>
|
<li><a href="<?cs var:toroot ?>guide/debugging_gdb.html">Debugging with GDB</a></li>
|
||||||
<li><a href="<?cs var:toroot ?>guide/debugging_native.html">Debugging Native Code</a></li>
|
<li><a href="<?cs var:toroot ?>guide/debugging_native.html">Debugging Native Code</a></li>
|
||||||
|
<li><a href="<?cs var:toroot ?>guide/tcpdump.html">Debugging with tcpdump</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|||||||
89
pdk/docs/guide/tcpdump.jd
Executable file
89
pdk/docs/guide/tcpdump.jd
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
page.title=Debugging with tcpdump and other tools
|
||||||
|
pdk.version=1.0
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<a name="toc"/>
|
||||||
|
<div style="padding:10px">
|
||||||
|
<a href="#installing">Installing tcpdump</a><BR>
|
||||||
|
<a href="#running">Running tcpdump</a><br/>
|
||||||
|
<a href="#other">Other network debugging commands</a><br/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a name="installing"></a>
|
||||||
|
<h3>Installing tcpdump</h3>
|
||||||
|
<h4>Pushing the binary to an existing device</h4>
|
||||||
|
<p>Download tcpdump from <a href="http://www.tcpdump.org/">http://www.tcpdump.org/</a>, then execute:</p>
|
||||||
|
<pre>
|
||||||
|
adb root
|
||||||
|
adb remount
|
||||||
|
adb push /wherever/you/put/tcpdump /system/xbin/tcpdump
|
||||||
|
adb shell chmod 6755 /data/local/tmp/tcpdump
|
||||||
|
</pre>
|
||||||
|
<h4>Including tcpdump in the build image</h4>
|
||||||
|
<p>If you are running your own build, execute:</p>
|
||||||
|
<pre>
|
||||||
|
mmm external/tcpdump # install the binary in out/.../system/xbin
|
||||||
|
make snod # build a new system.img that includes it
|
||||||
|
</pre>
|
||||||
|
<p>Flash the device as usual, for example, <code>fastboot flashball</code>.</p>
|
||||||
|
<p>If you want to build tcpdump by default, add <code>CUSTOM_TARGETS += tcpdump</code> to your <code>buildspec.mk</code>.</p>
|
||||||
|
<h3><a name="running"></a>Running tcpdump</h3>
|
||||||
|
<p>You need to have root access on your device. </p>
|
||||||
|
<h4>Batch mode capture</h4>
|
||||||
|
<p>The typical procedure is to capture packets to a file and then examine the file on the desktop, as illustrated below:</p>
|
||||||
|
<pre>
|
||||||
|
adb shell tcpdump -i any -p -s 0 -w /sdcard/capture.pcap
|
||||||
|
# "-i any": listen on any network interface
|
||||||
|
# "-p": disable promiscuous mode (doesn't work anyway)
|
||||||
|
# "-s 0": capture the entire packet
|
||||||
|
# "-w": write packets to a file (rather than printing to stdout)
|
||||||
|
|
||||||
|
... do whatever you want to capture, then ^C to stop it ...
|
||||||
|
|
||||||
|
adb pull /sdcard/capture.pcap .
|
||||||
|
sudo apt-get install wireshark # or ethereal, if you're still on dapper
|
||||||
|
wireshark capture.pcap # or ethereal
|
||||||
|
|
||||||
|
... look at your packets and be wise ...
|
||||||
|
</pre>
|
||||||
|
<p>You can run <code>tcpdump</code> in the background from an interactive shell or from Terminal. By default, <code>tcpdump</code> captures all traffic without filtering. If you prefer, add an expression like port 80 to the <code>tcpdump</code> command line.</p>
|
||||||
|
<h4>Real time packet monitoring</h4>
|
||||||
|
<p>Execute the following if you would like to watch packets go by rather than capturing them to a file (<code>-n</code> skips DNS lookups. <code>-s 0</code> captures the entire packet rather than just the header):</p>
|
||||||
|
<pre>
|
||||||
|
adb shell tcpdump -n -s 0
|
||||||
|
</pre>
|
||||||
|
<p>Typical <code>tcpdump</code> options apply. For example, if you want to see HTTP traffic:</p>
|
||||||
|
<pre>
|
||||||
|
adb shell tcpdump -X -n -s 0 port 80
|
||||||
|
</pre>
|
||||||
|
<p>You can also monitor packets with <code>wireshark</code> or <code>ethereal</code>, as shown below:</p>
|
||||||
|
<pre>
|
||||||
|
# In one shell, start tcpdump.
|
||||||
|
adb shell "tcpdump -n -s 0 -w - | nc -l -p 11233"
|
||||||
|
|
||||||
|
# In a separate shell, forward data and run ethereal.
|
||||||
|
adb forward tcp:11233 tcp:11233 && nc 127.0.0.1 11233 | ethereal -k -S -i -
|
||||||
|
</pre>
|
||||||
|
<p>Note that you can't restart capture via <code>ethereal</code>. If anything goes wrong, you will need to rerun both commands.</p>
|
||||||
|
<p>For more immediate output, add <code>-l</code> to the <code>tcpdump</code> command line, but this can cause <code>adb</code> to choke (it helps to use a nonzero argument for <code>-s</code> to limit the amount of data captured per packet; <code>-s 100</code> is sufficient if you just want to see headers).</p>
|
||||||
|
<h4>Disabling encryption</h4>
|
||||||
|
<p>If your service runs over <code>https</code>, <code>tcpdump</code> is of limited use. In this case, you can rewrite some service URLs to use <code>http</code>, for example:</p>
|
||||||
|
<pre>
|
||||||
|
vendor/google/tools/override-gservices url:calendar_sync_https_proxy \
|
||||||
|
https://www.google.com/calendar rewrite http://android.clients.google.com/proxy/calendar
|
||||||
|
</pre>
|
||||||
|
<h3><a name="other"></a>Other network debugging commands</h3>
|
||||||
|
<h4>On the device:</h4>
|
||||||
|
<ul>
|
||||||
|
<li><code>ifconfig interface</code>: note that unlike Linux, you need to give <code>ifconfig</code> an argument</li>
|
||||||
|
<li><code>netcfg</code>: lists interfaces and IP addresses</li>
|
||||||
|
<li><code>iftop</code>: like top for network</li>
|
||||||
|
<li><code>route</code>: examine the routing table</li>
|
||||||
|
<li><code>netstat</code>: see active network connections</li>
|
||||||
|
<li><code>nc</code>: <code>netcat</code> connection utility</li>
|
||||||
|
</ul>
|
||||||
|
<h4>On the desktop:</h4>
|
||||||
|
<ul>
|
||||||
|
<li> <code>curl</code>: fetch URLs directly to emulate device requests</li>
|
||||||
|
</ul>
|
||||||
60
testrunner/android_manifest.py
Normal file
60
testrunner/android_manifest.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/python2.4
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Copyright 2009, 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.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""In memory representation of AndroidManifest.xml file.
|
||||||
|
|
||||||
|
Specification of AndroidManifest.xml can be found at
|
||||||
|
http://developer.android.com/guide/topics/manifest/manifest-intro.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
# python imports
|
||||||
|
import xml.dom.minidom
|
||||||
|
import xml.parsers
|
||||||
|
|
||||||
|
|
||||||
|
class AndroidManifest(object):
|
||||||
|
"""In memory representation of AndroidManifest.xml file."""
|
||||||
|
|
||||||
|
FILENAME = "AndroidManifest.xml"
|
||||||
|
|
||||||
|
def __init__(self, app_path=None):
|
||||||
|
if app_path:
|
||||||
|
self.ParseManifest(app_path)
|
||||||
|
|
||||||
|
def GetPackageName(self):
|
||||||
|
"""Retrieve package name defined at <manifest package="...">.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Package name if defined, otherwise None
|
||||||
|
"""
|
||||||
|
manifests = self._dom.getElementsByTagName("manifest")
|
||||||
|
if not manifests or not manifests[0].getAttribute("package"):
|
||||||
|
return None
|
||||||
|
return manifests[0].getAttribute("package")
|
||||||
|
|
||||||
|
def ParseManifest(self, app_path):
|
||||||
|
"""Parse AndroidManifest.xml at the specified path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app_path: path to folder containing AndroidManifest.xml
|
||||||
|
Raises:
|
||||||
|
IOError: AndroidManifest.xml cannot be found at given path, or cannot be
|
||||||
|
opened for reading
|
||||||
|
"""
|
||||||
|
self.app_path = app_path.rstrip("/")
|
||||||
|
self.manifest_path = "%s/%s" % (self.app_path, self.FILENAME)
|
||||||
|
self._dom = xml.dom.minidom.parse(self.manifest_path)
|
||||||
96
testrunner/android_mk.py
Normal file
96
testrunner/android_mk.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/python2.4
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Copyright 2009, 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.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""In memory representation of Android.mk file.
|
||||||
|
|
||||||
|
Specifications for Android.mk can be found at
|
||||||
|
development/ndk/docs/ANDROID-MK.txt
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from sets import Set
|
||||||
|
|
||||||
|
|
||||||
|
class AndroidMK(object):
|
||||||
|
"""In memory representation of Android.mk file."""
|
||||||
|
|
||||||
|
_RE_INCLUDE = re.compile(r'include\s+\$\((.+)\)')
|
||||||
|
_VAR_DELIMITER = ":="
|
||||||
|
FILENAME = "Android.mk"
|
||||||
|
CERTIFICATE = "LOCAL_CERTIFICATE"
|
||||||
|
PACKAGE_NAME = "LOCAL_PACKAGE_NAME"
|
||||||
|
|
||||||
|
def __init__(self, app_path=None):
|
||||||
|
self._includes = Set() # variables included in makefile
|
||||||
|
self._variables = {} # variables defined in makefile
|
||||||
|
|
||||||
|
if app_path:
|
||||||
|
self.ParseMK(app_path)
|
||||||
|
|
||||||
|
def _ProcessMKLine(self, line):
|
||||||
|
"""Add a variable definition or include.
|
||||||
|
|
||||||
|
Ignores unrecognized lines.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
line: line of text from makefile
|
||||||
|
"""
|
||||||
|
m = self._RE_INCLUDE.match(line)
|
||||||
|
if m:
|
||||||
|
self._includes.add(m.group(1))
|
||||||
|
else:
|
||||||
|
parts = line.split(self._VAR_DELIMITER)
|
||||||
|
if len(parts) > 1:
|
||||||
|
self._variables[parts[0].strip()] = parts[1].strip()
|
||||||
|
|
||||||
|
def GetVariable(self, identifier):
|
||||||
|
"""Retrieve makefile variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
identifier: name of variable to retrieve
|
||||||
|
Returns:
|
||||||
|
value of specified identifier, None if identifier not found in makefile
|
||||||
|
"""
|
||||||
|
# use dict.get(x) rather than dict[x] to avoid KeyError exception,
|
||||||
|
# so None is returned if identifier not found
|
||||||
|
return self._variables.get(identifier, None)
|
||||||
|
|
||||||
|
def HasInclude(self, identifier):
|
||||||
|
"""Check variable is included in makefile.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
identifer: name of variable to check
|
||||||
|
Returns:
|
||||||
|
True if identifer is included in makefile, otherwise False
|
||||||
|
"""
|
||||||
|
return identifier in self._includes
|
||||||
|
|
||||||
|
def ParseMK(self, app_path):
|
||||||
|
"""Parse Android.mk at the specified path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app_path: path to folder containing Android.mk
|
||||||
|
Raises:
|
||||||
|
IOError: Android.mk cannot be found at given path, or cannot be opened
|
||||||
|
for reading
|
||||||
|
"""
|
||||||
|
self.app_path = app_path.rstrip("/")
|
||||||
|
self.mk_path = "%s/%s" % (self.app_path, self.FILENAME)
|
||||||
|
mk = open(self.mk_path)
|
||||||
|
for line in mk:
|
||||||
|
self._ProcessMKLine(line)
|
||||||
|
mk.close()
|
||||||
245
testrunner/create_test.py
Executable file
245
testrunner/create_test.py
Executable file
@@ -0,0 +1,245 @@
|
|||||||
|
#!/usr/bin/python2.4
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Copyright 2009, 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.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Utility to create Android project files for tests."""
|
||||||
|
|
||||||
|
# python imports
|
||||||
|
import datetime
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
import android_mk
|
||||||
|
import android_manifest
|
||||||
|
|
||||||
|
|
||||||
|
class TestsConsts(object):
|
||||||
|
"""Constants for test Android.mk and AndroidManifest.xml creation."""
|
||||||
|
|
||||||
|
MK_BUILD_INCLUDE = "call all-makefiles-under,$(LOCAL_PATH)"
|
||||||
|
MK_BUILD_STRING = "\ninclude $(%s)\n" % MK_BUILD_INCLUDE
|
||||||
|
TEST_MANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) $YEAR 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.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="$PACKAGE_NAME.tests">
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
||||||
|
android:targetPackage="$PACKAGE_NAME"
|
||||||
|
android:label="Tests for $MODULE_NAME">
|
||||||
|
</instrumentation>
|
||||||
|
</manifest>
|
||||||
|
"""
|
||||||
|
TEST_MK_TEMPLATE = """LOCAL_PATH := $$(call my-dir)
|
||||||
|
include $$(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
|
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $$(call all-java-files-under, src)
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := ${MODULE_NAME}Tests${CERTIFICATE}
|
||||||
|
|
||||||
|
LOCAL_INSTRUMENTATION_FOR := ${MODULE_NAME}
|
||||||
|
|
||||||
|
LOCAL_SDK_VERSION := current
|
||||||
|
|
||||||
|
include $$(BUILD_PACKAGE)
|
||||||
|
"""
|
||||||
|
TESTS_FOLDER = "tests"
|
||||||
|
|
||||||
|
|
||||||
|
def _GenerateTestManifest(manifest, module_name, mapping=None):
|
||||||
|
"""Create and populate tests/AndroidManifest.xml with variable values from
|
||||||
|
Android.mk and AndroidManifest.xml.
|
||||||
|
|
||||||
|
Does nothing if tests/AndroidManifest.xml already exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
manifest: AndroidManifest object for application manifest
|
||||||
|
module_name: module name used for labelling
|
||||||
|
mapping: optional user defined mapping of variable values, replaces values
|
||||||
|
extracted from AndroidManifest.xml
|
||||||
|
Raises:
|
||||||
|
IOError: tests/AndroidManifest.xml cannot be opened for writing
|
||||||
|
"""
|
||||||
|
# skip if file already exists
|
||||||
|
tests_path = "%s/%s" % (manifest.app_path, TestsConsts.TESTS_FOLDER)
|
||||||
|
tests_manifest_path = "%s/%s" % (tests_path, manifest.FILENAME)
|
||||||
|
if os.path.exists(tests_manifest_path):
|
||||||
|
_PrintMessage("%s already exists, not overwritten" % tests_manifest_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not mapping:
|
||||||
|
package_name = manifest.GetPackageName()
|
||||||
|
mapping = {"PACKAGE_NAME":package_name, "MODULE_NAME":module_name,
|
||||||
|
"YEAR":datetime.date.today().year}
|
||||||
|
output = string.Template(TestsConsts.TEST_MANIFEST_TEMPLATE).substitute(mapping)
|
||||||
|
|
||||||
|
# create tests folder if not existent
|
||||||
|
if not os.path.exists(tests_path):
|
||||||
|
os.mkdir(tests_path)
|
||||||
|
|
||||||
|
# write tests/AndroidManifest.xml
|
||||||
|
tests_manifest = open(tests_manifest_path, mode="w")
|
||||||
|
tests_manifest.write(output)
|
||||||
|
tests_manifest.close()
|
||||||
|
_PrintMessage("Created %s" % tests_manifest_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _GenerateTestMK(mk, mapping=None):
|
||||||
|
"""Create and populate tests/Android.mk with variable values from Android.mk.
|
||||||
|
|
||||||
|
Does nothing if tests/Android.mk already exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mk: AndroidMK object for application makefile
|
||||||
|
mapping: optional user defined mapping of variable values, replaces
|
||||||
|
values stored in mk
|
||||||
|
Raises:
|
||||||
|
IOError: tests/Android.mk cannot be opened for writing
|
||||||
|
"""
|
||||||
|
# skip if file already exists
|
||||||
|
tests_path = "%s/%s" % (mk.app_path, TestsConsts.TESTS_FOLDER)
|
||||||
|
tests_mk_path = "%s/%s" % (tests_path, mk.FILENAME)
|
||||||
|
if os.path.exists(tests_mk_path):
|
||||||
|
_PrintMessage("%s already exists, not overwritten" % tests_mk_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
# append test build if not existent in makefile
|
||||||
|
if not mk.HasInclude(TestsConsts.MK_BUILD_INCLUDE):
|
||||||
|
mk_path = "%s/%s" % (mk.app_path, mk.FILENAME)
|
||||||
|
mk_file = open(mk_path, mode="a")
|
||||||
|
mk_file.write(TestsConsts.MK_BUILD_STRING)
|
||||||
|
mk_file.close()
|
||||||
|
|
||||||
|
# construct tests/Android.mk
|
||||||
|
# include certificate definition if existent in makefile
|
||||||
|
certificate = mk.GetVariable(mk.CERTIFICATE)
|
||||||
|
if certificate:
|
||||||
|
cert_definition = ("\n%s := %s" % (mk.CERTIFICATE, certificate))
|
||||||
|
else:
|
||||||
|
cert_definition = ""
|
||||||
|
if not mapping:
|
||||||
|
module_name = mk.GetVariable(mk.PACKAGE_NAME)
|
||||||
|
mapping = {"MODULE_NAME":module_name, "CERTIFICATE":cert_definition}
|
||||||
|
output = string.Template(TestsConsts.TEST_MK_TEMPLATE).substitute(mapping)
|
||||||
|
|
||||||
|
# create tests folder if not existent
|
||||||
|
if not os.path.exists(tests_path):
|
||||||
|
os.mkdir(tests_path)
|
||||||
|
|
||||||
|
# write tests/Android.mk to disk
|
||||||
|
tests_mk = open(tests_mk_path, mode="w")
|
||||||
|
tests_mk.write(output)
|
||||||
|
tests_mk.close()
|
||||||
|
_PrintMessage("Created %s" % tests_mk_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _ParseArgs(argv):
|
||||||
|
"""Parse the command line arguments.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
argv: the list of command line arguments
|
||||||
|
Returns:
|
||||||
|
a tuple of options and individual command line arguments.
|
||||||
|
"""
|
||||||
|
parser = optparse.OptionParser(usage="%s <app_path>" % sys.argv[0])
|
||||||
|
options, args = parser.parse_args(argv)
|
||||||
|
if len(args) < 1:
|
||||||
|
_PrintError("Error: Incorrect syntax")
|
||||||
|
parser.print_usage()
|
||||||
|
sys.exit()
|
||||||
|
return (options, args)
|
||||||
|
|
||||||
|
|
||||||
|
def _PrintMessage(msg):
|
||||||
|
print >> sys.stdout, msg
|
||||||
|
|
||||||
|
|
||||||
|
def _PrintError(msg):
|
||||||
|
print >> sys.stderr, msg
|
||||||
|
|
||||||
|
|
||||||
|
def _ValidateInputFiles(mk, manifest):
|
||||||
|
"""Verify that required variables are defined in input files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mk: AndroidMK object for application makefile
|
||||||
|
manifest: AndroidManifest object for application manifest
|
||||||
|
Raises:
|
||||||
|
RuntimeError: mk does not define LOCAL_PACKAGE_NAME or
|
||||||
|
manifest does not define package variable
|
||||||
|
"""
|
||||||
|
module_name = mk.GetVariable(mk.PACKAGE_NAME)
|
||||||
|
if not module_name:
|
||||||
|
raise RuntimeError("Variable %s missing from %s" %
|
||||||
|
(mk.PACKAGE_NAME, mk.FILENAME))
|
||||||
|
|
||||||
|
package_name = manifest.GetPackageName()
|
||||||
|
if not package_name:
|
||||||
|
raise RuntimeError("Variable package missing from %s" % manifest.FILENAME)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
options, args = _ParseArgs(argv)
|
||||||
|
app_path = args[0];
|
||||||
|
|
||||||
|
if not os.path.exists(app_path):
|
||||||
|
_PrintError("Error: Application path %s not found" % app_path)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
try:
|
||||||
|
mk = android_mk.AndroidMK(app_path=app_path)
|
||||||
|
manifest = android_manifest.AndroidManifest(app_path=app_path)
|
||||||
|
_ValidateInputFiles(mk, manifest)
|
||||||
|
|
||||||
|
module_name = mk.GetVariable(mk.PACKAGE_NAME)
|
||||||
|
_GenerateTestMK(mk)
|
||||||
|
_GenerateTestManifest(manifest, module_name)
|
||||||
|
except Exception, e:
|
||||||
|
_PrintError("Error: %s" % e)
|
||||||
|
_PrintError("Error encountered, script aborted")
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
src_path = app_path + "/tests/src"
|
||||||
|
if not os.path.exists(src_path):
|
||||||
|
os.mkdir(src_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(sys.argv[1:])
|
||||||
@@ -88,6 +88,13 @@ See test_defs.xsd for more information.
|
|||||||
class="com.android.unit_tests.activity.ActivityTests"
|
class="com.android.unit_tests.activity.ActivityTests"
|
||||||
coverage_target="framework" />
|
coverage_target="framework" />
|
||||||
|
|
||||||
|
<test name="vpntests"
|
||||||
|
build_path="frameworks/base/tests/AndroidTests"
|
||||||
|
package="com.android.unit_tests"
|
||||||
|
class="com.android.unit_tests.VpnTest"
|
||||||
|
coverage_target="framework"
|
||||||
|
continuous="true" />
|
||||||
|
|
||||||
<!-- obsolete?
|
<!-- obsolete?
|
||||||
<test name="deadlock"
|
<test name="deadlock"
|
||||||
build_path="frameworks/base/tests/Deadlock"
|
build_path="frameworks/base/tests/Deadlock"
|
||||||
@@ -298,11 +305,11 @@ See test_defs.xsd for more information.
|
|||||||
coverage_target="Calendar"
|
coverage_target="Calendar"
|
||||||
continuous="true" />
|
continuous="true" />
|
||||||
|
|
||||||
|
<!-- Make continuous = "true" once the bug 1966269 is fixed -->
|
||||||
<test name="calprov"
|
<test name="calprov"
|
||||||
build_path="packages/providers/CalendarProvider/tests"
|
build_path="packages/providers/CalendarProvider/tests"
|
||||||
package="com.android.providers.calendar.tests"
|
package="com.android.providers.calendar.tests"
|
||||||
coverage_target="CalendarProvider"
|
coverage_target="CalendarProvider" />
|
||||||
continuous="true" />
|
|
||||||
|
|
||||||
<test name="camerastress"
|
<test name="camerastress"
|
||||||
build_path="packages/apps/Camera"
|
build_path="packages/apps/Camera"
|
||||||
@@ -460,10 +467,10 @@ See test_defs.xsd for more information.
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- host java tests -->
|
<!-- host java tests -->
|
||||||
<test-host name="cts-appinstall"
|
<test-host name="cts-appsecurity"
|
||||||
build_path="cts/tests/install-tests"
|
build_path="cts/tests/appsecurity-tests"
|
||||||
class="com.android.cts.install.InstallTests"
|
class="com.android.cts.appsecurity.AppSecurityTests"
|
||||||
jar_name="CtsInstallTests.jar"
|
jar_name="CtsAppSecurityTests.jar"
|
||||||
cts="true" />
|
cts="true" />
|
||||||
|
|
||||||
</test-definitions>
|
</test-definitions>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.ant;
|
|||||||
|
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.ISdkLog;
|
import com.android.sdklib.ISdkLog;
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
|
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties;
|
import com.android.sdklib.internal.project.ProjectProperties;
|
||||||
@@ -27,10 +28,20 @@ import org.apache.tools.ant.Project;
|
|||||||
import org.apache.tools.ant.taskdefs.ImportTask;
|
import org.apache.tools.ant.taskdefs.ImportTask;
|
||||||
import org.apache.tools.ant.types.Path;
|
import org.apache.tools.ant.types.Path;
|
||||||
import org.apache.tools.ant.types.Path.PathElement;
|
import org.apache.tools.ant.types.Path.PathElement;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.namespace.NamespaceContext;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup/Import Ant task. This task accomplishes:
|
* Setup/Import Ant task. This task accomplishes:
|
||||||
@@ -130,9 +141,15 @@ public final class SetupTask extends ImportTask {
|
|||||||
System.out.println("Project Target: " + androidTarget.getName());
|
System.out.println("Project Target: " + androidTarget.getName());
|
||||||
if (androidTarget.isPlatform() == false) {
|
if (androidTarget.isPlatform() == false) {
|
||||||
System.out.println("Vendor: " + androidTarget.getVendor());
|
System.out.println("Vendor: " + androidTarget.getVendor());
|
||||||
System.out.println("Platform Version: " + androidTarget.getApiVersionName());
|
System.out.println("Platform Version: " + androidTarget.getVersionName());
|
||||||
|
}
|
||||||
|
System.out.println("API level: " + androidTarget.getVersion().getApiString());
|
||||||
|
|
||||||
|
// if needed check the manifest so that it matches the target
|
||||||
|
if (androidTarget.getVersion().isPreview()) {
|
||||||
|
// for preview, the manifest minSdkVersion node *must* match the target codename
|
||||||
|
checkManifest(antProject, androidTarget.getVersion().getCodename());
|
||||||
}
|
}
|
||||||
System.out.println("API level: " + androidTarget.getApiVersionNumber());
|
|
||||||
|
|
||||||
// sets up the properties to find android.jar/framework.aidl/target tools
|
// sets up the properties to find android.jar/framework.aidl/target tools
|
||||||
String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);
|
String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);
|
||||||
@@ -205,4 +222,47 @@ public final class SetupTask extends ImportTask {
|
|||||||
public void setImport(boolean value) {
|
public void setImport(boolean value) {
|
||||||
mDoImport = value;
|
mDoImport = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkManifest(Project antProject, String codename) {
|
||||||
|
try {
|
||||||
|
File manifest = new File(antProject.getBaseDir(), "AndroidManifest.xml");
|
||||||
|
|
||||||
|
XPath xPath = XPathFactory.newInstance().newXPath();
|
||||||
|
xPath.setNamespaceContext(new NamespaceContext() {
|
||||||
|
public String getNamespaceURI(String prefix) {
|
||||||
|
if (prefix != null) {
|
||||||
|
if (prefix.equals("android")) {
|
||||||
|
return SdkConstants.NS_RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return XMLConstants.NULL_NS_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix(String namespaceURI) {
|
||||||
|
// This isn't necessary for our use.
|
||||||
|
assert false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator getPrefixes(String namespaceURI) {
|
||||||
|
// This isn't necessary for our use.
|
||||||
|
assert false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
String value = xPath.evaluate("/manifest/uses-sdk/@android:minSdkVersion",
|
||||||
|
new InputSource(new FileInputStream(manifest)));
|
||||||
|
|
||||||
|
if (codename.equals(value) == false) {
|
||||||
|
throw new BuildException(String.format("For '%1$s' SDK Preview, application manifest must declare minSdkVersion to '%1$s'",
|
||||||
|
codename));
|
||||||
|
}
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new BuildException(e);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new BuildException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ import java.util.Map;
|
|||||||
public interface IDevice {
|
public interface IDevice {
|
||||||
|
|
||||||
public final static String PROP_BUILD_VERSION = "ro.build.version.release";
|
public final static String PROP_BUILD_VERSION = "ro.build.version.release";
|
||||||
public final static String PROP_BUILD_VERSION_NUMBER = "ro.build.version.sdk";
|
public final static String PROP_BUILD_API_LEVEL = "ro.build.version.sdk";
|
||||||
|
public final static String PROP_BUILD_CODENAME = "ro.build.version.codename";
|
||||||
|
|
||||||
public final static String PROP_DEBUGGABLE = "ro.debuggable";
|
public final static String PROP_DEBUGGABLE = "ro.debuggable";
|
||||||
|
|
||||||
/** Serial number of the first connected emulator. */
|
/** Serial number of the first connected emulator. */
|
||||||
public final static String FIRST_EMULATOR_SN = "emulator-5554"; //$NON-NLS-1$
|
public final static String FIRST_EMULATOR_SN = "emulator-5554"; //$NON-NLS-1$
|
||||||
/** Device change bit mask: {@link DeviceState} change. */
|
/** Device change bit mask: {@link DeviceState} change. */
|
||||||
@@ -39,6 +42,9 @@ public interface IDevice {
|
|||||||
/** Device change bit mask: build info change. */
|
/** Device change bit mask: build info change. */
|
||||||
public static final int CHANGE_BUILD_INFO = 0x0004;
|
public static final int CHANGE_BUILD_INFO = 0x0004;
|
||||||
|
|
||||||
|
/** @deprecated Use {@link #PROP_BUILD_API_LEVEL}. */
|
||||||
|
public final static String PROP_BUILD_VERSION_NUMBER = PROP_BUILD_API_LEVEL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state of a device.
|
* The state of a device.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -666,6 +666,12 @@
|
|||||||
id="com.android.ide.eclipse.adt.refactoring.extract.string"
|
id="com.android.ide.eclipse.adt.refactoring.extract.string"
|
||||||
name="Extract Android String">
|
name="Extract Android String">
|
||||||
</command>
|
</command>
|
||||||
|
<keyBinding
|
||||||
|
commandId="com.android.ide.eclipse.adt.refactoring.extract.string"
|
||||||
|
contextId="org.eclipse.ui.globalScope"
|
||||||
|
keyConfigurationId="org.eclipse.ui.defaultAcceleratorConfiguration"
|
||||||
|
keySequence="M3+M2+A S">
|
||||||
|
</keyBinding>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.ltk.core.refactoring.refactoringContributions">
|
point="org.eclipse.ltk.core.refactoring.refactoringContributions">
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
|
|||||||
import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig;
|
import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig;
|
||||||
import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener;
|
import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener;
|
||||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
|
|
||||||
@@ -225,7 +226,7 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
|
|
||||||
PreCompilerDeltaVisitor dv = null;
|
PreCompilerDeltaVisitor dv = null;
|
||||||
String javaPackage = null;
|
String javaPackage = null;
|
||||||
int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
|
String minSdkVersion = null;
|
||||||
|
|
||||||
if (kind == FULL_BUILD) {
|
if (kind == FULL_BUILD) {
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
||||||
@@ -315,16 +316,62 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
minSdkVersion = parser.getApiLevelRequirement();
|
minSdkVersion = parser.getApiLevelRequirement();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK &&
|
if (minSdkVersion != null) {
|
||||||
minSdkVersion < projectTarget.getApiVersionNumber()) {
|
int minSdkValue = -1;
|
||||||
// check it against the target api level
|
try {
|
||||||
|
minSdkValue = Integer.parseInt(minSdkVersion);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// it's ok, it means minSdkVersion contains a (hopefully) valid codename.
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidVersion projectVersion = projectTarget.getVersion();
|
||||||
|
|
||||||
|
if (minSdkValue != -1) {
|
||||||
|
String codename = projectVersion.getCodename();
|
||||||
|
if (codename != null) {
|
||||||
|
// integer minSdk when the target is a preview => fatal error
|
||||||
|
String msg = String.format(
|
||||||
|
"Platform %1$s is a preview and requires appication manifests to set %2$s to '%3$s'",
|
||||||
|
codename, AndroidManifestParser.ATTRIBUTE_MIN_SDK_VERSION,
|
||||||
|
codename);
|
||||||
|
AdtPlugin.printErrorToConsole(project, msg);
|
||||||
|
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
|
||||||
|
IMarker.SEVERITY_ERROR);
|
||||||
|
stopBuild(msg);
|
||||||
|
} else if (minSdkValue < projectVersion.getApiLevel()) {
|
||||||
|
// integer minSdk is not high enough for the target => warning
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"Manifest min SDK version (%1$d) is lower than project target API level (%2$d)",
|
"Manifest min SDK version (%1$d) is lower than project target API level (%2$d)",
|
||||||
minSdkVersion, projectTarget.getApiVersionNumber());
|
minSdkVersion, projectVersion.getApiLevel());
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
||||||
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
|
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
|
||||||
IMarker.SEVERITY_WARNING);
|
IMarker.SEVERITY_WARNING);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// looks like the min sdk is a codename, check it matches the codename
|
||||||
|
// of the platform
|
||||||
|
String codename = projectVersion.getCodename();
|
||||||
|
if (codename == null) {
|
||||||
|
// platform is not a preview => fatal error
|
||||||
|
String msg = String.format(
|
||||||
|
"Manifest attribute '%1$s' is set to '%2$s'. Integer is expected.",
|
||||||
|
AndroidManifestParser.ATTRIBUTE_MIN_SDK_VERSION, codename);
|
||||||
|
AdtPlugin.printErrorToConsole(project, msg);
|
||||||
|
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
|
||||||
|
IMarker.SEVERITY_ERROR);
|
||||||
|
stopBuild(msg);
|
||||||
|
} else if (codename.equals(minSdkVersion) == false) {
|
||||||
|
// platform and manifest codenames don't match => fatal error.
|
||||||
|
String msg = String.format(
|
||||||
|
"Value of manifest attribute '%1$s' does not match platform codename '%2$s'",
|
||||||
|
AndroidManifestParser.ATTRIBUTE_MIN_SDK_VERSION, codename);
|
||||||
|
AdtPlugin.printErrorToConsole(project, msg);
|
||||||
|
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
|
||||||
|
IMarker.SEVERITY_ERROR);
|
||||||
|
stopBuild(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (javaPackage == null || javaPackage.length() == 0) {
|
if (javaPackage == null || javaPackage.length() == 0) {
|
||||||
// looks like the AndroidManifest file isn't valid.
|
// looks like the AndroidManifest file isn't valid.
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
|
|||||||
/** Application Package, gathered from the parsing of the manifest */
|
/** Application Package, gathered from the parsing of the manifest */
|
||||||
private String mJavaPackage = null;
|
private String mJavaPackage = null;
|
||||||
/** minSDKVersion attribute value, gathered from the parsing of the manifest */
|
/** minSDKVersion attribute value, gathered from the parsing of the manifest */
|
||||||
private int mMinSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
|
private String mMinSdkVersion = null;
|
||||||
|
|
||||||
// Internal usage fields.
|
// Internal usage fields.
|
||||||
/**
|
/**
|
||||||
@@ -162,16 +162,16 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
|
|||||||
/**
|
/**
|
||||||
* Returns the minSDkVersion attribute from the manifest if it was checked/parsed.
|
* Returns the minSDkVersion attribute from the manifest if it was checked/parsed.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This can return {@link AndroidManifestParser#INVALID_MIN_SDK} in two cases:
|
* This can return null in two cases:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The manifest was not part of the resource change delta, and the manifest was
|
* <li>The manifest was not part of the resource change delta, and the manifest was
|
||||||
* not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li>
|
* not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li>
|
||||||
* <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>),
|
* <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>),
|
||||||
* but the package declaration is missing</li>
|
* but the package declaration is missing</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* @return the minSdkVersion or {@link AndroidManifestParser#INVALID_MIN_SDK}.
|
* @return the minSdkVersion or null.
|
||||||
*/
|
*/
|
||||||
public int getMinSdkVersion() {
|
public String getMinSdkVersion() {
|
||||||
return mMinSdkVersion;
|
return mMinSdkVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,12 +310,12 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
|
|||||||
Object[] choices = null;
|
Object[] choices = null;
|
||||||
if (attrInfo.isInValue) {
|
if (attrInfo.isInValue) {
|
||||||
// Editing an attribute's value... Get the attribute name and then the
|
// Editing an attribute's value... Get the attribute name and then the
|
||||||
// possible choice for the tuple(parent,attribute)
|
// possible choices for the tuple(parent,attribute)
|
||||||
String value = attrInfo.value;
|
String value = attrInfo.value;
|
||||||
if (value.startsWith("'") || value.startsWith("\"")) { //$NON-NLS-1$ //$NON-NLS-2$
|
if (value.startsWith("'") || value.startsWith("\"")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
value = value.substring(1);
|
value = value.substring(1);
|
||||||
// The prefix that was found at the beginning only scan for characters
|
// The prefix that was found at the beginning only scan for characters
|
||||||
// valid of tag name. We now know the real prefix for this attribute's
|
// valid for tag name. We now know the real prefix for this attribute's
|
||||||
// value, which is needed to generate the completion choices below.
|
// value, which is needed to generate the completion choices below.
|
||||||
attrInfo.correctedPrefix = value;
|
attrInfo.correctedPrefix = value;
|
||||||
} else {
|
} else {
|
||||||
@@ -772,7 +772,7 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
|
|||||||
IDescriptorProvider descriptorProvider = data.getDescriptorProvider(mDescriptorId);
|
IDescriptorProvider descriptorProvider = data.getDescriptorProvider(mDescriptorId);
|
||||||
|
|
||||||
if (descriptorProvider != null) {
|
if (descriptorProvider != null) {
|
||||||
mRootDescriptor = new ElementDescriptor("",
|
mRootDescriptor = new ElementDescriptor("", //$NON-NLS-1$
|
||||||
descriptorProvider.getRootElementDescriptors());
|
descriptorProvider.getRootElementDescriptors());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -565,6 +565,11 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
|
|||||||
* Callers <em>must</em> call model.releaseFromRead() when done, typically
|
* Callers <em>must</em> call model.releaseFromRead() when done, typically
|
||||||
* in a try..finally clause.
|
* in a try..finally clause.
|
||||||
*
|
*
|
||||||
|
* Portability note: this uses getModelManager which is part of wst.sse.core; however
|
||||||
|
* the interface returned is part of wst.sse.core.internal.provisional so we can
|
||||||
|
* expect it to change in a distant future if they start cleaning their codebase,
|
||||||
|
* however unlikely that is.
|
||||||
|
*
|
||||||
* @return The model for the XML document or null if cannot be obtained from the editor
|
* @return The model for the XML document or null if cannot be obtained from the editor
|
||||||
*/
|
*/
|
||||||
public final IStructuredModel getModelForRead() {
|
public final IStructuredModel getModelForRead() {
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import org.eclipse.swt.widgets.Composite;
|
|||||||
*/
|
*/
|
||||||
public final class ReferenceAttributeDescriptor extends TextAttributeDescriptor {
|
public final class ReferenceAttributeDescriptor extends TextAttributeDescriptor {
|
||||||
|
|
||||||
|
/** The {@link ResourceType} that this reference attribute can accept. It can be null,
|
||||||
|
* in which case any reference type can be used. */
|
||||||
private ResourceType mResourceType;
|
private ResourceType mResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,6 +68,12 @@ public final class ReferenceAttributeDescriptor extends TextAttributeDescriptor
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the {@link ResourceType} that this reference attribute can accept.
|
||||||
|
* It can be null, in which case any reference type can be used. */
|
||||||
|
public ResourceType getResourceType() {
|
||||||
|
return mResourceType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A new {@link UiResourceAttributeNode} linked to this reference descriptor.
|
* @return A new {@link UiResourceAttributeNode} linked to this reference descriptor.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
|
|||||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.adt.internal.wizards.actions.AvdManagerAction;
|
import com.android.ide.eclipse.adt.internal.wizards.actions.AvdManagerAction;
|
||||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.NullSdkLog;
|
import com.android.sdklib.NullSdkLog;
|
||||||
import com.android.sdklib.SdkManager;
|
|
||||||
import com.android.sdklib.internal.avd.AvdManager;
|
import com.android.sdklib.internal.avd.AvdManager;
|
||||||
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
||||||
|
|
||||||
@@ -274,16 +274,16 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
* @param packageName the Android package name of the app
|
* @param packageName the Android package name of the app
|
||||||
* @param debugPackageName the Android package name to debug
|
* @param debugPackageName the Android package name to debug
|
||||||
* @param debuggable the debuggable value of the app, or null if not set.
|
* @param debuggable the debuggable value of the app, or null if not set.
|
||||||
* @param requiredApiVersionNumber the api version required by the app, or
|
* @param requiredApiVersionNumber the api version required by the app, or null if none.
|
||||||
* {@link AndroidManifestParser#INVALID_MIN_SDK} if none.
|
|
||||||
* @param launchAction the action to perform after app sync
|
* @param launchAction the action to perform after app sync
|
||||||
* @param config the launch configuration
|
* @param config the launch configuration
|
||||||
* @param launch the launch object
|
* @param launch the launch object
|
||||||
*/
|
*/
|
||||||
public void launch(final IProject project, String mode, IFile apk,
|
public void launch(final IProject project, String mode, IFile apk,
|
||||||
String packageName, String debugPackageName, Boolean debuggable, int requiredApiVersionNumber,
|
String packageName, String debugPackageName, Boolean debuggable,
|
||||||
final IAndroidLaunchAction launchAction, final AndroidLaunchConfiguration config,
|
String requiredApiVersionNumber, final IAndroidLaunchAction launchAction,
|
||||||
final AndroidLaunch launch, IProgressMonitor monitor) {
|
final AndroidLaunchConfiguration config, final AndroidLaunch launch,
|
||||||
|
IProgressMonitor monitor) {
|
||||||
|
|
||||||
String message = String.format("Performing %1$s", launchAction.getLaunchDescription());
|
String message = String.format("Performing %1$s", launchAction.getLaunchDescription());
|
||||||
AdtPlugin.printToConsole(project, message);
|
AdtPlugin.printToConsole(project, message);
|
||||||
@@ -398,17 +398,16 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
} else {
|
} else {
|
||||||
if (projectTarget.isPlatform()) { // means this can run on any device as long
|
if (projectTarget.isPlatform()) { // means this can run on any device as long
|
||||||
// as api level is high enough
|
// as api level is high enough
|
||||||
String apiString = d.getProperty(SdkManager.PROP_VERSION_SDK);
|
AndroidVersion deviceVersion = Sdk.getDeviceVersion(d);
|
||||||
try {
|
if (deviceVersion.canRun(projectTarget.getVersion())) {
|
||||||
int apiNumber = Integer.parseInt(apiString);
|
|
||||||
if (apiNumber >= projectTarget.getApiVersionNumber()) {
|
|
||||||
// device is compatible with project
|
// device is compatible with project
|
||||||
compatibleRunningAvds.put(d, null);
|
compatibleRunningAvds.put(d, null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} else {
|
||||||
// do nothing, we'll consider it a non compatible device below.
|
// for non project platform, we can't be sure if a device can
|
||||||
}
|
// run an application or not, since we don't query the device
|
||||||
|
// for the list of optional libraries that it supports.
|
||||||
}
|
}
|
||||||
hasDevice = true;
|
hasDevice = true;
|
||||||
}
|
}
|
||||||
@@ -544,9 +543,12 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
AvdInfo defaultAvd = null;
|
AvdInfo defaultAvd = null;
|
||||||
for (AvdInfo avd : avds) {
|
for (AvdInfo avd : avds) {
|
||||||
if (projectTarget.isCompatibleBaseFor(avd.getTarget())) {
|
if (projectTarget.isCompatibleBaseFor(avd.getTarget())) {
|
||||||
|
// at this point we can ignore the code name issue since
|
||||||
|
// IAndroidTarget.isCompatibleBaseFor() will already have filtered the non
|
||||||
|
// compatible AVDs.
|
||||||
if (defaultAvd == null ||
|
if (defaultAvd == null ||
|
||||||
avd.getTarget().getApiVersionNumber() <
|
avd.getTarget().getVersion().getApiLevel() <
|
||||||
defaultAvd.getTarget().getApiVersionNumber()) {
|
defaultAvd.getTarget().getVersion().getApiLevel()) {
|
||||||
defaultAvd = avd;
|
defaultAvd = avd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -654,46 +656,66 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
if (device != null) {
|
if (device != null) {
|
||||||
// check the app required API level versus the target device API level
|
// check the app required API level versus the target device API level
|
||||||
|
|
||||||
String deviceApiVersionName = device.getProperty(IDevice.PROP_BUILD_VERSION);
|
String deviceVersion = device.getProperty(IDevice.PROP_BUILD_VERSION);
|
||||||
String value = device.getProperty(IDevice.PROP_BUILD_VERSION_NUMBER);
|
String deviceApiLevelString = device.getProperty(IDevice.PROP_BUILD_API_LEVEL);
|
||||||
int deviceApiVersionNumber = AndroidManifestParser.INVALID_MIN_SDK;
|
String deviceCodeName = device.getProperty(IDevice.PROP_BUILD_CODENAME);
|
||||||
|
|
||||||
|
int deviceApiLevel = -1;
|
||||||
try {
|
try {
|
||||||
deviceApiVersionNumber = Integer.parseInt(value);
|
deviceApiLevel = Integer.parseInt(deviceApiLevelString);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// pass, we'll keep the deviceVersionNumber value at 0.
|
// pass, we'll keep the apiLevel value at -1.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (launchInfo.getRequiredApiVersionNumber() == AndroidManifestParser.INVALID_MIN_SDK) {
|
String requiredApiString = launchInfo.getRequiredApiVersionNumber();
|
||||||
// warn the API level requirement is not set.
|
if (requiredApiString != null) {
|
||||||
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
|
int requiredApi = -1;
|
||||||
"WARNING: Application does not specify an API level requirement!");
|
try {
|
||||||
|
requiredApi = Integer.parseInt(requiredApiString);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// pass, we'll keep requiredApi value at -1.
|
||||||
|
}
|
||||||
|
|
||||||
// and display the target device API level (if known)
|
if (requiredApi == -1) {
|
||||||
if (deviceApiVersionName == null ||
|
// this means the manifest uses a codename for minSdkVersion
|
||||||
deviceApiVersionNumber == AndroidManifestParser.INVALID_MIN_SDK) {
|
// check that the device is using the same codename
|
||||||
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
|
if (requiredApiString.equals(deviceCodeName) == false) {
|
||||||
"WARNING: Unknown device API version!");
|
|
||||||
} else {
|
|
||||||
AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
|
AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
|
||||||
"Device API version is %1$d (Android %2$s)", deviceApiVersionNumber,
|
"ERROR: Application requires a device running '%1$s'!",
|
||||||
deviceApiVersionName));
|
requiredApiString));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else { // app requires a specific API level
|
} else {
|
||||||
if (deviceApiVersionName == null ||
|
// app requires a specific API level
|
||||||
deviceApiVersionNumber == AndroidManifestParser.INVALID_MIN_SDK) {
|
if (deviceApiLevel == -1) {
|
||||||
AdtPlugin.printToConsole(launchInfo.getProject(),
|
AdtPlugin.printToConsole(launchInfo.getProject(),
|
||||||
"WARNING: Unknown device API version!");
|
"WARNING: Unknown device API version!");
|
||||||
} else if (deviceApiVersionNumber < launchInfo.getRequiredApiVersionNumber()) {
|
} else if (deviceApiLevel < requiredApi) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).",
|
"ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).",
|
||||||
launchInfo.getRequiredApiVersionNumber(), deviceApiVersionNumber,
|
requiredApi, deviceApiLevel, deviceVersion);
|
||||||
deviceApiVersionName);
|
|
||||||
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
|
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
|
||||||
|
|
||||||
// abort the launch
|
// abort the launch
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// warn the application API level requirement is not set.
|
||||||
|
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
|
||||||
|
"WARNING: Application does not specify an API level requirement!");
|
||||||
|
|
||||||
|
// and display the target device API level (if known)
|
||||||
|
if (deviceApiLevel == -1) {
|
||||||
|
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
|
||||||
|
"WARNING: Unknown device API version!");
|
||||||
|
} else {
|
||||||
|
AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
|
||||||
|
"Device API version is %1$d (Android %2$s)", deviceApiLevel,
|
||||||
|
deviceVersion));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// now checks that the device/app can be debugged (if needed)
|
// now checks that the device/app can be debugged (if needed)
|
||||||
if (device.isEmulator() == false && launchInfo.isDebugMode()) {
|
if (device.isEmulator() == false && launchInfo.isDebugMode()) {
|
||||||
@@ -1521,7 +1543,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
/**
|
/**
|
||||||
* Get the stderr/stdout outputs of a process and return when the process is done.
|
* Get the stderr/stdout outputs of a process and return when the process is done.
|
||||||
* Both <b>must</b> be read or the process will block on windows.
|
* Both <b>must</b> be read or the process will block on windows.
|
||||||
* @param process The process to get the ouput from
|
* @param process The process to get the output from
|
||||||
*/
|
*/
|
||||||
private void grabEmulatorOutput(final Process process) {
|
private void grabEmulatorOutput(final Process process) {
|
||||||
// read the lines as they come. if null is returned, it's
|
// read the lines as they come. if null is returned, it's
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package com.android.ide.eclipse.adt.internal.launch;
|
package com.android.ide.eclipse.adt.internal.launch;
|
||||||
|
|
||||||
import com.android.ddmlib.IDevice;
|
import com.android.ddmlib.IDevice;
|
||||||
import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser;
|
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
@@ -54,9 +53,8 @@ public final class DelayedLaunchInfo {
|
|||||||
/** debuggable attribute of the manifest file. */
|
/** debuggable attribute of the manifest file. */
|
||||||
private final Boolean mDebuggable;
|
private final Boolean mDebuggable;
|
||||||
|
|
||||||
/** Required ApiVersionNumber by the app. {@link AndroidManifestParser#INVALID_MIN_SDK} means
|
/** Required Api level by the app. null means no requirements */
|
||||||
* no requirements */
|
private final String mRequiredApiVersionNumber;
|
||||||
private final int mRequiredApiVersionNumber;
|
|
||||||
|
|
||||||
private InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
|
private InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
|
||||||
|
|
||||||
@@ -87,14 +85,13 @@ public final class DelayedLaunchInfo {
|
|||||||
* @param launchAction action to perform after app install
|
* @param launchAction action to perform after app install
|
||||||
* @param pack IFile to the package (.apk) file
|
* @param pack IFile to the package (.apk) file
|
||||||
* @param debuggable debuggable attribute of the app's manifest file.
|
* @param debuggable debuggable attribute of the app's manifest file.
|
||||||
* @param requiredApiVersionNumber required SDK version by the app.
|
* @param requiredApiVersionNumber required SDK version by the app. null means no requirements.
|
||||||
* {@link AndroidManifestParser#INVALID_MIN_SDK} means no requirements.
|
|
||||||
* @param launch the launch object
|
* @param launch the launch object
|
||||||
* @param monitor progress monitor for launch
|
* @param monitor progress monitor for launch
|
||||||
*/
|
*/
|
||||||
public DelayedLaunchInfo(IProject project, String packageName, String debugPackageName,
|
public DelayedLaunchInfo(IProject project, String packageName, String debugPackageName,
|
||||||
IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable,
|
IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable,
|
||||||
int requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
|
String requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
|
||||||
mProject = project;
|
mProject = project;
|
||||||
mPackageName = packageName;
|
mPackageName = packageName;
|
||||||
mDebugPackageName = debugPackageName;
|
mDebugPackageName = debugPackageName;
|
||||||
@@ -160,9 +157,9 @@ public final class DelayedLaunchInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the required api version number for the Android app
|
* @return the required api version number for the Android app.
|
||||||
*/
|
*/
|
||||||
public int getRequiredApiVersionNumber() {
|
public String getRequiredApiVersionNumber() {
|
||||||
return mRequiredApiVersionNumber;
|
return mRequiredApiVersionNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.android.ddmuilib.TableHelper;
|
|||||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
||||||
import com.android.sdkuilib.internal.widgets.AvdSelector;
|
import com.android.sdkuilib.internal.widgets.AvdSelector;
|
||||||
@@ -131,26 +132,19 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
case 2:
|
case 2:
|
||||||
// check for compatibility.
|
// check for compatibility.
|
||||||
if (device.isEmulator() == false) { // physical device
|
if (device.isEmulator() == false) { // physical device
|
||||||
// get the api level of the device
|
// get the version of the device
|
||||||
try {
|
AndroidVersion deviceVersion = Sdk.getDeviceVersion(device);
|
||||||
String apiValue = device.getProperty(
|
if (deviceVersion == null) {
|
||||||
IDevice.PROP_BUILD_VERSION_NUMBER);
|
return mWarningImage;
|
||||||
if (apiValue != null) {
|
} else {
|
||||||
int api = Integer.parseInt(apiValue);
|
if (deviceVersion.canRun(mProjectTarget.getVersion()) == false) {
|
||||||
if (api >= mProjectTarget.getApiVersionNumber()) {
|
return mNoMatchImage;
|
||||||
// if the project is compiling against an add-on, the optional
|
}
|
||||||
// API may be missing from the device.
|
|
||||||
|
// if the project is compiling against an add-on,
|
||||||
|
// the optional API may be missing from the device.
|
||||||
return mProjectTarget.isPlatform() ?
|
return mProjectTarget.isPlatform() ?
|
||||||
mMatchImage : mWarningImage;
|
mMatchImage : mWarningImage;
|
||||||
} else {
|
|
||||||
return mNoMatchImage;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return mWarningImage;
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// lets consider the device non compatible
|
|
||||||
return mNoMatchImage;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// get the AvdInfo
|
// get the AvdInfo
|
||||||
@@ -411,6 +405,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
offsetComp.setLayout(layout);
|
offsetComp.setLayout(layout);
|
||||||
|
|
||||||
mPreferredAvdSelector = new AvdSelector(offsetComp,
|
mPreferredAvdSelector = new AvdSelector(offsetComp,
|
||||||
|
mSdk.getSdkLocation(),
|
||||||
mSdk.getAvdManager(),
|
mSdk.getAvdManager(),
|
||||||
new NonRunningAvdFilter(),
|
new NonRunningAvdFilter(),
|
||||||
DisplayMode.SIMPLE_SELECTION);
|
DisplayMode.SIMPLE_SELECTION);
|
||||||
|
|||||||
@@ -195,7 +195,9 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
|||||||
// create the selector with no manager, we'll reset the manager every time this is
|
// create the selector with no manager, we'll reset the manager every time this is
|
||||||
// displayed to ensure we have the latest one (dialog is reused but SDK could have
|
// displayed to ensure we have the latest one (dialog is reused but SDK could have
|
||||||
// been changed in between.
|
// been changed in between.
|
||||||
mPreferredAvdSelector = new AvdSelector(offsetComp, null /* avd manager */,
|
mPreferredAvdSelector = new AvdSelector(offsetComp,
|
||||||
|
Sdk.getCurrent().getSdkLocation(),
|
||||||
|
null /* avd manager */,
|
||||||
DisplayMode.SIMPLE_CHECK);
|
DisplayMode.SIMPLE_CHECK);
|
||||||
mPreferredAvdSelector.setTableHeightHint(100);
|
mPreferredAvdSelector.setTableHeightHint(100);
|
||||||
mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
|
mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class AndroidManifestParser {
|
|||||||
private final static String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
|
private final static String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
|
||||||
private final static String ATTRIBUTE_PROCESS = "process"; //$NON-NLS-$
|
private final static String ATTRIBUTE_PROCESS = "process"; //$NON-NLS-$
|
||||||
private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$
|
private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$
|
||||||
private final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$
|
public final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$
|
||||||
private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$
|
private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$
|
||||||
private final static String ATTRIBUTE_EXPORTED = "exported"; //$NON-NLS-1$
|
private final static String ATTRIBUTE_EXPORTED = "exported"; //$NON-NLS-1$
|
||||||
private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$
|
private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$
|
||||||
@@ -76,8 +76,6 @@ public class AndroidManifestParser {
|
|||||||
private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
|
private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
|
||||||
private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
|
private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
|
||||||
|
|
||||||
public final static int INVALID_MIN_SDK = -1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumentation info obtained from manifest
|
* Instrumentation info obtained from manifest
|
||||||
*/
|
*/
|
||||||
@@ -179,9 +177,8 @@ public class AndroidManifestParser {
|
|||||||
private Set<String> mProcesses = null;
|
private Set<String> mProcesses = null;
|
||||||
/** debuggable attribute value. If null, the attribute is not present. */
|
/** debuggable attribute value. If null, the attribute is not present. */
|
||||||
private Boolean mDebuggable = null;
|
private Boolean mDebuggable = null;
|
||||||
/** API level requirement. if {@link AndroidManifestParser#INVALID_MIN_SDK}
|
/** API level requirement. if null the attribute was not present. */
|
||||||
* the attribute was not present. */
|
private String mApiLevelRequirement = null;
|
||||||
private int mApiLevelRequirement = INVALID_MIN_SDK;
|
|
||||||
/** List of all instrumentations declared by the manifest */
|
/** List of all instrumentations declared by the manifest */
|
||||||
private final ArrayList<Instrumentation> mInstrumentations =
|
private final ArrayList<Instrumentation> mInstrumentations =
|
||||||
new ArrayList<Instrumentation>();
|
new ArrayList<Instrumentation>();
|
||||||
@@ -258,10 +255,9 @@ public class AndroidManifestParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the <code>minSdkVersion</code> attribute, or
|
* Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
|
||||||
* {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set.
|
|
||||||
*/
|
*/
|
||||||
int getApiLevelRequirement() {
|
String getApiLevelRequirement() {
|
||||||
return mApiLevelRequirement;
|
return mApiLevelRequirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,16 +327,8 @@ public class AndroidManifestParser {
|
|||||||
|
|
||||||
mValidLevel++;
|
mValidLevel++;
|
||||||
} else if (NODE_USES_SDK.equals(localName)) {
|
} else if (NODE_USES_SDK.equals(localName)) {
|
||||||
value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION,
|
mApiLevelRequirement = getAttributeValue(attributes,
|
||||||
true /* hasNamespace */);
|
ATTRIBUTE_MIN_SDK_VERSION, true /* hasNamespace */);
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
try {
|
|
||||||
mApiLevelRequirement = Integer.parseInt(value);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
handleError(e, -1 /* lineNumber */);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (NODE_INSTRUMENTATION.equals(localName)) {
|
} else if (NODE_INSTRUMENTATION.equals(localName)) {
|
||||||
processInstrumentationNode(attributes);
|
processInstrumentationNode(attributes);
|
||||||
}
|
}
|
||||||
@@ -636,7 +624,7 @@ public class AndroidManifestParser {
|
|||||||
private final Activity mLauncherActivity;
|
private final Activity mLauncherActivity;
|
||||||
private final String[] mProcesses;
|
private final String[] mProcesses;
|
||||||
private final Boolean mDebuggable;
|
private final Boolean mDebuggable;
|
||||||
private final int mApiLevelRequirement;
|
private final String mApiLevelRequirement;
|
||||||
private final Instrumentation[] mInstrumentations;
|
private final Instrumentation[] mInstrumentations;
|
||||||
private final String[] mLibraries;
|
private final String[] mLibraries;
|
||||||
|
|
||||||
@@ -904,10 +892,9 @@ public class AndroidManifestParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the <code>minSdkVersion</code> attribute, or {@link #INVALID_MIN_SDK}
|
* Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
|
||||||
* if it's not set.
|
|
||||||
*/
|
*/
|
||||||
public int getApiLevelRequirement() {
|
public String getApiLevelRequirement() {
|
||||||
return mApiLevelRequirement;
|
return mApiLevelRequirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -939,13 +926,13 @@ public class AndroidManifestParser {
|
|||||||
* @param launcherActivity the launcher activity parser from the manifest.
|
* @param launcherActivity the launcher activity parser from the manifest.
|
||||||
* @param processes the list of custom processes declared in the manifest.
|
* @param processes the list of custom processes declared in the manifest.
|
||||||
* @param debuggable the debuggable attribute, or null if not set.
|
* @param debuggable the debuggable attribute, or null if not set.
|
||||||
* @param apiLevelRequirement the minSdkVersion attribute value or 0 if not set.
|
* @param apiLevelRequirement the minSdkVersion attribute value or null if not set.
|
||||||
* @param instrumentations the list of instrumentations parsed from the manifest.
|
* @param instrumentations the list of instrumentations parsed from the manifest.
|
||||||
* @param libraries the list of libraries in use parsed from the manifest.
|
* @param libraries the list of libraries in use parsed from the manifest.
|
||||||
*/
|
*/
|
||||||
private AndroidManifestParser(String javaPackage, Activity[] activities,
|
private AndroidManifestParser(String javaPackage, Activity[] activities,
|
||||||
Activity launcherActivity, String[] processes, Boolean debuggable,
|
Activity launcherActivity, String[] processes, Boolean debuggable,
|
||||||
int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
|
String apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
|
||||||
mJavaPackage = javaPackage;
|
mJavaPackage = javaPackage;
|
||||||
mActivities = activities;
|
mActivities = activities;
|
||||||
mLauncherActivity = launcherActivity;
|
mLauncherActivity = launcherActivity;
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
/** Keep track of the current workbench window. */
|
/** Keep track of the current workbench window. */
|
||||||
private IWorkbenchWindow mWindow;
|
private IWorkbenchWindow mWindow;
|
||||||
private ITextSelection mSelection;
|
private ITextSelection mSelection;
|
||||||
|
private IEditorPart mEditor;
|
||||||
private IFile mFile;
|
private IFile mFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,7 +108,8 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
if (selection instanceof ITextSelection) {
|
if (selection instanceof ITextSelection) {
|
||||||
mSelection = (ITextSelection) selection;
|
mSelection = (ITextSelection) selection;
|
||||||
if (mSelection.getLength() > 0) {
|
if (mSelection.getLength() > 0) {
|
||||||
mFile = getSelectedFile();
|
mEditor = getActiveEditor();
|
||||||
|
mFile = getSelectedFile(mEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +121,7 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
*/
|
*/
|
||||||
public void run(IAction action) {
|
public void run(IAction action) {
|
||||||
if (mSelection != null && mFile != null) {
|
if (mSelection != null && mFile != null) {
|
||||||
ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mSelection);
|
ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mEditor, mSelection);
|
||||||
RefactoringWizard wizard = new ExtractStringWizard(ref, mFile.getProject());
|
RefactoringWizard wizard = new ExtractStringWizard(ref, mFile.getProject());
|
||||||
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
|
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
|
||||||
try {
|
try {
|
||||||
@@ -130,6 +132,21 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the active editor (hopefully matching our selection) or null.
|
||||||
|
*/
|
||||||
|
private IEditorPart getActiveEditor() {
|
||||||
|
IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
|
||||||
|
if (wwin != null) {
|
||||||
|
IWorkbenchPage page = wwin.getActivePage();
|
||||||
|
if (page != null) {
|
||||||
|
return page.getActiveEditor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the active {@link IFile} (hopefully matching our selection) or null.
|
* Returns the active {@link IFile} (hopefully matching our selection) or null.
|
||||||
* The file is only returned if it's a file from a project with an Android nature.
|
* The file is only returned if it's a file from a project with an Android nature.
|
||||||
@@ -138,12 +155,7 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
* for the refactoring. This check is performed when the refactoring is invoked since
|
* for the refactoring. This check is performed when the refactoring is invoked since
|
||||||
* it can then produce meaningful error messages as needed.
|
* it can then produce meaningful error messages as needed.
|
||||||
*/
|
*/
|
||||||
private IFile getSelectedFile() {
|
private IFile getSelectedFile(IEditorPart editor) {
|
||||||
IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
|
|
||||||
if (wwin != null) {
|
|
||||||
IWorkbenchPage page = wwin.getActivePage();
|
|
||||||
if (page != null) {
|
|
||||||
IEditorPart editor = page.getActiveEditor();
|
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
IEditorInput input = editor.getEditorInput();
|
IEditorInput input = editor.getEditorInput();
|
||||||
|
|
||||||
@@ -162,8 +174,6 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
|
|||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.events.ModifyEvent;
|
import org.eclipse.swt.events.ModifyEvent;
|
||||||
import org.eclipse.swt.events.ModifyListener;
|
import org.eclipse.swt.events.ModifyListener;
|
||||||
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Combo;
|
import org.eclipse.swt.widgets.Combo;
|
||||||
@@ -42,6 +44,7 @@ import org.eclipse.swt.widgets.Label;
|
|||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -59,7 +62,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
private final IProject mProject;
|
private final IProject mProject;
|
||||||
|
|
||||||
/** Text field where the user enters the new ID to be generated or replaced with. */
|
/** Text field where the user enters the new ID to be generated or replaced with. */
|
||||||
private Text mStringIdField;
|
private Combo mStringIdCombo;
|
||||||
/** Text field where the user enters the new string value. */
|
/** Text field where the user enters the new string value. */
|
||||||
private Text mStringValueField;
|
private Text mStringValueField;
|
||||||
/** The configuration selector, to select the resource path of the XML file. */
|
/** The configuration selector, to select the resource path of the XML file. */
|
||||||
@@ -132,7 +135,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
// line: Textfield for string value (based on selection, if any)
|
// line: Textfield for string value (based on selection, if any)
|
||||||
|
|
||||||
Label label = new Label(group, SWT.NONE);
|
Label label = new Label(group, SWT.NONE);
|
||||||
label.setText("String");
|
label.setText("&String");
|
||||||
|
|
||||||
String selectedString = ref.getTokenString();
|
String selectedString = ref.getTokenString();
|
||||||
|
|
||||||
@@ -156,24 +159,31 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
|
|
||||||
label = new Label(group, SWT.NONE);
|
label = new Label(group, SWT.NONE);
|
||||||
if (ref.getMode() == ExtractStringRefactoring.Mode.EDIT_SOURCE) {
|
if (ref.getMode() == ExtractStringRefactoring.Mode.EDIT_SOURCE) {
|
||||||
label.setText("Replace by R.string.");
|
label.setText("&Replace by R.string.");
|
||||||
} else if (ref.getMode() == ExtractStringRefactoring.Mode.SELECT_NEW_ID) {
|
} else if (ref.getMode() == ExtractStringRefactoring.Mode.SELECT_NEW_ID) {
|
||||||
label.setText("New R.string.");
|
label.setText("New &R.string.");
|
||||||
} else {
|
} else {
|
||||||
label.setText("ID R.string.");
|
label.setText("ID &R.string.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mStringIdField = new Text(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
|
mStringIdCombo = new Combo(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER | SWT.DROP_DOWN);
|
||||||
mStringIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
mStringIdCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
mStringIdField.setText(guessId(selectedString));
|
mStringIdCombo.setText(guessId(selectedString));
|
||||||
|
mStringIdCombo.forceFocus();
|
||||||
|
|
||||||
ref.setNewStringId(mStringIdField.getText().trim());
|
ref.setNewStringId(mStringIdCombo.getText().trim());
|
||||||
|
|
||||||
mStringIdField.addModifyListener(new ModifyListener() {
|
mStringIdCombo.addModifyListener(new ModifyListener() {
|
||||||
public void modifyText(ModifyEvent e) {
|
public void modifyText(ModifyEvent e) {
|
||||||
validatePage();
|
validatePage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mStringIdCombo.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,7 +206,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
|
|
||||||
Label label;
|
Label label;
|
||||||
label = new Label(group, SWT.NONE);
|
label = new Label(group, SWT.NONE);
|
||||||
label.setText("Configuration:");
|
label.setText("&Configuration:");
|
||||||
|
|
||||||
mConfigSelector = new ConfigurationSelector(group);
|
mConfigSelector = new ConfigurationSelector(group);
|
||||||
GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
|
GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
|
||||||
@@ -210,7 +220,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
// line: selection of the output file
|
// line: selection of the output file
|
||||||
|
|
||||||
label = new Label(group, SWT.NONE);
|
label = new Label(group, SWT.NONE);
|
||||||
label.setText("Resource file:");
|
label.setText("Resource &file:");
|
||||||
|
|
||||||
mResFileCombo = new Combo(group, SWT.DROP_DOWN);
|
mResFileCombo = new Combo(group, SWT.DROP_DOWN);
|
||||||
mResFileCombo.select(0);
|
mResFileCombo.select(0);
|
||||||
@@ -269,7 +279,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
|
|
||||||
// Analyze fatal errors.
|
// Analyze fatal errors.
|
||||||
|
|
||||||
String text = mStringIdField.getText().trim();
|
String text = mStringIdCombo.getText().trim();
|
||||||
if (text == null || text.length() < 1) {
|
if (text == null || text.length() < 1) {
|
||||||
setErrorMessage("Please provide a resource ID.");
|
setErrorMessage("Please provide a resource ID.");
|
||||||
success = false;
|
success = false;
|
||||||
@@ -313,9 +323,12 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
ref.setTargetFile(resFile);
|
ref.setTargetFile(resFile);
|
||||||
sLastResFilePath.put(mProject.getFullPath().toPortableString(), resFile);
|
sLastResFilePath.put(mProject.getFullPath().toPortableString(), resFile);
|
||||||
|
|
||||||
if (mXmlHelper.isResIdDuplicate(mProject, resFile, text)) {
|
String idValue = mXmlHelper.valueOfStringId(mProject, resFile, text);
|
||||||
String msg = String.format("There's already a string item called '%1$s' in %2$s.",
|
if (idValue != null) {
|
||||||
text, resFile);
|
String msg = String.format("%1$s already contains a string ID '%2$s' with value '%3$s'.",
|
||||||
|
resFile,
|
||||||
|
text,
|
||||||
|
idValue);
|
||||||
if (ref.getMode() == ExtractStringRefactoring.Mode.SELECT_NEW_ID) {
|
if (ref.getMode() == ExtractStringRefactoring.Mode.SELECT_NEW_ID) {
|
||||||
setErrorMessage(msg);
|
setErrorMessage(msg);
|
||||||
success = false;
|
success = false;
|
||||||
@@ -341,6 +354,23 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateStringValueCombo() {
|
||||||
|
String resFile = mResFileCombo.getText();
|
||||||
|
Map<String, String> ids = mXmlHelper.getResIdsForFile(mProject, resFile);
|
||||||
|
|
||||||
|
// get the current text from the combo, to make sure we don't change it
|
||||||
|
String currText = mStringIdCombo.getText();
|
||||||
|
|
||||||
|
// erase the choices and fill with the given ids
|
||||||
|
mStringIdCombo.removeAll();
|
||||||
|
mStringIdCombo.setItems(ids.keySet().toArray(new String[ids.size()]));
|
||||||
|
|
||||||
|
// set the current text to preserve it in case it changed
|
||||||
|
if (!currText.equals(mStringIdCombo.getText())) {
|
||||||
|
mStringIdCombo.setText(currText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class OnConfigSelectorUpdated implements Runnable, ModifyListener {
|
public class OnConfigSelectorUpdated implements Runnable, ModifyListener {
|
||||||
|
|
||||||
/** Regex pattern to parse a valid res path: it reads (/res/folder-name/)+(filename). */
|
/** Regex pattern to parse a valid res path: it reads (/res/folder-name/)+(filename). */
|
||||||
@@ -457,6 +487,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finally validate the whole page
|
// finally validate the whole page
|
||||||
|
updateStringValueCombo();
|
||||||
validatePage();
|
validatePage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,6 +540,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateStringValueCombo();
|
||||||
validatePage();
|
validatePage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,24 +22,31 @@ import org.eclipse.core.resources.IFile;
|
|||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* An helper utility to get IDs out of an Android XML resource file.
|
||||||
*/
|
*/
|
||||||
class XmlStringFileHelper {
|
class XmlStringFileHelper {
|
||||||
|
|
||||||
/** A temporary cache of R.string IDs defined by a given xml file. The key is the
|
/** A temporary cache of R.string IDs defined by a given xml file. The key is the
|
||||||
* project path of the file, the data is a set of known string Ids for that file. */
|
* project path of the file, the data is a set of known string Ids for that file.
|
||||||
private HashMap<String,HashSet<String>> mResIdCache;
|
*
|
||||||
|
* Map type: map [String filename] => map [String id => String value].
|
||||||
|
*/
|
||||||
|
private HashMap<String, Map<String, String>> mResIdCache =
|
||||||
|
new HashMap<String, Map<String, String>>();
|
||||||
/** An instance of XPath, created lazily on demand. */
|
/** An instance of XPath, created lazily on demand. */
|
||||||
private XPath mXPath;
|
private XPath mXPath;
|
||||||
|
|
||||||
@@ -47,39 +54,48 @@ class XmlStringFileHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility method used by the wizard to check whether the given string ID is already
|
* Utility method used by the wizard to retrieve the actual value definition of a given
|
||||||
* defined in the XML file which path is given.
|
* string ID.
|
||||||
*
|
*
|
||||||
* @param project The project contain the XML file.
|
* @param project The project contain the XML file.
|
||||||
* @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
|
* @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
|
||||||
* The given file may or may not exist.
|
* The given file may or may not exist.
|
||||||
* @param stringId The string ID to find.
|
* @param stringId The string ID to find.
|
||||||
* @return True if such a string ID is already defined.
|
* @return The value string if the ID is defined, null otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isResIdDuplicate(IProject project, String xmlFileWsPath, String stringId) {
|
public String valueOfStringId(IProject project, String xmlFileWsPath, String stringId) {
|
||||||
// This is going to be called many times on the same file.
|
Map<String, String> cache = getResIdsForFile(project, xmlFileWsPath);
|
||||||
// Build a cache of the existing IDs for a given file.
|
return cache.get(stringId);
|
||||||
if (mResIdCache == null) {
|
|
||||||
mResIdCache = new HashMap<String, HashSet<String>>();
|
|
||||||
}
|
|
||||||
HashSet<String> cache = mResIdCache.get(xmlFileWsPath);
|
|
||||||
if (cache == null) {
|
|
||||||
cache = getResIdsForFile(project, xmlFileWsPath);
|
|
||||||
mResIdCache.put(xmlFileWsPath, cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cache.contains(stringId);
|
/**
|
||||||
|
* Utility method that retrieves all the *string* IDs defined in the given Android resource
|
||||||
|
* file. The instance maintains an internal cache so a given file is retrieved only once.
|
||||||
|
* Callers should consider the set to be read-only.
|
||||||
|
*
|
||||||
|
* @param project The project contain the XML file.
|
||||||
|
* @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
|
||||||
|
* The given file may or may not exist.
|
||||||
|
* @return The map of string IDs => values defined in the given file. Cached. Never null.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getResIdsForFile(IProject project, String xmlFileWsPath) {
|
||||||
|
Map<String, String> cache = mResIdCache.get(xmlFileWsPath);
|
||||||
|
if (cache == null) {
|
||||||
|
cache = internalGetResIdsForFile(project, xmlFileWsPath);
|
||||||
|
mResIdCache.put(xmlFileWsPath, cache);
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract all the defined string IDs from a given file using XPath.
|
* Extract all the defined string IDs from a given file using XPath.
|
||||||
* @param project The project contain the XML file.
|
* @param project The project contain the XML file.
|
||||||
* @param xmlFileWsPath The project path of the file to parse. It may not exist.
|
* @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
|
* @return The map of all string IDs => values defined in the file.
|
||||||
* null. It is empty if the file does not exist.
|
* The returned set is always non null. It is empty if the file does not exist.
|
||||||
*/
|
*/
|
||||||
private HashSet<String> getResIdsForFile(IProject project, String xmlFileWsPath) {
|
private Map<String, String> internalGetResIdsForFile(IProject project, String xmlFileWsPath) {
|
||||||
HashSet<String> ids = new HashSet<String>();
|
TreeMap<String, String> ids = new TreeMap<String, String>();
|
||||||
|
|
||||||
if (mXPath == null) {
|
if (mXPath == null) {
|
||||||
mXPath = AndroidXPathFactory.newXPath();
|
mXPath = AndroidXPathFactory.newXPath();
|
||||||
@@ -98,20 +114,26 @@ class XmlStringFileHelper {
|
|||||||
// <string name="ID">something</string>
|
// <string name="ID">something</string>
|
||||||
// </resources>
|
// </resources>
|
||||||
|
|
||||||
String xpathExpr = "/resources/string/@name"; //$NON-NLS-1$
|
String xpathExpr = "/resources/string"; //$NON-NLS-1$
|
||||||
|
|
||||||
Object result = mXPath.evaluate(xpathExpr, source, XPathConstants.NODESET);
|
Object result = mXPath.evaluate(xpathExpr, source, XPathConstants.NODESET);
|
||||||
if (result instanceof NodeList) {
|
if (result instanceof NodeList) {
|
||||||
NodeList list = (NodeList) result;
|
NodeList list = (NodeList) result;
|
||||||
for (int n = list.getLength() - 1; n >= 0; n--) {
|
for (int n = list.getLength() - 1; n >= 0; n--) {
|
||||||
String id = list.item(n).getNodeValue();
|
Node strNode = list.item(n);
|
||||||
ids.add(id);
|
NamedNodeMap attrs = strNode.getAttributes();
|
||||||
|
Node nameAttr = attrs.getNamedItem("name"); //$NON-NLS-1$
|
||||||
|
if (nameAttr != null) {
|
||||||
|
String id = nameAttr.getNodeValue();
|
||||||
|
String text = strNode.getTextContent();
|
||||||
|
ids.put(id, text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (CoreException e1) {
|
} catch (CoreException e1) {
|
||||||
// IFile.getContents failed. Ignore.
|
// IFile.getContents failed. Ignore.
|
||||||
} catch (XPathExpressionException e) {
|
} catch (XPathExpressionException e2) {
|
||||||
// mXPath.evaluate failed. Ignore.
|
// mXPath.evaluate failed. Ignore.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString();
|
return result == null ? null : result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(FolderConfiguration folderConfig) {
|
public int compareTo(FolderConfiguration folderConfig) {
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ public final class AndroidTargetParser {
|
|||||||
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
|
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
|
||||||
|
|
||||||
Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null;
|
Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null;
|
||||||
if (mAndroidTarget.getApiVersionNumber() >= 3) {
|
if (mAndroidTarget.getVersion().getApiLevel() >= 3) {
|
||||||
xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser);
|
xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
package com.android.ide.eclipse.adt.internal.sdk;
|
package com.android.ide.eclipse.adt.internal.sdk;
|
||||||
|
|
||||||
|
import com.android.ddmlib.IDevice;
|
||||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
|
import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
|
||||||
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor;
|
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor;
|
||||||
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IProjectListener;
|
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IProjectListener;
|
||||||
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData.LayoutBridge;
|
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData.LayoutBridge;
|
||||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.ISdkLog;
|
import com.android.sdklib.ISdkLog;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
@@ -394,6 +396,21 @@ public class Sdk implements IProjectListener {
|
|||||||
return mAvdManager;
|
return mAvdManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AndroidVersion getDeviceVersion(IDevice device) {
|
||||||
|
try {
|
||||||
|
Map<String, String> props = device.getProperties();
|
||||||
|
String apiLevel = props.get(IDevice.PROP_BUILD_API_LEVEL);
|
||||||
|
if (apiLevel == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AndroidVersion(Integer.parseInt(apiLevel),
|
||||||
|
props.get((IDevice.PROP_BUILD_CODENAME)));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Sdk(SdkManager manager, AvdManager avdManager) {
|
private Sdk(SdkManager manager, AvdManager avdManager) {
|
||||||
mManager = manager;
|
mManager = manager;
|
||||||
mAvdManager = avdManager;
|
mAvdManager = avdManager;
|
||||||
|
|||||||
@@ -840,26 +840,22 @@ public class NewProjectCreationPage extends WizardPage {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
String minSdkVersion = mInfo.getMinSdkVersion();
|
||||||
int version = Integer.parseInt(mInfo.getMinSdkVersion());
|
|
||||||
|
|
||||||
// Before changing, compare with the currently selected one, if any.
|
// Before changing, compare with the currently selected one, if any.
|
||||||
// There can be multiple targets with the same sdk api version, so don't change
|
// There can be multiple targets with the same sdk api version, so don't change
|
||||||
// it if it's already at the right version.
|
// it if it's already at the right version.
|
||||||
IAndroidTarget curr_target = mInfo.getSdkTarget();
|
IAndroidTarget curr_target = mInfo.getSdkTarget();
|
||||||
if (curr_target != null && curr_target.getApiVersionNumber() == version) {
|
if (curr_target != null && curr_target.getVersion().equals(minSdkVersion)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
||||||
if (target.getApiVersionNumber() == version) {
|
if (target.getVersion().equals(minSdkVersion)) {
|
||||||
mSdkTargetSelector.setSelection(target);
|
mSdkTargetSelector.setSelection(target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -873,7 +869,7 @@ public class NewProjectCreationPage extends WizardPage {
|
|||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
mInternalMinSdkVersionUpdate = true;
|
mInternalMinSdkVersionUpdate = true;
|
||||||
mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
|
mMinSdkVersionField.setText(target.getVersion().getApiString());
|
||||||
mInternalMinSdkVersionUpdate = false;
|
mInternalMinSdkVersionUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -932,7 +928,7 @@ public class NewProjectCreationPage extends WizardPage {
|
|||||||
String packageName = null;
|
String packageName = null;
|
||||||
Activity activity = null;
|
Activity activity = null;
|
||||||
String activityName = null;
|
String activityName = null;
|
||||||
int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
|
String minSdkVersion = null;
|
||||||
try {
|
try {
|
||||||
packageName = manifestData.getPackage();
|
packageName = manifestData.getPackage();
|
||||||
minSdkVersion = manifestData.getApiLevelRequirement();
|
minSdkVersion = manifestData.getApiLevelRequirement();
|
||||||
@@ -1033,18 +1029,14 @@ public class NewProjectCreationPage extends WizardPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundTarget && minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK) {
|
if (!foundTarget && minSdkVersion != null) {
|
||||||
try {
|
|
||||||
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
||||||
if (target.getApiVersionNumber() == minSdkVersion) {
|
if (target.getVersion().equals(minSdkVersion)) {
|
||||||
mSdkTargetSelector.setSelection(target);
|
mSdkTargetSelector.setSelection(target);
|
||||||
foundTarget = true;
|
foundTarget = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(NumberFormatException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundTarget) {
|
if (!foundTarget) {
|
||||||
@@ -1059,9 +1051,9 @@ public class NewProjectCreationPage extends WizardPage {
|
|||||||
|
|
||||||
if (!foundTarget) {
|
if (!foundTarget) {
|
||||||
mInternalMinSdkVersionUpdate = true;
|
mInternalMinSdkVersionUpdate = true;
|
||||||
mMinSdkVersionField.setText(
|
if (minSdkVersion != null) {
|
||||||
minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" //$NON-NLS-1$
|
mMinSdkVersionField.setText(minSdkVersion);
|
||||||
: Integer.toString(minSdkVersion));
|
}
|
||||||
mInternalMinSdkVersionUpdate = false;
|
mInternalMinSdkVersionUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1269,21 +1261,10 @@ public class NewProjectCreationPage extends WizardPage {
|
|||||||
return MSG_NONE;
|
return MSG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int version = AndroidManifestParser.INVALID_MIN_SDK;
|
if (mInfo.getSdkTarget() != null &&
|
||||||
try {
|
mInfo.getSdkTarget().getVersion().equals(mInfo.getMinSdkVersion()) == false) {
|
||||||
// If not empty, it must be a valid integer > 0
|
|
||||||
version = Integer.parseInt(mInfo.getMinSdkVersion());
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1) {
|
|
||||||
return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mInfo.getSdkTarget() != null && mInfo.getSdkTarget().getApiVersionNumber() != version) {
|
|
||||||
return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
|
return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
|
||||||
MSG_WARNING);
|
mInfo.getSdkTarget().getVersion().isPreview() ? MSG_ERROR : MSG_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_NONE;
|
return MSG_NONE;
|
||||||
|
|||||||
@@ -821,7 +821,7 @@ public class NewTestProjectCreationPage extends WizardPage {
|
|||||||
if (manifestData != null) {
|
if (manifestData != null) {
|
||||||
String appName = String.format("%1$sTest", project.getName());
|
String appName = String.format("%1$sTest", project.getName());
|
||||||
String packageName = manifestData.getPackage();
|
String packageName = manifestData.getPackage();
|
||||||
int minSdkVersion = manifestData.getApiLevelRequirement();
|
String minSdkVersion = manifestData.getApiLevelRequirement();
|
||||||
IAndroidTarget sdkTarget = null;
|
IAndroidTarget sdkTarget = null;
|
||||||
if (Sdk.getCurrent() != null) {
|
if (Sdk.getCurrent() != null) {
|
||||||
sdkTarget = Sdk.getCurrent().getTarget(project);
|
sdkTarget = Sdk.getCurrent().getTarget(project);
|
||||||
@@ -859,9 +859,9 @@ public class NewTestProjectCreationPage extends WizardPage {
|
|||||||
|
|
||||||
if (!mMinSdkVersionModifiedByUser) {
|
if (!mMinSdkVersionModifiedByUser) {
|
||||||
mInternalMinSdkVersionUpdate = true;
|
mInternalMinSdkVersionUpdate = true;
|
||||||
mMinSdkVersionField.setText(
|
if (minSdkVersion != null) {
|
||||||
minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK ?
|
mMinSdkVersionField.setText(minSdkVersion);
|
||||||
Integer.toString(minSdkVersion) : ""); //$NON-NLS-1$
|
}
|
||||||
if (sdkTarget == null) {
|
if (sdkTarget == null) {
|
||||||
updateSdkSelectorToMatchMinSdkVersion();
|
updateSdkSelectorToMatchMinSdkVersion();
|
||||||
}
|
}
|
||||||
@@ -1052,23 +1052,19 @@ public class NewTestProjectCreationPage extends WizardPage {
|
|||||||
* that matches.
|
* that matches.
|
||||||
*/
|
*/
|
||||||
private void updateSdkSelectorToMatchMinSdkVersion() {
|
private void updateSdkSelectorToMatchMinSdkVersion() {
|
||||||
try {
|
String minSdkVersion = mInfo.getMinSdkVersion();
|
||||||
int version = Integer.parseInt(mInfo.getMinSdkVersion());
|
|
||||||
|
|
||||||
IAndroidTarget curr_target = mInfo.getSdkTarget();
|
IAndroidTarget curr_target = mInfo.getSdkTarget();
|
||||||
if (curr_target != null && curr_target.getApiVersionNumber() == version) {
|
if (curr_target != null && curr_target.getVersion().equals(minSdkVersion)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
||||||
if (target.getApiVersionNumber() == version) {
|
if (target.getVersion().equals(minSdkVersion)) {
|
||||||
mSdkTargetSelector.setSelection(target);
|
mSdkTargetSelector.setSelection(target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1086,7 +1082,7 @@ public class NewTestProjectCreationPage extends WizardPage {
|
|||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
mInternalMinSdkVersionUpdate = true;
|
mInternalMinSdkVersionUpdate = true;
|
||||||
mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
|
mMinSdkVersionField.setText(target.getVersion().getApiString());
|
||||||
mInternalMinSdkVersionUpdate = false;
|
mInternalMinSdkVersionUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1261,21 +1257,10 @@ public class NewTestProjectCreationPage extends WizardPage {
|
|||||||
return MSG_NONE;
|
return MSG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int version = AndroidManifestParser.INVALID_MIN_SDK;
|
if (mInfo.getSdkTarget() != null &&
|
||||||
try {
|
mInfo.getSdkTarget().getVersion().equals(mInfo.getMinSdkVersion()) == false) {
|
||||||
// If not empty, it must be a valid integer > 0
|
|
||||||
version = Integer.parseInt(mInfo.getMinSdkVersion());
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1) {
|
|
||||||
return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mInfo.getSdkTarget() != null && mInfo.getSdkTarget().getApiVersionNumber() != version) {
|
|
||||||
return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
|
return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
|
||||||
MSG_WARNING);
|
mInfo.getSdkTarget().getVersion().isPreview() ? MSG_ERROR : MSG_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_NONE;
|
return MSG_NONE;
|
||||||
|
|||||||
@@ -1130,7 +1130,7 @@ class NewXmlFileCreationPage extends WizardPage {
|
|||||||
IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null;
|
IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null;
|
||||||
int currentApiLevel = 1;
|
int currentApiLevel = 1;
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
currentApiLevel = target.getApiVersionNumber();
|
currentApiLevel = target.getVersion().getApiLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TypeInfo type : sTypes) {
|
for (TypeInfo type : sTypes) {
|
||||||
@@ -1175,7 +1175,7 @@ class NewXmlFileCreationPage extends WizardPage {
|
|||||||
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
|
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
|
||||||
int currentApiLevel = 1;
|
int currentApiLevel = 1;
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
currentApiLevel = target.getApiVersionNumber();
|
currentApiLevel = target.getVersion().getApiLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeInfo type = getSelectedType();
|
TypeInfo type = getSelectedType();
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
HOST=`uname`
|
||||||
|
if [ "${HOST:0:6}" == "CYGWIN" ]; then
|
||||||
|
if [ "x$1" == "x" ] || [ `basename "$1"` != "layoutlib.jar" ]; then
|
||||||
|
echo "Usage: $0 sdk/platforms/xxx/data/layoutlib.jar"
|
||||||
|
echo "Argument 1 should be the path to the layoutlib.jar that should be updated by create_bridge_symlinks.sh."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "### $0 executing"
|
echo "### $0 executing"
|
||||||
|
|
||||||
function die() {
|
function die() {
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ class Main {
|
|||||||
mSdkLog.printf(" Name: %s\n", target.getName());
|
mSdkLog.printf(" Name: %s\n", target.getName());
|
||||||
if (target.isPlatform()) {
|
if (target.isPlatform()) {
|
||||||
mSdkLog.printf(" Type: Platform\n");
|
mSdkLog.printf(" Type: Platform\n");
|
||||||
mSdkLog.printf(" API level: %d\n", target.getApiVersionNumber());
|
mSdkLog.printf(" API level: %s\n", target.getVersion().getApiString());
|
||||||
mSdkLog.printf(" Revision: %d\n", target.getRevision());
|
mSdkLog.printf(" Revision: %d\n", target.getRevision());
|
||||||
} else {
|
} else {
|
||||||
mSdkLog.printf(" Type: Add-On\n");
|
mSdkLog.printf(" Type: Add-On\n");
|
||||||
@@ -426,7 +426,7 @@ class Main {
|
|||||||
mSdkLog.printf(" Description: %s\n", target.getDescription());
|
mSdkLog.printf(" Description: %s\n", target.getDescription());
|
||||||
}
|
}
|
||||||
mSdkLog.printf(" Based on Android %s (API level %d)\n",
|
mSdkLog.printf(" Based on Android %s (API level %d)\n",
|
||||||
target.getApiVersionName(), target.getApiVersionNumber());
|
target.getVersionName(), target.getVersion().getApiString());
|
||||||
|
|
||||||
// display the optional libraries.
|
// display the optional libraries.
|
||||||
IOptionalLibrary[] libraries = target.getOptionalLibraries();
|
IOptionalLibrary[] libraries = target.getOptionalLibraries();
|
||||||
@@ -501,13 +501,13 @@ class Main {
|
|||||||
// get the target of the AVD
|
// get the target of the AVD
|
||||||
IAndroidTarget target = info.getTarget();
|
IAndroidTarget target = info.getTarget();
|
||||||
if (target.isPlatform()) {
|
if (target.isPlatform()) {
|
||||||
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
|
mSdkLog.printf(" Target: %s (API level %s)\n", target.getName(),
|
||||||
target.getApiVersionNumber());
|
target.getVersion().getApiString());
|
||||||
} else {
|
} else {
|
||||||
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
|
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
|
||||||
.getVendor());
|
.getVendor());
|
||||||
mSdkLog.printf(" Based on Android %s (API level %d)\n", target
|
mSdkLog.printf(" Based on Android %s (API level %s)\n",
|
||||||
.getApiVersionName(), target.getApiVersionNumber());
|
target.getVersionName(), target.getVersion().getApiString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// display some extra values.
|
// display some extra values.
|
||||||
|
|||||||
@@ -137,14 +137,13 @@ final class AddOnTarget implements IAndroidTarget {
|
|||||||
return mDescription;
|
return mDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getApiVersionName() {
|
public AndroidVersion getVersion() {
|
||||||
// this is always defined by the base platform
|
// this is always defined by the base platform
|
||||||
return mBasePlatform.getApiVersionName();
|
return mBasePlatform.getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApiVersionNumber() {
|
public String getVersionName() {
|
||||||
// this is always defined by the base platform
|
return mBasePlatform.getVersionName();
|
||||||
return mBasePlatform.getApiVersionNumber();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRevision() {
|
public int getRevision() {
|
||||||
@@ -182,7 +181,7 @@ final class AddOnTarget implements IAndroidTarget {
|
|||||||
return sampleLoc.getAbsolutePath();
|
return sampleLoc.getAbsolutePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// INTENT FALL-THROUGH
|
// INTENDED FALL-THROUGH
|
||||||
default :
|
default :
|
||||||
return mBasePlatform.getPath(pathId);
|
return mBasePlatform.getPath(pathId);
|
||||||
}
|
}
|
||||||
@@ -222,21 +221,22 @@ final class AddOnTarget implements IAndroidTarget {
|
|||||||
// if the receiver has no optional library, then anything with api version number >= to
|
// if the receiver has no optional library, then anything with api version number >= to
|
||||||
// the receiver is compatible.
|
// the receiver is compatible.
|
||||||
if (mLibraries.length == 0) {
|
if (mLibraries.length == 0) {
|
||||||
return target.getApiVersionNumber() >= getApiVersionNumber();
|
return target.getVersion().getApiLevel() >= getVersion().getApiLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, target is only compatible if the vendor and name are equals with the api
|
// Otherwise, target is only compatible if the vendor and name are equals with the api
|
||||||
// number greater or equal (ie target is a newer version of this add-on).
|
// number greater or equal (ie target is a newer version of this add-on).
|
||||||
if (target.isPlatform() == false) {
|
if (target.isPlatform() == false) {
|
||||||
return (mVendor.equals(target.getVendor()) && mName.equals(target.getName()) &&
|
return (mVendor.equals(target.getVendor()) && mName.equals(target.getName()) &&
|
||||||
target.getApiVersionNumber() >= getApiVersionNumber());
|
target.getVersion().getApiLevel() >= getVersion().getApiLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String hashString() {
|
public String hashString() {
|
||||||
return String.format(ADD_ON_FORMAT, mVendor, mName, mBasePlatform.getApiVersionNumber());
|
return String.format(ADD_ON_FORMAT, mVendor, mName,
|
||||||
|
mBasePlatform.getVersion().getApiLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -250,7 +250,7 @@ final class AddOnTarget implements IAndroidTarget {
|
|||||||
AddOnTarget addon = (AddOnTarget)obj;
|
AddOnTarget addon = (AddOnTarget)obj;
|
||||||
|
|
||||||
return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) &&
|
return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) &&
|
||||||
mBasePlatform.getApiVersionNumber() == addon.mBasePlatform.getApiVersionNumber();
|
mBasePlatform.getVersion().getApiLevel() == addon.mBasePlatform.getVersion().getApiLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.equals(obj);
|
return super.equals(obj);
|
||||||
@@ -277,7 +277,7 @@ final class AddOnTarget implements IAndroidTarget {
|
|||||||
|
|
||||||
// api version
|
// api version
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
value = getApiVersionNumber() - target.getApiVersionNumber();
|
value = getVersion().getApiLevel() - target.getVersion().getApiLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* 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.sdklib;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the version of a target or device.
|
||||||
|
* <p/>
|
||||||
|
* A version is defined by an API level and an optional code name.
|
||||||
|
* <ul><li>Release versions of the Android platform are identified by their API level (integer),
|
||||||
|
* (technically the code name for release version is "REL" but this class will return
|
||||||
|
* <code>null<code> instead.)</li>
|
||||||
|
* <li>Preview versions of the platform are identified by a code name. Their API level
|
||||||
|
* is usually set to the value of the previous platform.</li></ul>
|
||||||
|
* <p/>
|
||||||
|
* While this class contains both values, its goal is to abstract them, so that code comparing 2+
|
||||||
|
* versions doesn't have to deal with the logic of handle both values.
|
||||||
|
* <p/>
|
||||||
|
* There are some cases where ones may want to access the values directly. This can be done
|
||||||
|
* with {@link #getApiLevel()} and {@link #getCodename()}.
|
||||||
|
* <p/>
|
||||||
|
* For generic UI display of the API version, {@link #getApiString()} is to be used.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AndroidVersion {
|
||||||
|
|
||||||
|
private static final String PROP_API_LEVEL = "AndroidVersion.ApiLevel"; //$NON-NLS-1$
|
||||||
|
private static final String PROP_CODENAME = "AndroidVersion.CodeName"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private final int mApiLevel;
|
||||||
|
private final String mCodename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@link AndroidVersion} with the given api level and codename.
|
||||||
|
*/
|
||||||
|
public AndroidVersion(int apiLevel, String codename) {
|
||||||
|
mApiLevel = apiLevel;
|
||||||
|
mCodename = codename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@link AndroidVersion} from {@link Properties}, with default values if the
|
||||||
|
* {@link Properties} object doesn't contain the expected values.
|
||||||
|
* <p/>The {@link Properties} is expected to have been filled with
|
||||||
|
* {@link #saveProperties(Properties)}.
|
||||||
|
*/
|
||||||
|
public AndroidVersion(Properties properties, int defaultApiLevel, String defaultCodeName) {
|
||||||
|
if (properties == null) {
|
||||||
|
mApiLevel = defaultApiLevel;
|
||||||
|
mCodename = defaultCodeName;
|
||||||
|
} else {
|
||||||
|
mApiLevel = Integer.parseInt(properties.getProperty(PROP_API_LEVEL,
|
||||||
|
Integer.toString(defaultApiLevel)));
|
||||||
|
mCodename = properties.getProperty(PROP_CODENAME, defaultCodeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveProperties(Properties props) {
|
||||||
|
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
|
||||||
|
if (mCodename != null) {
|
||||||
|
props.setProperty(PROP_CODENAME, mCodename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the api level as an integer.
|
||||||
|
* <p/>For target that are in preview mode, this can be superseded by
|
||||||
|
* {@link #getCodename()}.
|
||||||
|
* <p/>To display the API level in the UI, use {@link #getApiString()}, which will use the
|
||||||
|
* codename if applicable.
|
||||||
|
* @see #getCodename()
|
||||||
|
* @see #getApiString()
|
||||||
|
*/
|
||||||
|
public int getApiLevel() {
|
||||||
|
return mApiLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version code name if applicable, null otherwise.
|
||||||
|
* <p/>If the codename is non null, then the API level should be ignored, and this should be
|
||||||
|
* used as a unique identifier of the target instead.
|
||||||
|
*/
|
||||||
|
public String getCodename() {
|
||||||
|
return mCodename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representing the API level and/or the code name.
|
||||||
|
*/
|
||||||
|
public String getApiString() {
|
||||||
|
if (mCodename != null) {
|
||||||
|
return mCodename;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Integer.toString(mApiLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the version is a preview version.
|
||||||
|
*/
|
||||||
|
public boolean isPreview() {
|
||||||
|
return mCodename != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a device running a version similar to the receiver can run a project compiled
|
||||||
|
* for the given <var>version</var>.
|
||||||
|
* <p/>
|
||||||
|
* Be aware that this is not a perfect test, as other properties could break compatibility
|
||||||
|
* despite this method returning true. For a more comprehensive test, see
|
||||||
|
* {@link IAndroidTarget#isCompatibleBaseFor(IAndroidTarget)}.
|
||||||
|
* <p/>
|
||||||
|
* Nevertheless, when testing if an application can run on a device (where there is no
|
||||||
|
* access to the list of optional libraries), this method can give a good indication of whether
|
||||||
|
* there is a chance the application could run, or if there's a direct incompatibility.
|
||||||
|
*/
|
||||||
|
public boolean canRun(AndroidVersion appVersion) {
|
||||||
|
// if the application is compiled for a preview version, the device must be running exactly
|
||||||
|
// the same.
|
||||||
|
if (appVersion.mCodename != null) {
|
||||||
|
return appVersion.mCodename.equals(mCodename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, we check the api level (note that a device running a preview version
|
||||||
|
// will have the api level of the previous platform).
|
||||||
|
return mApiLevel >= appVersion.mApiLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <code>true</code> if the AndroidVersion is an API level equals to
|
||||||
|
* <var>apiLevel</var>.
|
||||||
|
*/
|
||||||
|
public boolean equals(int apiLevel) {
|
||||||
|
return mCodename == null && apiLevel == mApiLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares the receiver with either an {@link AndroidVersion} object or a {@link String}
|
||||||
|
* object.
|
||||||
|
* <p/>If <var>obj</var> is a {@link String}, then the method will first check if it's a string
|
||||||
|
* representation of a number, in which case it'll compare it to the api level. Otherwise, it'll
|
||||||
|
* compare it against the code name.
|
||||||
|
* <p/>For all other type of object give as parameter, this method will return
|
||||||
|
* <code>false</code>.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof AndroidVersion) {
|
||||||
|
AndroidVersion version = (AndroidVersion)obj;
|
||||||
|
|
||||||
|
if (mCodename == null) {
|
||||||
|
return version.mCodename == null &&
|
||||||
|
mApiLevel == version.mApiLevel;
|
||||||
|
} else {
|
||||||
|
return mCodename.equals(version.mCodename) &&
|
||||||
|
mApiLevel == version.mApiLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (obj instanceof String) {
|
||||||
|
try {
|
||||||
|
int value = Integer.parseInt((String)obj);
|
||||||
|
return value == mApiLevel;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// not a number? compare to the code name
|
||||||
|
return obj.equals(mCodename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
if (mCodename != null) {
|
||||||
|
return mCodename.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// there may be some collisions between the hashcode of the codename and the api level
|
||||||
|
// but it's acceptable.
|
||||||
|
return mApiLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,14 +119,14 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
|
|||||||
String getDescription();
|
String getDescription();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the api version as an integer.
|
* Returns the version of the target. This is guaranteed to be non-null.
|
||||||
*/
|
*/
|
||||||
int getApiVersionNumber();
|
AndroidVersion getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the platform version as a readable string.
|
* Returns the platform version as a readable string.
|
||||||
*/
|
*/
|
||||||
String getApiVersionName();
|
public String getVersionName();
|
||||||
|
|
||||||
/** Returns the revision number for the target. */
|
/** Returns the revision number for the target. */
|
||||||
int getRevision();
|
int getRevision();
|
||||||
|
|||||||
@@ -26,32 +26,41 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
final class PlatformTarget implements IAndroidTarget {
|
final class PlatformTarget implements IAndroidTarget {
|
||||||
/** String used to get a hash to the platform target */
|
/** String used to get a hash to the platform target */
|
||||||
private final static String PLATFORM_HASH = "android-%d";
|
private final static String PLATFORM_HASH_API_LEVEL = "android-%d";
|
||||||
|
private final static String PLATFORM_HASH_CODENAME = "android-%s";
|
||||||
|
|
||||||
private final static String PLATFORM_VENDOR = "Android Open Source Project";
|
private final static String PLATFORM_VENDOR = "Android Open Source Project";
|
||||||
|
|
||||||
private final static String PLATFORM_NAME = "Android %s";
|
private final static String PLATFORM_NAME = "Android %s";
|
||||||
|
private final static String PLATFORM_NAME_PREVIEW = "Android %s (Preview)";
|
||||||
|
|
||||||
private final String mLocation;
|
private final String mLocation;
|
||||||
private final String mName;
|
private final String mName;
|
||||||
private final int mApiVersionNumber;
|
private final AndroidVersion mVersion;
|
||||||
private final String mApiVersionName;
|
private final String mVersionName;
|
||||||
private final int mRevision;
|
private final int mRevision;
|
||||||
private final Map<String, String> mProperties;
|
private final Map<String, String> mProperties;
|
||||||
private final Map<Integer, String> mPaths = new HashMap<Integer, String>();
|
private final Map<Integer, String> mPaths = new HashMap<Integer, String>();
|
||||||
private String[] mSkins;
|
private String[] mSkins;
|
||||||
|
|
||||||
|
|
||||||
PlatformTarget(String location, Map<String, String> properties,
|
PlatformTarget(String location, Map<String, String> properties,
|
||||||
int apiNumber, String apiName, int revision) {
|
int apiLevel, String codeName, String versionName, int revision) {
|
||||||
mName = String.format(PLATFORM_NAME, apiName);
|
|
||||||
if (location.endsWith(File.separator) == false) {
|
if (location.endsWith(File.separator) == false) {
|
||||||
location = location + File.separator;
|
location = location + File.separator;
|
||||||
}
|
}
|
||||||
mLocation = location;
|
mLocation = location;
|
||||||
mProperties = Collections.unmodifiableMap(properties);
|
mProperties = Collections.unmodifiableMap(properties);
|
||||||
mApiVersionNumber = apiNumber;
|
mVersion = new AndroidVersion(apiLevel, codeName);
|
||||||
mApiVersionName = apiName;
|
mVersionName = versionName;
|
||||||
mRevision = revision;
|
mRevision = revision;
|
||||||
|
|
||||||
|
if (mVersion.isPreview()) {
|
||||||
|
mName = String.format(PLATFORM_NAME_PREVIEW, mVersionName);
|
||||||
|
} else {
|
||||||
|
mName = String.format(PLATFORM_NAME, mVersionName);
|
||||||
|
}
|
||||||
|
|
||||||
// pre-build the path to the platform components
|
// pre-build the path to the platform components
|
||||||
mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY);
|
mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY);
|
||||||
mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES);
|
mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES);
|
||||||
@@ -119,15 +128,15 @@ final class PlatformTarget implements IAndroidTarget {
|
|||||||
* @see com.android.sdklib.IAndroidTarget#getDescription()
|
* @see com.android.sdklib.IAndroidTarget#getDescription()
|
||||||
*/
|
*/
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return String.format("Standard Android platform %s", mApiVersionName);
|
return String.format("Standard Android platform %s", mVersionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApiVersionNumber(){
|
public AndroidVersion getVersion() {
|
||||||
return mApiVersionNumber;
|
return mVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getApiVersionName() {
|
public String getVersionName() {
|
||||||
return mApiVersionName;
|
return mVersionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRevision() {
|
public int getRevision() {
|
||||||
@@ -189,13 +198,23 @@ final class PlatformTarget implements IAndroidTarget {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the platform has a codename (ie it's a preview of an upcoming platform), then
|
||||||
|
// both platform must be exactly identical.
|
||||||
|
if (mVersion.getCodename() != null) {
|
||||||
|
return equals(target);
|
||||||
|
}
|
||||||
|
|
||||||
// target is compatible wit the receiver as long as its api version number is greater or
|
// target is compatible wit the receiver as long as its api version number is greater or
|
||||||
// equal.
|
// equal.
|
||||||
return target.getApiVersionNumber() >= mApiVersionNumber;
|
return target.getVersion().getApiLevel() >= mVersion.getApiLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String hashString() {
|
public String hashString() {
|
||||||
return String.format(PLATFORM_HASH, mApiVersionNumber);
|
if (mVersion.getCodename() != null) {
|
||||||
|
return String.format(PLATFORM_HASH_CODENAME, mVersion.getCodename());
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format(PLATFORM_HASH_API_LEVEL, mVersion.getApiLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -206,10 +225,12 @@ final class PlatformTarget implements IAndroidTarget {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj instanceof PlatformTarget) {
|
if (obj instanceof PlatformTarget) {
|
||||||
return mApiVersionNumber == ((PlatformTarget)obj).mApiVersionNumber;
|
PlatformTarget platform = (PlatformTarget)obj;
|
||||||
|
|
||||||
|
return mVersion.equals(platform.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.equals(obj);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -223,7 +244,13 @@ final class PlatformTarget implements IAndroidTarget {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mApiVersionNumber - target.getApiVersionNumber();
|
int apiDiff = mVersion.getApiLevel() - target.getVersion().getApiLevel();
|
||||||
|
|
||||||
|
if (mVersion.getCodename() != null && apiDiff == 0) {
|
||||||
|
return mVersion.getCodename().compareTo(target.getVersion().getCodename());
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- platform only methods.
|
// ---- platform only methods.
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import java.util.regex.Pattern;
|
|||||||
public final class SdkManager {
|
public final class SdkManager {
|
||||||
|
|
||||||
public final static String PROP_VERSION_SDK = "ro.build.version.sdk";
|
public final static String PROP_VERSION_SDK = "ro.build.version.sdk";
|
||||||
|
public final static String PROP_VERSION_CODENAME = "ro.build.version.codename";
|
||||||
public final static String PROP_VERSION_RELEASE = "ro.build.version.release";
|
public final static String PROP_VERSION_RELEASE = "ro.build.version.release";
|
||||||
public final static String PROP_VERSION_REVISION = "ro.build.version.incremental";
|
public final static String PROP_VERSION_REVISION = "ro.build.version.incremental";
|
||||||
|
|
||||||
@@ -263,23 +264,28 @@ public final class SdkManager {
|
|||||||
|
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
// look for some specific values in the map.
|
// look for some specific values in the map.
|
||||||
|
|
||||||
|
// version string
|
||||||
String apiName = map.get(PROP_VERSION_RELEASE);
|
String apiName = map.get(PROP_VERSION_RELEASE);
|
||||||
if (apiName == null) {
|
if (apiName == null) {
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(null,
|
log.error(null,
|
||||||
"Ignoring platform '%1$s': %2$s is missing from '%3$s'",
|
"Ignoring platform '%1$s': %2$s is missing from '%3$s'",
|
||||||
platform.getName(), PROP_VERSION_RELEASE, SdkConstants.FN_BUILD_PROP);
|
platform.getName(), PROP_VERSION_RELEASE,
|
||||||
|
SdkConstants.FN_BUILD_PROP);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// api level
|
||||||
int apiNumber;
|
int apiNumber;
|
||||||
String stringValue = map.get(PROP_VERSION_SDK);
|
String stringValue = map.get(PROP_VERSION_SDK);
|
||||||
if (stringValue == null) {
|
if (stringValue == null) {
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(null,
|
log.error(null,
|
||||||
"Ignoring platform '%1$s': %2$s is missing from '%3$s'",
|
"Ignoring platform '%1$s': %2$s is missing from '%3$s'",
|
||||||
platform.getName(), PROP_VERSION_SDK, SdkConstants.FN_BUILD_PROP);
|
platform.getName(), PROP_VERSION_SDK,
|
||||||
|
SdkConstants.FN_BUILD_PROP);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@@ -291,19 +297,28 @@ public final class SdkManager {
|
|||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(null,
|
log.error(null,
|
||||||
"Ignoring platform '%1$s': %2$s is not a valid number in %3$s.",
|
"Ignoring platform '%1$s': %2$s is not a valid number in %3$s.",
|
||||||
platform.getName(), PROP_VERSION_SDK, SdkConstants.FN_BUILD_PROP);
|
platform.getName(), PROP_VERSION_SDK,
|
||||||
|
SdkConstants.FN_BUILD_PROP);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// codename (optional)
|
||||||
|
String apiCodename = map.get(PROP_VERSION_CODENAME);
|
||||||
|
if (apiCodename != null && apiCodename.equals("REL")) {
|
||||||
|
apiCodename = null; // REL means it's a release version and therefore the
|
||||||
|
// codename is irrelevant at this point.
|
||||||
|
}
|
||||||
|
|
||||||
int revision = 1;
|
int revision = 1;
|
||||||
stringValue = map.get(PROP_VERSION_REVISION);
|
stringValue = map.get(PROP_VERSION_REVISION);
|
||||||
if (stringValue == null) {
|
if (stringValue == null) {
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(null,
|
log.error(null,
|
||||||
"Ignoring platform '%1$s': %2$s is missing from '%3$s'",
|
"Ignoring platform '%1$s': %2$s is missing from '%3$s'",
|
||||||
platform.getName(), PROP_VERSION_REVISION, SdkConstants.FN_BUILD_PROP);
|
platform.getName(), PROP_VERSION_REVISION,
|
||||||
|
SdkConstants.FN_BUILD_PROP);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@@ -346,6 +361,7 @@ public final class SdkManager {
|
|||||||
platform.getAbsolutePath(),
|
platform.getAbsolutePath(),
|
||||||
map,
|
map,
|
||||||
apiNumber,
|
apiNumber,
|
||||||
|
apiCodename,
|
||||||
apiName,
|
apiName,
|
||||||
revision);
|
revision);
|
||||||
|
|
||||||
@@ -435,8 +451,7 @@ public final class SdkManager {
|
|||||||
try {
|
try {
|
||||||
int apiValue = Integer.parseInt(api);
|
int apiValue = Integer.parseInt(api);
|
||||||
for (IAndroidTarget target : targetList) {
|
for (IAndroidTarget target : targetList) {
|
||||||
if (target.isPlatform() &&
|
if (target.isPlatform() && target.getVersion().equals(apiValue)) {
|
||||||
target.getApiVersionNumber() == apiValue) {
|
|
||||||
baseTarget = (PlatformTarget)target;
|
baseTarget = (PlatformTarget)target;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
@@ -36,13 +37,12 @@ import java.util.Properties;
|
|||||||
*/
|
*/
|
||||||
public class AddonPackage extends Package {
|
public class AddonPackage extends Package {
|
||||||
|
|
||||||
private static final String PROP_API_LEVEL = "Addon.ApiLevel"; //$NON-NLS-1$
|
|
||||||
private static final String PROP_NAME = "Addon.Name"; //$NON-NLS-1$
|
private static final String PROP_NAME = "Addon.Name"; //$NON-NLS-1$
|
||||||
private static final String PROP_VENDOR = "Addon.Vendor"; //$NON-NLS-1$
|
private static final String PROP_VENDOR = "Addon.Vendor"; //$NON-NLS-1$
|
||||||
|
|
||||||
private final String mVendor;
|
private final String mVendor;
|
||||||
private final String mName;
|
private final String mName;
|
||||||
private final int mApiLevel;
|
private final AndroidVersion mVersion;
|
||||||
|
|
||||||
/** An add-on library. */
|
/** An add-on library. */
|
||||||
public static class Lib {
|
public static class Lib {
|
||||||
@@ -74,7 +74,10 @@ public class AddonPackage extends Package {
|
|||||||
super(source, packageNode, licenses);
|
super(source, packageNode, licenses);
|
||||||
mVendor = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR);
|
mVendor = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR);
|
||||||
mName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_NAME);
|
mName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_NAME);
|
||||||
mApiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
mVersion = new AndroidVersion(
|
||||||
|
XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0),
|
||||||
|
null); // add-ons on platform previews is not supported, so the codename is always
|
||||||
|
// null in this case.
|
||||||
|
|
||||||
mLibs = parseLibs(XmlParserUtils.getFirstChild(packageNode, SdkRepository.NODE_LIBS));
|
mLibs = parseLibs(XmlParserUtils.getFirstChild(packageNode, SdkRepository.NODE_LIBS));
|
||||||
}
|
}
|
||||||
@@ -88,7 +91,7 @@ public class AddonPackage extends Package {
|
|||||||
AddonPackage(IAndroidTarget target, Properties props) {
|
AddonPackage(IAndroidTarget target, Properties props) {
|
||||||
super( null, //source
|
super( null, //source
|
||||||
props, //properties
|
props, //properties
|
||||||
0, //revision
|
target.getRevision(), //revision
|
||||||
null, //license
|
null, //license
|
||||||
target.getDescription(), //description
|
target.getDescription(), //description
|
||||||
null, //descUrl
|
null, //descUrl
|
||||||
@@ -97,7 +100,7 @@ public class AddonPackage extends Package {
|
|||||||
target.getLocation() //archiveOsPath
|
target.getLocation() //archiveOsPath
|
||||||
);
|
);
|
||||||
|
|
||||||
mApiLevel = target.getApiVersionNumber();
|
mVersion = target.getVersion();
|
||||||
mName = target.getName();
|
mName = target.getName();
|
||||||
mVendor = target.getVendor();
|
mVendor = target.getVendor();
|
||||||
|
|
||||||
@@ -114,13 +117,13 @@ public class AddonPackage extends Package {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the properties of the current packages in the given {@link Properties} object.
|
* Save the properties of the current packages in the given {@link Properties} object.
|
||||||
* These properties will later be give the constructor that takes a {@link Properties} object.
|
* These properties will later be given to a constructor that takes a {@link Properties} object.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void saveProperties(Properties props) {
|
void saveProperties(Properties props) {
|
||||||
super.saveProperties(props);
|
super.saveProperties(props);
|
||||||
|
|
||||||
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
|
mVersion.saveProperties(props);
|
||||||
props.setProperty(PROP_NAME, mName);
|
props.setProperty(PROP_NAME, mName);
|
||||||
props.setProperty(PROP_VENDOR, mVendor);
|
props.setProperty(PROP_VENDOR, mVendor);
|
||||||
}
|
}
|
||||||
@@ -165,9 +168,9 @@ public class AddonPackage extends Package {
|
|||||||
return mName;
|
return mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
|
/** Returns the version, for platform, add-on and doc packages. */
|
||||||
public int getApiLevel() {
|
public AndroidVersion getVersion() {
|
||||||
return mApiLevel;
|
return mVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the libs defined in this add-on. Can be an empty array but not null. */
|
/** Returns the libs defined in this add-on. Can be an empty array but not null. */
|
||||||
@@ -181,7 +184,7 @@ public class AddonPackage extends Package {
|
|||||||
return String.format("%1$s by %2$s for Android API %3$d",
|
return String.format("%1$s by %2$s for Android API %3$d",
|
||||||
getName(),
|
getName(),
|
||||||
getVendor(),
|
getVendor(),
|
||||||
getApiLevel());
|
mVersion.getApiLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a long description for an {@link IDescription}. */
|
/** Returns a long description for an {@link IDescription}. */
|
||||||
@@ -214,7 +217,7 @@ public class AddonPackage extends Package {
|
|||||||
// First find if this add-on is already installed. If so, reuse the same directory.
|
// First find if this add-on is already installed. If so, reuse the same directory.
|
||||||
for (IAndroidTarget target : sdkManager.getTargets()) {
|
for (IAndroidTarget target : sdkManager.getTargets()) {
|
||||||
if (!target.isPlatform() &&
|
if (!target.isPlatform() &&
|
||||||
target.getApiVersionNumber() == getApiLevel() &&
|
target.getVersion().equals(mVersion) &&
|
||||||
target.getName().equals(getName()) &&
|
target.getName().equals(getName()) &&
|
||||||
target.getVendor().equals(getVendor())) {
|
target.getVendor().equals(getVendor())) {
|
||||||
return new File(target.getLocation());
|
return new File(target.getLocation());
|
||||||
@@ -226,7 +229,7 @@ public class AddonPackage extends Package {
|
|||||||
String name = suggestedDir;
|
String name = suggestedDir;
|
||||||
|
|
||||||
if (suggestedDir == null || suggestedDir.length() == 0) {
|
if (suggestedDir == null || suggestedDir.length() == 0) {
|
||||||
name = String.format("addon-%s-%s-%d", getName(), getVendor(), getApiLevel()); //$NON-NLS-1$
|
name = String.format("addon-%s-%s-%d", getName(), getVendor(), mVersion.getApiLevel()); //$NON-NLS-1$
|
||||||
name = name.toLowerCase();
|
name = name.toLowerCase();
|
||||||
name = name.replaceAll("[^a-z0-9_-]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
|
name = name.replaceAll("[^a-z0-9_-]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
name = name.replaceAll("_+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
|
name = name.replaceAll("_+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
@@ -268,6 +271,7 @@ public class AddonPackage extends Package {
|
|||||||
String newId = newPkg.getName() + "+" + newPkg.getVendor(); //$NON-NLS-1$
|
String newId = newPkg.getName() + "+" + newPkg.getVendor(); //$NON-NLS-1$
|
||||||
|
|
||||||
return thisId.equalsIgnoreCase(newId) &&
|
return thisId.equalsIgnoreCase(newId) &&
|
||||||
|
mVersion.getApiLevel() == newPkg.getVersion().getApiLevel() &&
|
||||||
newPkg.getRevision() > this.getRevision();
|
newPkg.getRevision() > this.getRevision();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
import com.android.sdklib.internal.repository.Archive.Arch;
|
import com.android.sdklib.internal.repository.Archive.Arch;
|
||||||
@@ -33,9 +34,7 @@ import java.util.Properties;
|
|||||||
*/
|
*/
|
||||||
public class DocPackage extends Package {
|
public class DocPackage extends Package {
|
||||||
|
|
||||||
private static final String PROP_API_LEVEL = "Doc.ApiLevel"; //$NON-NLS-1$
|
private final AndroidVersion mVersion;
|
||||||
|
|
||||||
private final int mApiLevel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new doc package from the attributes and elements of the given XML node.
|
* Creates a new doc package from the attributes and elements of the given XML node.
|
||||||
@@ -44,7 +43,13 @@ public class DocPackage extends Package {
|
|||||||
*/
|
*/
|
||||||
DocPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
|
DocPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
|
||||||
super(source, packageNode, licenses);
|
super(source, packageNode, licenses);
|
||||||
mApiLevel = XmlParserUtils.getXmlInt(packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
|
||||||
|
int apiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
||||||
|
String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_CODENAME);
|
||||||
|
if (codeName.length() == 0) {
|
||||||
|
codeName = null;
|
||||||
|
}
|
||||||
|
mVersion = new AndroidVersion(apiLevel, codeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +60,7 @@ public class DocPackage extends Package {
|
|||||||
DocPackage(RepoSource source,
|
DocPackage(RepoSource source,
|
||||||
Properties props,
|
Properties props,
|
||||||
int apiLevel,
|
int apiLevel,
|
||||||
|
String codename,
|
||||||
int revision,
|
int revision,
|
||||||
String license,
|
String license,
|
||||||
String description,
|
String description,
|
||||||
@@ -71,8 +77,7 @@ public class DocPackage extends Package {
|
|||||||
archiveOs,
|
archiveOs,
|
||||||
archiveArch,
|
archiveArch,
|
||||||
archiveOsPath);
|
archiveOsPath);
|
||||||
mApiLevel = Integer.parseInt(
|
mVersion = new AndroidVersion(props, apiLevel, codename);
|
||||||
getProperty(props, PROP_API_LEVEL, Integer.toString(apiLevel)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,20 +88,23 @@ public class DocPackage extends Package {
|
|||||||
void saveProperties(Properties props) {
|
void saveProperties(Properties props) {
|
||||||
super.saveProperties(props);
|
super.saveProperties(props);
|
||||||
|
|
||||||
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
|
mVersion.saveProperties(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the api-level, an int > 0, for platform, add-on and doc packages.
|
/** Returns the version, for platform, add-on and doc packages.
|
||||||
* Can be 0 if this is a local package of unknown api-level. */
|
* Can be 0 if this is a local package of unknown api-level. */
|
||||||
public int getApiLevel() {
|
public AndroidVersion getVersion() {
|
||||||
return mApiLevel;
|
return mVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a short description for an {@link IDescription}. */
|
/** Returns a short description for an {@link IDescription}. */
|
||||||
@Override
|
@Override
|
||||||
public String getShortDescription() {
|
public String getShortDescription() {
|
||||||
if (mApiLevel != 0) {
|
if (mVersion.isPreview()) {
|
||||||
return String.format("Documentation for Android SDK, API %1$d", mApiLevel);
|
return String.format("Documentation for Android '%1$s' Preview SDK",
|
||||||
|
mVersion.getCodename());
|
||||||
|
} else if (mVersion.getApiLevel() != 0) {
|
||||||
|
return String.format("Documentation for Android SDK, API %1$d", mVersion.getApiLevel());
|
||||||
} else {
|
} else {
|
||||||
return String.format("Documentation for Android SDK");
|
return String.format("Documentation for Android SDK");
|
||||||
}
|
}
|
||||||
@@ -147,6 +155,6 @@ public class DocPackage extends Package {
|
|||||||
|
|
||||||
DocPackage newPkg = (DocPackage) replacementPackage;
|
DocPackage newPkg = (DocPackage) replacementPackage;
|
||||||
return newPkg.getRevision() > this.getRevision() &&
|
return newPkg.getRevision() > this.getRevision() &&
|
||||||
newPkg.getApiLevel() >= this.getApiLevel();
|
newPkg.getVersion().equals(this.getVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ public class LocalSdkParser {
|
|||||||
null, //source
|
null, //source
|
||||||
props, //properties
|
props, //properties
|
||||||
0, //apiLevel
|
0, //apiLevel
|
||||||
|
null, // codename
|
||||||
0, //revision
|
0, //revision
|
||||||
null, //license
|
null, //license
|
||||||
null, //description
|
null, //description
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
@@ -34,11 +35,10 @@ import java.util.Properties;
|
|||||||
*/
|
*/
|
||||||
public class PlatformPackage extends Package {
|
public class PlatformPackage extends Package {
|
||||||
|
|
||||||
private static final String PROP_API_LEVEL = "Platform.ApiLevel"; //$NON-NLS-1$
|
|
||||||
private static final String PROP_VERSION = "Platform.Version"; //$NON-NLS-1$
|
private static final String PROP_VERSION = "Platform.Version"; //$NON-NLS-1$
|
||||||
|
|
||||||
private final String mVersion;
|
private final AndroidVersion mVersion;
|
||||||
private final int mApiLevel;
|
private final String mVersionName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new platform package from the attributes and elements of the given XML node.
|
* Creates a new platform package from the attributes and elements of the given XML node.
|
||||||
@@ -47,8 +47,13 @@ public class PlatformPackage extends Package {
|
|||||||
*/
|
*/
|
||||||
PlatformPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
|
PlatformPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
|
||||||
super(source, packageNode, licenses);
|
super(source, packageNode, licenses);
|
||||||
mVersion = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VERSION);
|
mVersionName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VERSION);
|
||||||
mApiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
int apiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
||||||
|
String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_CODENAME);
|
||||||
|
if (codeName.length() == 0) {
|
||||||
|
codeName = null;
|
||||||
|
}
|
||||||
|
mVersion = new AndroidVersion(apiLevel, codeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +65,7 @@ public class PlatformPackage extends Package {
|
|||||||
PlatformPackage(IAndroidTarget target, Properties props) {
|
PlatformPackage(IAndroidTarget target, Properties props) {
|
||||||
super( null, //source
|
super( null, //source
|
||||||
props, //properties
|
props, //properties
|
||||||
0, //revision
|
target.getRevision(), //revision
|
||||||
null, //license
|
null, //license
|
||||||
target.getDescription(), //description
|
target.getDescription(), //description
|
||||||
null, //descUrl
|
null, //descUrl
|
||||||
@@ -69,38 +74,43 @@ public class PlatformPackage extends Package {
|
|||||||
target.getLocation() //archiveOsPath
|
target.getLocation() //archiveOsPath
|
||||||
);
|
);
|
||||||
|
|
||||||
mApiLevel = target.getApiVersionNumber();
|
mVersion = target.getVersion();
|
||||||
mVersion = target.getApiVersionName();
|
mVersionName = target.getVersionName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the properties of the current packages in the given {@link Properties} object.
|
* Save the properties of the current packages in the given {@link Properties} object.
|
||||||
* These properties will later be give the constructor that takes a {@link Properties} object.
|
* These properties will later be given to a constructor that takes a {@link Properties} object.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void saveProperties(Properties props) {
|
void saveProperties(Properties props) {
|
||||||
super.saveProperties(props);
|
super.saveProperties(props);
|
||||||
|
|
||||||
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
|
mVersion.saveProperties(props);
|
||||||
props.setProperty(PROP_VERSION, mVersion);
|
props.setProperty(PROP_VERSION, mVersionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the version, a string, for platform packages. */
|
/** Returns the version, a string, for platform packages. */
|
||||||
public String getVersion() {
|
public String getVersionName() {
|
||||||
return mVersion;
|
return mVersionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
|
/** Returns the package version, for platform, add-on and doc packages. */
|
||||||
public int getApiLevel() {
|
public AndroidVersion getVersion() {
|
||||||
return mApiLevel;
|
return mVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a short description for an {@link IDescription}. */
|
/** Returns a short description for an {@link IDescription}. */
|
||||||
@Override
|
@Override
|
||||||
public String getShortDescription() {
|
public String getShortDescription() {
|
||||||
|
if (mVersion.isPreview()) {
|
||||||
|
return String.format("SDK Platform Android %1$s (Preview)",
|
||||||
|
getVersionName());
|
||||||
|
}
|
||||||
|
|
||||||
return String.format("SDK Platform Android %1$s, API %2$d",
|
return String.format("SDK Platform Android %1$s, API %2$d",
|
||||||
getVersion(),
|
getVersionName(),
|
||||||
getApiLevel());
|
mVersion.getApiLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a long description for an {@link IDescription}. */
|
/** Returns a long description for an {@link IDescription}. */
|
||||||
@@ -128,17 +138,17 @@ public class PlatformPackage extends Package {
|
|||||||
@Override
|
@Override
|
||||||
public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
|
public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
|
||||||
|
|
||||||
// First find if this add-on is already installed. If so, reuse the same directory.
|
// First find if this platform is already installed. If so, reuse the same directory.
|
||||||
for (IAndroidTarget target : sdkManager.getTargets()) {
|
for (IAndroidTarget target : sdkManager.getTargets()) {
|
||||||
if (target.isPlatform() &&
|
if (target.isPlatform() &&
|
||||||
target.getApiVersionNumber() == getApiLevel() &&
|
target.getVersion().equals(mVersion) &&
|
||||||
target.getApiVersionName().equals(getVersion())) {
|
target.getVersionName().equals(getVersionName())) {
|
||||||
return new File(target.getLocation());
|
return new File(target.getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS);
|
File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS);
|
||||||
File folder = new File(platforms, String.format("android-%s", getVersion())); //$NON-NLS-1$
|
File folder = new File(platforms, String.format("android-%s", getVersionName())); //$NON-NLS-1$
|
||||||
|
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
@@ -162,8 +172,8 @@ public class PlatformPackage extends Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlatformPackage newPkg = (PlatformPackage) replacementPackage;
|
PlatformPackage newPkg = (PlatformPackage) replacementPackage;
|
||||||
return newPkg.getVersion().equalsIgnoreCase(this.getVersion()) &&
|
return newPkg.getVersionName().equalsIgnoreCase(this.getVersionName()) &&
|
||||||
newPkg.getApiLevel() == this.getApiLevel() &&
|
newPkg.getVersion().equals(this.getVersion()) &&
|
||||||
newPkg.getRevision() > this.getRevision();
|
newPkg.getRevision() > this.getRevision();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class SdkRepository {
|
|||||||
|
|
||||||
/** The URL of the official Google sdk-repository site. */
|
/** The URL of the official Google sdk-repository site. */
|
||||||
public static final String URL_GOOGLE_SDK_REPO_SITE =
|
public static final String URL_GOOGLE_SDK_REPO_SITE =
|
||||||
"https://dl.google.com/android/repository/"; //$NON-NLS-1$
|
"https://dl-ssl.google.com/android/repository/"; //$NON-NLS-1$
|
||||||
|
|
||||||
public static final String URL_DEFAULT_XML_FILE = "repository.xml"; //$NON-NLS-1$
|
public static final String URL_DEFAULT_XML_FILE = "repository.xml"; //$NON-NLS-1$
|
||||||
|
|
||||||
@@ -63,6 +63,8 @@ public class SdkRepository {
|
|||||||
public static final String NODE_VERSION = "version"; //$NON-NLS-1$
|
public static final String NODE_VERSION = "version"; //$NON-NLS-1$
|
||||||
/** The api-level, an int > 0, for platform, add-on and doc packages. */
|
/** The api-level, an int > 0, for platform, add-on and doc packages. */
|
||||||
public static final String NODE_API_LEVEL = "api-level"; //$NON-NLS-1$
|
public static final String NODE_API_LEVEL = "api-level"; //$NON-NLS-1$
|
||||||
|
/** The codename, a string, for platform packages. */
|
||||||
|
public static final String NODE_CODENAME = "codename"; //$NON-NLS-1$
|
||||||
/** The vendor, a string, for add-on packages. */
|
/** The vendor, a string, for add-on packages. */
|
||||||
public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$
|
public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$
|
||||||
/** The name, a string, for add-on packages or for libraries. */
|
/** The name, a string, for add-on packages or for libraries. */
|
||||||
|
|||||||
@@ -52,6 +52,8 @@
|
|||||||
<xsd:element name="version" type="xsd:normalizedString" />
|
<xsd:element name="version" type="xsd:normalizedString" />
|
||||||
<!-- The Android API Level for the platform. An int > 0. -->
|
<!-- The Android API Level for the platform. An int > 0. -->
|
||||||
<xsd:element name="api-level" type="xsd:positiveInteger" />
|
<xsd:element name="api-level" type="xsd:positiveInteger" />
|
||||||
|
<!-- The optional codename for this platform, if it's a preview. -->
|
||||||
|
<xsd:element name="codename" type="xsd:string" minOccurs="0" />
|
||||||
|
|
||||||
<!-- The revision, an int > 0, incremented each time a new
|
<!-- The revision, an int > 0, incremented each time a new
|
||||||
package is generated. -->
|
package is generated. -->
|
||||||
@@ -156,6 +158,8 @@
|
|||||||
<xsd:all>
|
<xsd:all>
|
||||||
<!-- The Android API Level for the documentation. An int > 0. -->
|
<!-- The Android API Level for the documentation. An int > 0. -->
|
||||||
<xsd:element name="api-level" type="xsd:positiveInteger" />
|
<xsd:element name="api-level" type="xsd:positiveInteger" />
|
||||||
|
<!-- The optional codename for this doc, if it's a preview. -->
|
||||||
|
<xsd:element name="codename" type="xsd:string" minOccurs="0" />
|
||||||
|
|
||||||
<!-- The revision, an int > 0, incremented each time a new
|
<!-- The revision, an int > 0, incremented each time a new
|
||||||
package is generated. -->
|
package is generated. -->
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.android.sdklib.repository;
|
package com.android.sdklib.repository;
|
||||||
|
|
||||||
import com.android.sdklib.SdkConstants;
|
|
||||||
|
|
||||||
import org.xml.sax.ErrorHandler;
|
import org.xml.sax.ErrorHandler;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.SAXParseException;
|
import org.xml.sax.SAXParseException;
|
||||||
|
|||||||
@@ -157,6 +157,24 @@
|
|||||||
<sdk:uses-license ref="license2" />
|
<sdk:uses-license ref="license2" />
|
||||||
</sdk:add-on>
|
</sdk:add-on>
|
||||||
|
|
||||||
|
<sdk:platform>
|
||||||
|
<sdk:version>Pastry</sdk:version>
|
||||||
|
<sdk:api-level>5</sdk:api-level>
|
||||||
|
<sdk:codename>Pastry</sdk:codename>
|
||||||
|
<sdk:revision>3</sdk:revision>
|
||||||
|
<sdk:uses-license ref="license1" />
|
||||||
|
<sdk:description>Preview version for Pastry</sdk:description>
|
||||||
|
<sdk:desc-url>http://www.example.com/platform1.html</sdk:desc-url>
|
||||||
|
<!-- The archives node is mandatory and it cannot be empty. -->
|
||||||
|
<sdk:archives>
|
||||||
|
<sdk:archive os="any">
|
||||||
|
<sdk:size>65536</sdk:size>
|
||||||
|
<sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
|
||||||
|
<sdk:url>http://www.example.com/files/plat1.zip</sdk:url>
|
||||||
|
</sdk:archive>
|
||||||
|
</sdk:archives>
|
||||||
|
</sdk:platform>
|
||||||
|
|
||||||
<sdk:tool>
|
<sdk:tool>
|
||||||
<sdk:revision>1</sdk:revision>
|
<sdk:revision>1</sdk:revision>
|
||||||
<sdk:description>Some optional description</sdk:description>
|
<sdk:description>Some optional description</sdk:description>
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ public class AvdManagerPage extends Composite implements ISdkListener {
|
|||||||
Label label = new Label(parent, SWT.NONE);
|
Label label = new Label(parent, SWT.NONE);
|
||||||
label.setText("List of existing Android Virtual Devices:");
|
label.setText("List of existing Android Virtual Devices:");
|
||||||
|
|
||||||
mAvdSelector = new AvdSelector(parent, mUpdaterData.getAvdManager(), DisplayMode.MANAGER);
|
mAvdSelector = new AvdSelector(parent,
|
||||||
|
mUpdaterData.getOsSdkRoot(),
|
||||||
|
mUpdaterData.getAvdManager(),
|
||||||
|
DisplayMode.MANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.android.sdklib.internal.repository.RepoSource;
|
|||||||
import com.android.sdklib.internal.repository.RepoSources;
|
import com.android.sdklib.internal.repository.RepoSources;
|
||||||
import com.android.sdklib.repository.SdkRepository;
|
import com.android.sdklib.repository.SdkRepository;
|
||||||
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
||||||
|
import com.android.sdkuilib.internal.tasks.ProgressTaskFactory;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.custom.SashForm;
|
import org.eclipse.swt.custom.SashForm;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.sdkuilib.internal.repository;
|
package com.android.sdkuilib.internal.tasks;
|
||||||
|
|
||||||
import com.android.sdklib.internal.repository.ITaskMonitor;
|
import com.android.sdklib.internal.repository.ITaskMonitor;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.sdkuilib.internal.repository;
|
package com.android.sdkuilib.internal.tasks;
|
||||||
|
|
||||||
import com.android.sdklib.internal.repository.ITask;
|
import com.android.sdklib.internal.repository.ITask;
|
||||||
import com.android.sdklib.internal.repository.ITaskMonitor;
|
import com.android.sdklib.internal.repository.ITaskMonitor;
|
||||||
@@ -26,7 +26,7 @@ import org.eclipse.swt.widgets.Shell;
|
|||||||
/**
|
/**
|
||||||
* An {@link ITaskMonitor} that displays a {@link ProgressDialog}.
|
* An {@link ITaskMonitor} that displays a {@link ProgressDialog}.
|
||||||
*/
|
*/
|
||||||
class ProgressTask implements ITaskMonitor {
|
public final class ProgressTask implements ITaskMonitor {
|
||||||
|
|
||||||
private static final double MAX_COUNT = 10000.0;
|
private static final double MAX_COUNT = 10000.0;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.sdkuilib.internal.repository;
|
package com.android.sdkuilib.internal.tasks;
|
||||||
|
|
||||||
import com.android.sdklib.internal.repository.ITask;
|
import com.android.sdklib.internal.repository.ITask;
|
||||||
import com.android.sdklib.internal.repository.ITaskFactory;
|
import com.android.sdklib.internal.repository.ITaskFactory;
|
||||||
@@ -25,7 +25,7 @@ import org.eclipse.swt.widgets.Shell;
|
|||||||
* An {@link ITaskFactory} that creates a new {@link ProgressTask} dialog
|
* An {@link ITaskFactory} that creates a new {@link ProgressTask} dialog
|
||||||
* for each new task.
|
* for each new task.
|
||||||
*/
|
*/
|
||||||
public class ProgressTaskFactory implements ITaskFactory {
|
public final class ProgressTaskFactory implements ITaskFactory {
|
||||||
|
|
||||||
private final Shell mShell;
|
private final Shell mShell;
|
||||||
|
|
||||||
@@ -19,7 +19,6 @@ package com.android.sdkuilib.internal.widgets;
|
|||||||
import com.android.prefs.AndroidLocation;
|
import com.android.prefs.AndroidLocation;
|
||||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.ISdkLog;
|
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
import com.android.sdklib.internal.avd.AvdManager;
|
import com.android.sdklib.internal.avd.AvdManager;
|
||||||
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
||||||
@@ -274,14 +273,14 @@ final class AvdCreationDialog extends Dialog {
|
|||||||
for (IAndroidTarget target : sdkManager.getTargets()) {
|
for (IAndroidTarget target : sdkManager.getTargets()) {
|
||||||
String name;
|
String name;
|
||||||
if (target.isPlatform()) {
|
if (target.isPlatform()) {
|
||||||
name = String.format("%s - API Level %d",
|
name = String.format("%s - API Level %s",
|
||||||
target.getName(),
|
target.getName(),
|
||||||
target.getApiVersionNumber());
|
target.getVersion().getApiString());
|
||||||
} else {
|
} else {
|
||||||
name = String.format("%s (%s) - API Level %d",
|
name = String.format("%s (%s) - API Level %s",
|
||||||
target.getName(),
|
target.getName(),
|
||||||
target.getVendor(),
|
target.getVendor(),
|
||||||
target.getApiVersionNumber());
|
target.getVersion().getApiString());
|
||||||
}
|
}
|
||||||
mCurrentTargets.put(name, target);
|
mCurrentTargets.put(name, target);
|
||||||
mTargetCombo.add(name);
|
mTargetCombo.add(name);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.sdkuilib.internal.widgets;
|
package com.android.sdkuilib.internal.widgets;
|
||||||
|
|
||||||
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.internal.avd.AvdManager;
|
import com.android.sdklib.internal.avd.AvdManager;
|
||||||
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
||||||
@@ -106,8 +107,9 @@ final class AvdDetailsDialog extends Dialog {
|
|||||||
displayValue(c, "Error:", mAvdInfo.getErrorMessage());
|
displayValue(c, "Error:", mAvdInfo.getErrorMessage());
|
||||||
} else {
|
} else {
|
||||||
IAndroidTarget target = mAvdInfo.getTarget();
|
IAndroidTarget target = mAvdInfo.getTarget();
|
||||||
displayValue(c, "Target:", String.format("%s (API level %d)",
|
AndroidVersion version = target.getVersion();
|
||||||
target.getName(), target.getApiVersionNumber()));
|
displayValue(c, "Target:", String.format("%s (API level %s)",
|
||||||
|
target.getName(), version.getApiString()));
|
||||||
|
|
||||||
// display some extra values.
|
// display some extra values.
|
||||||
Map<String, String> properties = mAvdInfo.getProperties();
|
Map<String, String> properties = mAvdInfo.getProperties();
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ import com.android.prefs.AndroidLocation.AndroidLocationException;
|
|||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.ISdkLog;
|
import com.android.sdklib.ISdkLog;
|
||||||
import com.android.sdklib.NullSdkLog;
|
import com.android.sdklib.NullSdkLog;
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.internal.avd.AvdManager;
|
import com.android.sdklib.internal.avd.AvdManager;
|
||||||
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
|
||||||
import com.android.sdklib.internal.avd.AvdManager.AvdInfo.AvdStatus;
|
import com.android.sdklib.internal.avd.AvdManager.AvdInfo.AvdStatus;
|
||||||
|
import com.android.sdklib.internal.repository.ITask;
|
||||||
|
import com.android.sdklib.internal.repository.ITaskMonitor;
|
||||||
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
||||||
|
import com.android.sdkuilib.internal.tasks.ProgressTask;
|
||||||
import com.android.sdkuilib.repository.UpdaterWindow;
|
import com.android.sdkuilib.repository.UpdaterWindow;
|
||||||
|
|
||||||
import org.eclipse.jface.dialogs.MessageDialog;
|
import org.eclipse.jface.dialogs.MessageDialog;
|
||||||
@@ -49,16 +53,19 @@ import org.eclipse.swt.widgets.Table;
|
|||||||
import org.eclipse.swt.widgets.TableColumn;
|
import org.eclipse.swt.widgets.TableColumn;
|
||||||
import org.eclipse.swt.widgets.TableItem;
|
import org.eclipse.swt.widgets.TableItem;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The AVD selector is a table that is added to the given parent composite.
|
* The AVD selector is a table that is added to the given parent composite.
|
||||||
* <p/>
|
* <p/>
|
||||||
* To use, create it using {@link #AvdSelector(Composite, AvdManager, DisplayMode)} then
|
* After using one of the constructors, call {@link #setSelection(AvdInfo)},
|
||||||
* call {@link #setSelection(AvdInfo)}, {@link #setSelectionListener(SelectionListener)}
|
* {@link #setSelectionListener(SelectionListener)} and finally use
|
||||||
* and finally use {@link #getSelected()} to retrieve the selection.
|
* {@link #getSelected()} to retrieve the selection.
|
||||||
*/
|
*/
|
||||||
public final class AvdSelector {
|
public final class AvdSelector {
|
||||||
private static int NUM_COL = 2;
|
private static int NUM_COL = 2;
|
||||||
@@ -66,6 +73,7 @@ public final class AvdSelector {
|
|||||||
private final DisplayMode mDisplayMode;
|
private final DisplayMode mDisplayMode;
|
||||||
|
|
||||||
private AvdManager mAvdManager;
|
private AvdManager mAvdManager;
|
||||||
|
private final String mOsSdkPath;
|
||||||
|
|
||||||
private Table mTable;
|
private Table mTable;
|
||||||
private Button mDeleteButton;
|
private Button mDeleteButton;
|
||||||
@@ -74,16 +82,20 @@ public final class AvdSelector {
|
|||||||
private Button mRefreshButton;
|
private Button mRefreshButton;
|
||||||
private Button mManagerButton;
|
private Button mManagerButton;
|
||||||
private Button mUpdateButton;
|
private Button mUpdateButton;
|
||||||
|
private Button mStartButton;
|
||||||
|
|
||||||
private SelectionListener mSelectionListener;
|
private SelectionListener mSelectionListener;
|
||||||
private IAvdFilter mTargetFilter;
|
private IAvdFilter mTargetFilter;
|
||||||
|
|
||||||
|
/** Defaults to true. Changed by the {@link #setEnabled(boolean)} method to represent the
|
||||||
|
* "global" enabled state on this composite. */
|
||||||
private boolean mIsEnabled = true;
|
private boolean mIsEnabled = true;
|
||||||
|
|
||||||
private ImageFactory mImageFactory;
|
private ImageFactory mImageFactory;
|
||||||
private Image mOkImage;
|
private Image mOkImage;
|
||||||
private Image mBrokenImage;
|
private Image mBrokenImage;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The display mode of the AVD Selector.
|
* The display mode of the AVD Selector.
|
||||||
*/
|
*/
|
||||||
@@ -170,15 +182,20 @@ public final class AvdSelector {
|
|||||||
* {@link IAndroidTarget} will be displayed.
|
* {@link IAndroidTarget} will be displayed.
|
||||||
*
|
*
|
||||||
* @param parent The parent composite where the selector will be added.
|
* @param parent The parent composite where the selector will be added.
|
||||||
|
* @param osSdkPath The SDK root path. When not null, enables the start button to start
|
||||||
|
* an emulator on a given AVD.
|
||||||
* @param manager the AVD manager.
|
* @param manager the AVD manager.
|
||||||
* @param filter When non-null, will allow filtering the AVDs to display.
|
* @param filter When non-null, will allow filtering the AVDs to display.
|
||||||
* @param extraAction When non-null, displays an extra action button.
|
|
||||||
* @param displayMode The display mode ({@link DisplayMode}).
|
* @param displayMode The display mode ({@link DisplayMode}).
|
||||||
|
*
|
||||||
|
* TODO: pass an ISdkLog and use it when reloading, starting the emulator, etc.
|
||||||
*/
|
*/
|
||||||
public AvdSelector(Composite parent,
|
public AvdSelector(Composite parent,
|
||||||
|
String osSdkPath,
|
||||||
AvdManager manager,
|
AvdManager manager,
|
||||||
IAvdFilter filter,
|
IAvdFilter filter,
|
||||||
DisplayMode displayMode) {
|
DisplayMode displayMode) {
|
||||||
|
mOsSdkPath = osSdkPath;
|
||||||
mAvdManager = manager;
|
mAvdManager = manager;
|
||||||
mTargetFilter = filter;
|
mTargetFilter = filter;
|
||||||
mDisplayMode = displayMode;
|
mDisplayMode = displayMode;
|
||||||
@@ -265,6 +282,17 @@ public final class AvdSelector {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mStartButton = new Button(buttons, SWT.PUSH | SWT.FLAT);
|
||||||
|
mStartButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
mStartButton.setText("Start...");
|
||||||
|
mStartButton.setToolTipText("Starts the selected AVD.");
|
||||||
|
mStartButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent arg0) {
|
||||||
|
onStart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Composite padding = new Composite(buttons, SWT.NONE);
|
Composite padding = new Composite(buttons, SWT.NONE);
|
||||||
padding.setLayoutData(new GridData(GridData.FILL_VERTICAL));
|
padding.setLayoutData(new GridData(GridData.FILL_VERTICAL));
|
||||||
|
|
||||||
@@ -327,9 +355,11 @@ public final class AvdSelector {
|
|||||||
* @param manager the AVD manager.
|
* @param manager the AVD manager.
|
||||||
* @param displayMode The display mode ({@link DisplayMode}).
|
* @param displayMode The display mode ({@link DisplayMode}).
|
||||||
*/
|
*/
|
||||||
public AvdSelector(Composite parent, AvdManager manager,
|
public AvdSelector(Composite parent,
|
||||||
|
String osSdkPath,
|
||||||
|
AvdManager manager,
|
||||||
DisplayMode displayMode) {
|
DisplayMode displayMode) {
|
||||||
this(parent, manager, (IAvdFilter)null /* filter */, displayMode);
|
this(parent, osSdkPath, manager, (IAvdFilter)null /* filter */, displayMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -344,10 +374,11 @@ public final class AvdSelector {
|
|||||||
* @param displayMode The display mode ({@link DisplayMode}).
|
* @param displayMode The display mode ({@link DisplayMode}).
|
||||||
*/
|
*/
|
||||||
public AvdSelector(Composite parent,
|
public AvdSelector(Composite parent,
|
||||||
|
String osSdkPath,
|
||||||
AvdManager manager,
|
AvdManager manager,
|
||||||
IAndroidTarget filter,
|
IAndroidTarget filter,
|
||||||
DisplayMode displayMode) {
|
DisplayMode displayMode) {
|
||||||
this(parent, manager, new TargetBasedFilter(filter), displayMode);
|
this(parent, osSdkPath, manager, new TargetBasedFilter(filter), displayMode);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sets the table grid layout data.
|
* Sets the table grid layout data.
|
||||||
@@ -373,7 +404,6 @@ public final class AvdSelector {
|
|||||||
* This must be called from the UI thread.
|
* This must be called from the UI thread.
|
||||||
*
|
*
|
||||||
* @param reload if true, the AVD manager will reload the AVD from the disk.
|
* @param reload if true, the AVD manager will reload the AVD from the disk.
|
||||||
* @throws AndroidLocationException if reload the AVD failed.
|
|
||||||
* @return false if the reloading failed. This is always true if <var>reload</var> is
|
* @return false if the reloading failed. This is always true if <var>reload</var> is
|
||||||
* <code>false</code>.
|
* <code>false</code>.
|
||||||
*/
|
*/
|
||||||
@@ -693,8 +723,8 @@ public final class AvdSelector {
|
|||||||
IAndroidTarget target = avd.getTarget();
|
IAndroidTarget target = avd.getTarget();
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
item.setText(1, target.getFullName());
|
item.setText(1, target.getFullName());
|
||||||
item.setText(2, target.getApiVersionName());
|
item.setText(2, target.getVersionName());
|
||||||
item.setText(3, Integer.toString(target.getApiVersionNumber()));
|
item.setText(3, target.getVersion().getApiString());
|
||||||
} else {
|
} else {
|
||||||
item.setText(1, "?");
|
item.setText(1, "?");
|
||||||
item.setText(2, "?");
|
item.setText(2, "?");
|
||||||
@@ -735,11 +765,13 @@ public final class AvdSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the enable state of the Details, Delete and Update buttons.
|
* Updates the enable state of the Details, Start, Delete and Update buttons.
|
||||||
*/
|
*/
|
||||||
private void enableActionButtons() {
|
private void enableActionButtons() {
|
||||||
if (mIsEnabled == false) {
|
if (mIsEnabled == false) {
|
||||||
mDetailsButton.setEnabled(false);
|
mDetailsButton.setEnabled(false);
|
||||||
|
mStartButton.setEnabled(false);
|
||||||
|
|
||||||
if (mDeleteButton != null) {
|
if (mDeleteButton != null) {
|
||||||
mDeleteButton.setEnabled(false);
|
mDeleteButton.setEnabled(false);
|
||||||
}
|
}
|
||||||
@@ -748,13 +780,18 @@ public final class AvdSelector {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AvdInfo selection = getTableSelection();
|
AvdInfo selection = getTableSelection();
|
||||||
|
boolean hasSelection = selection != null;
|
||||||
|
|
||||||
|
mDetailsButton.setEnabled(hasSelection);
|
||||||
|
mStartButton.setEnabled(mOsSdkPath != null &&
|
||||||
|
hasSelection &&
|
||||||
|
selection.getStatus() == AvdStatus.OK);
|
||||||
|
|
||||||
mDetailsButton.setEnabled(selection != null);
|
|
||||||
if (mDeleteButton != null) {
|
if (mDeleteButton != null) {
|
||||||
mDeleteButton.setEnabled(selection != null);
|
mDeleteButton.setEnabled(hasSelection);
|
||||||
}
|
}
|
||||||
if (mUpdateButton != null) {
|
if (mUpdateButton != null) {
|
||||||
mUpdateButton.setEnabled(selection != null &&
|
mUpdateButton.setEnabled(hasSelection &&
|
||||||
selection.getStatus() == AvdStatus.ERROR_IMAGE_DIR);
|
selection.getStatus() == AvdStatus.ERROR_IMAGE_DIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -849,6 +886,113 @@ public final class AvdSelector {
|
|||||||
refresh(true /*reload*/); // UpdaterWindow uses its own AVD manager so this one must reload.
|
refresh(true /*reload*/); // UpdaterWindow uses its own AVD manager so this one must reload.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onStart() {
|
||||||
|
AvdInfo avdInfo = getTableSelection();
|
||||||
|
|
||||||
|
if (avdInfo == null || mOsSdkPath == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = mOsSdkPath +
|
||||||
|
File.separator +
|
||||||
|
SdkConstants.OS_SDK_TOOLS_FOLDER +
|
||||||
|
SdkConstants.FN_EMULATOR;
|
||||||
|
|
||||||
|
final String avdName = avdInfo.getName();
|
||||||
|
|
||||||
|
// build the command line based on the available parameters.
|
||||||
|
ArrayList<String> list = new ArrayList<String>();
|
||||||
|
list.add(path);
|
||||||
|
list.add("-avd"); //$NON-NLS-1$
|
||||||
|
list.add(avdName);
|
||||||
|
|
||||||
|
// convert the list into an array for the call to exec.
|
||||||
|
final String[] command = list.toArray(new String[list.size()]);
|
||||||
|
|
||||||
|
// launch the emulator
|
||||||
|
new ProgressTask(mTable.getShell(),
|
||||||
|
"Starting Android Emulator",
|
||||||
|
new ITask() {
|
||||||
|
public void run(ITaskMonitor monitor) {
|
||||||
|
try {
|
||||||
|
monitor.setDescription("Starting emualator for AVD '%1$s'", avdName);
|
||||||
|
int n = 10;
|
||||||
|
monitor.setProgressMax(n);
|
||||||
|
Process process = Runtime.getRuntime().exec(command);
|
||||||
|
grabEmulatorOutput(process, monitor);
|
||||||
|
|
||||||
|
// This small wait prevents the dialog from closing too fast:
|
||||||
|
// When it works, the emulator returns immediately, even if no UI
|
||||||
|
// is shown yet. And when it fails (because the AVD is locked/running)
|
||||||
|
// if we don't have a wait we don't capture the error for some reason.
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
monitor.incProgress(1);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
monitor.setResult("Failed to start emulator: %1$s", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stderr/stdout outputs of a process and return when the process is done.
|
||||||
|
* Both <b>must</b> be read or the process will block on windows.
|
||||||
|
* @param process The process to get the output from.
|
||||||
|
* @param monitor An {@link ISdkLog} to capture errors.
|
||||||
|
*/
|
||||||
|
private void grabEmulatorOutput(final Process process, final ITaskMonitor monitor) {
|
||||||
|
// read the lines as they come. if null is returned, it's because the process finished
|
||||||
|
new Thread("emu-stderr") { //$NON-NLS-1$
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// create a buffer to read the stderr output
|
||||||
|
InputStreamReader is = new InputStreamReader(process.getErrorStream());
|
||||||
|
BufferedReader errReader = new BufferedReader(is);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
String line = errReader.readLine();
|
||||||
|
if (line != null) {
|
||||||
|
monitor.setResult("%1$s", line); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
new Thread("emu-stdout") { //$NON-NLS-1$
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
InputStreamReader is = new InputStreamReader(process.getInputStream());
|
||||||
|
BufferedReader outReader = new BufferedReader(is);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
String line = outReader.readLine();
|
||||||
|
if (line != null) {
|
||||||
|
monitor.setResult("%1$s", line); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects all log from the AVD action and displays it in a dialog.
|
* Collects all log from the AVD action and displays it in a dialog.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -323,8 +323,8 @@ public class SdkTargetSelector {
|
|||||||
item.setData(target);
|
item.setData(target);
|
||||||
item.setText(0, target.getName());
|
item.setText(0, target.getName());
|
||||||
item.setText(1, target.getVendor());
|
item.setText(1, target.getVendor());
|
||||||
item.setText(2, target.getApiVersionName());
|
item.setText(2, target.getVersionName());
|
||||||
item.setText(3, Integer.toString(target.getApiVersionNumber()));
|
item.setText(3, target.getVersion().getApiString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
table.setEnabled(false);
|
table.setEnabled(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user