am 9d0a4a6e: am 5f3ed7dd: am 80bc4f93: Merge "Refresh 64-bit headers/libs (WW20)"
* commit '9d0a4a6eca86933e9cd1fd60ba8cc0abae351b2a':
Refresh 64-bit headers/libs (WW20)
diff --git a/apps/Development/res/layout/connectivity.xml b/apps/Development/res/layout/connectivity.xml
index 53f1ed7..2aaf6c6 100644
--- a/apps/Development/res/layout/connectivity.xml
+++ b/apps/Development/res/layout/connectivity.xml
@@ -219,6 +219,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start_tdls" />
+ <Button android:id="@+id/stopTdls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/stop_tdls" />
+ </LinearLayout>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -227,10 +236,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minEms="10" />
- <Button android:id="@+id/stopTdls"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/stop_tdls" />
</LinearLayout>
<!-- divider line -->
@@ -279,6 +284,14 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/netid" />
+ <EditText android:id="@+id/netid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minEms="5" />
<Button android:id="@+id/add_default_route"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/apps/Development/res/values/strings.xml b/apps/Development/res/values/strings.xml
index ced7b72..0c13987 100644
--- a/apps/Development/res/values/strings.xml
+++ b/apps/Development/res/values/strings.xml
@@ -43,6 +43,7 @@
<string name="start_hipri">Start HiPri</string>
<string name="stop_hipri">Stop HiPri</string>
<string name="crash">CRASH</string>
+ <string name="netid">NetId</string>
<string name="add_default_route">Add Default Route</string>
<string name="remove_default_route">Remove Default Route</string>
<string name="default_request">Make a http request</string>
diff --git a/apps/Development/src/com/android/development/Connectivity.java b/apps/Development/src/com/android/development/Connectivity.java
index 7d4491b..55e5350 100644
--- a/apps/Development/src/com/android/development/Connectivity.java
+++ b/apps/Development/src/com/android/development/Connectivity.java
@@ -524,7 +524,8 @@
private void onAddDefaultRoute() {
try {
- mNetd.addRoute("eth0", new RouteInfo(null,
+ int netId = Integer.valueOf(((TextView) findViewById(R.id.netid)).getText().toString());
+ mNetd.addRoute(netId, new RouteInfo(null,
NetworkUtils.numericToInetAddress("8.8.8.8")));
} catch (Exception e) {
Log.e(TAG, "onAddDefaultRoute got exception: " + e.toString());
@@ -533,7 +534,8 @@
private void onRemoveDefaultRoute() {
try {
- mNetd.removeRoute("eth0", new RouteInfo(null,
+ int netId = Integer.valueOf(((TextView) findViewById(R.id.netid)).getText().toString());
+ mNetd.removeRoute(netId, new RouteInfo(null,
NetworkUtils.numericToInetAddress("8.8.8.8")));
} catch (Exception e) {
Log.e(TAG, "onRemoveDefaultRoute got exception: " + e.toString());
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-az-rAZ/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-az-rAZ/strings.xml
index d59ae53..8e1956a 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-az-rAZ/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Son çarə"</string>
+ <string name="title" msgid="8156274565006125136">"Dəstəklənməyən fəaliyyət"</string>
+ <string name="error" msgid="6539615832923362301">"Bu fəaliyyət hazırda dəstəklənmir."</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-az/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-az/strings.xml
index d59ae53..8e1956a 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-az/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Son çarə"</string>
+ <string name="title" msgid="8156274565006125136">"Dəstəklənməyən fəaliyyət"</string>
+ <string name="error" msgid="6539615832923362301">"Bu fəaliyyət hazırda dəstəklənmir."</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-en-rIN/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-en-rIN/strings.xml
index d59ae53..a7c82cb 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-en-rIN/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"Unsupported action"</string>
+ <string name="error" msgid="6539615832923362301">"That action is not currently supported."</string>
</resources>
diff --git a/apps/Fallback/res/values-et/strings.xml b/apps/Fallback/res/values-et-rEE/strings.xml
similarity index 100%
rename from apps/Fallback/res/values-et/strings.xml
rename to apps/Fallback/res/values-et-rEE/strings.xml
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-fr-rCA/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-fr-rCA/strings.xml
index d59ae53..a751b97 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Application de secours"</string>
+ <string name="title" msgid="8156274565006125136">"Action non prise en charge"</string>
+ <string name="error" msgid="6539615832923362301">"Cette action n\'est actuellement pas prise en charge."</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-hy-rAM/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-hy-rAM/strings.xml
index d59ae53..1547741 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-hy-rAM/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"Չաջակցվող գործողություն"</string>
+ <string name="error" msgid="6539615832923362301">"Այդ գործողությունն այժմ չի աջակցվում:"</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-ka-rGE/strings.xml
similarity index 65%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-ka-rGE/strings.xml
index d59ae53..469a135 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-ka-rGE/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"შემოვლით რეჟიმში გადასვლა"</string>
+ <string name="title" msgid="8156274565006125136">"მოქმედება მხარდაჭერილი არ არის"</string>
+ <string name="error" msgid="6539615832923362301">"ეს მოქმედება ამჟამად მხარდაუჭერელია."</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-km-rKH/strings.xml
similarity index 66%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-km-rKH/strings.xml
index d59ae53..a442335 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-km-rKH/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"សកម្មភាពមិនបានគាំទ្រ"</string>
+ <string name="error" msgid="6539615832923362301">"បច្ចុប្បន្នសកម្មភាពនោះមិនត្រូវបានគាំទ្រទេ។"</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-lo-rLA/strings.xml
similarity index 69%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-lo-rLA/strings.xml
index d59ae53..948b60f 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-lo-rLA/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"ການເຮັດວຽກທີ່ບໍ່ຮອງຮັບ"</string>
+ <string name="error" msgid="6539615832923362301">"ການເຮັດວຽກນັ້ນຍັງບໍ່ຮອງຮັບເທື່ອ"</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-mn-rMN/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-mn-rMN/strings.xml
index d59ae53..8cb3870 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-mn-rMN/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"Дэмжигдээгүй үйлдэл"</string>
+ <string name="error" msgid="6539615832923362301">"Энэ үйлдэл одоогоор дэмжигдээгүй."</string>
</resources>
diff --git a/apps/Fallback/res/values-ms/strings.xml b/apps/Fallback/res/values-ms-rMY/strings.xml
similarity index 100%
rename from apps/Fallback/res/values-ms/strings.xml
rename to apps/Fallback/res/values-ms-rMY/strings.xml
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-ne-rNP/strings.xml
similarity index 71%
rename from apps/Fallback/res/values-be/strings.xml
rename to apps/Fallback/res/values-ne-rNP/strings.xml
index d59ae53..7d27eff 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-ne-rNP/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"असमर्थित कार्य"</string>
+ <string name="error" msgid="6539615832923362301">"यस कारवाही हाल समर्थित छैन।"</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-ne/strings.xml
similarity index 71%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-ne/strings.xml
index d59ae53..7d27eff 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-ne/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+ <string name="title" msgid="8156274565006125136">"असमर्थित कार्य"</string>
+ <string name="error" msgid="6539615832923362301">"यस कारवाही हाल समर्थित छैन।"</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-si-rLK/strings.xml
similarity index 69%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-si-rLK/strings.xml
index d59ae53..8a7e7a5 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-si-rLK/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"පසු බැසීම"</string>
+ <string name="title" msgid="8156274565006125136">"සහය නොදක්වන ක්රියාව"</string>
+ <string name="error" msgid="6539615832923362301">"එම ක්රියාවට දැන් සහය නොදක්වයි."</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-si/strings.xml
similarity index 69%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-si/strings.xml
index d59ae53..8a7e7a5 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-si/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"පසු බැසීම"</string>
+ <string name="title" msgid="8156274565006125136">"සහය නොදක්වන ක්රියාව"</string>
+ <string name="error" msgid="6539615832923362301">"එම ක්රියාවට දැන් සහය නොදක්වයි."</string>
</resources>
diff --git a/apps/Fallback/res/values-be/strings.xml b/apps/Fallback/res/values-zh-rHK/strings.xml
similarity index 70%
copy from apps/Fallback/res/values-be/strings.xml
copy to apps/Fallback/res/values-zh-rHK/strings.xml
index d59ae53..ce01c92 100644
--- a/apps/Fallback/res/values-be/strings.xml
+++ b/apps/Fallback/res/values-zh-rHK/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="appTitle" msgid="161410001913116606">"Дапаможны"</string>
- <string name="title" msgid="8156274565006125136">"Дзеянні, якія не падрымліваюцца"</string>
- <string name="error" msgid="6539615832923362301">"Гэтае дзеянне зараз не падтрымліваецца."</string>
+ <string name="appTitle" msgid="161410001913116606">"後備"</string>
+ <string name="title" msgid="8156274565006125136">"不支援的操作"</string>
+ <string name="error" msgid="6539615832923362301">"目前不支援該操作。"</string>
</resources>
diff --git a/build/Android.mk b/build/Android.mk
index a3f1464..8bfa64f 100644
--- a/build/Android.mk
+++ b/build/Android.mk
@@ -126,6 +126,8 @@
android-support-v7-mediarouter \
android-support-v7-recyclerview \
android-support-v13 \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ android-support-multidex \
+ android-support-multidex-instrumentation
$(foreach lib, $(ANDROID_SUPPORT_LIBRARIES), $(eval $(call _package_sdk_library,$(lib))))
diff --git a/build/sdk.atree b/build/sdk.atree
index 88b448a..5a10440 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -369,6 +369,25 @@
${OUT_DIR}/target/common/obj/PACKAGING/android-support-v7-appcompat_intermediates/android-support-v7-appcompat.jar extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar
${OUT_DIR}/target/common/obj/PACKAGING/android-support-v4_intermediates/android-support-v4.jar extras/android/support/v7/appcompat/libs/android-support-v4.jar
+frameworks/multidex/library/README.txt extras/android/support/multidex/library/README.txt
+frameworks/multidex/library/.project extras/android/support/multidex/library/.project
+frameworks/multidex/library/.classpath extras/android/support/multidex/library/.classpath
+frameworks/multidex/library/AndroidManifest.xml extras/android/support/multidex/library/AndroidManifest.xml
+frameworks/multidex/library/project.properties extras/android/support/multidex/library/project.properties
+frameworks/multidex/library/src/.readme extras/android/support/multidex/library/src/.readme
+frameworks/multidex/library/res/.readme extras/android/support/multidex/library/res/.readme
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-multidex_intermediates/android-support-multidex.jar extras/android/support/multidex/library/libs/android-support-multidex.jar
+
+frameworks/multidex/instrumentation/README.txt extras/android/support/multidex/instrumentation/README.txt
+frameworks/multidex/instrumentation/.project extras/android/support/multidex/instrumentation/.project
+frameworks/multidex/instrumentation/.classpath extras/android/support/multidex/instrumentation/.classpath
+frameworks/multidex/instrumentation/AndroidManifest.xml extras/android/support/multidex/instrumentation/AndroidManifest.xml
+frameworks/multidex/instrumentation/project.properties extras/android/support/multidex/instrumentation/project.properties
+frameworks/multidex/instrumentation/src/.readme extras/android/support/multidex/instrumentation/src/.readme
+frameworks/multidex/instrumentation/res/.readme extras/android/support/multidex/instrumentation/res/.readme
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-multidex-instrumentation_intermediates/android-support-multidex-instrumentation.jar extras/android/support/multidex/instrumentation/libs/android-support-multidex-instrumentation.jar
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-multidex_intermediates/android-support-multidex.jar extras/android/support/multidex/instrumentation/libs/android-support-multidex.jar
+
frameworks/support/v7/mediarouter/README.txt extras/android/support/v7/mediarouter/README.txt
frameworks/support/v7/mediarouter/.project extras/android/support/v7/mediarouter/.project
frameworks/support/v7/mediarouter/.classpath extras/android/support/v7/mediarouter/.classpath
@@ -398,6 +417,5 @@
# Tests Component
##############################################################################
framework/layoutlib-tests.jar tests/libtests/layoutlib-tests.jar
-system/app/ConnectivityTest.apk tests/emulator-test-apps/ConnectivityTest.apk
-system/app/GpsLocationTest.apk tests/emulator-test-apps/GpsLocationTest.apk
+system/app/EmulatorSmokeTests.apk tests/emulator-test-apps/EmulatorSmokeTests.apk
diff --git a/build/windows_sdk_whitelist.mk b/build/windows_sdk_whitelist.mk
index e175fad..7f22c8c 100644
--- a/build/windows_sdk_whitelist.mk
+++ b/build/windows_sdk_whitelist.mk
@@ -51,6 +51,7 @@
frameworks/compile \
frameworks/native \
frameworks/rs \
+ frameworks/tools \
system/core/adb \
system/core/fastboot \
system/core/libcutils \
diff --git a/cmds/monkey/src/com/android/commands/monkey/Monkey.java b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
index a2655e1..dfcb4b0 100644
--- a/cmds/monkey/src/com/android/commands/monkey/Monkey.java
+++ b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
@@ -1150,6 +1150,7 @@
if (ev != null) {
int injectCode = ev.injectEvent(mWm, mAm, mVerbose);
if (injectCode == MonkeyEvent.INJECT_FAIL) {
+ System.out.println(" // Injection Failed");
if (ev instanceof MonkeyKeyEvent) {
mDroppedKeyEvents++;
} else if (ev instanceof MonkeyMotionEvent) {
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
index a7f538d..af6a231 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
@@ -436,6 +436,7 @@
if (lastKey != KeyEvent.KEYCODE_POWER
&& lastKey != KeyEvent.KEYCODE_ENDCALL
+ && lastKey != KeyEvent.KEYCODE_SLEEP
&& PHYSICAL_KEY_EXISTS[lastKey]) {
break;
}
diff --git a/ide/eclipse/.classpath b/ide/eclipse/.classpath
index af99325..5bd032f 100644
--- a/ide/eclipse/.classpath
+++ b/ide/eclipse/.classpath
@@ -22,7 +22,6 @@
<classpathentry kind="src" path="packages/apps/Nfc/src"/>
<classpathentry kind="src" path="packages/apps/Nfc/nci/src"/>
<classpathentry kind="src" path="packages/apps/PackageInstaller/src"/>
- <classpathentry kind="src" path="packages/apps/Phone/src"/>
<classpathentry kind="src" path="packages/apps/PhoneCommon/src"/>
<classpathentry kind="src" path="packages/apps/QuickSearchBox/src"/>
<classpathentry kind="src" path="packages/apps/Provision/src"/>
@@ -39,8 +38,11 @@
<classpathentry kind="src" path="packages/screensavers/Basic/src"/>
<classpathentry kind="src" path="packages/screensavers/PhotoTable/src"/>
<classpathentry kind="src" path="packages/screensavers/WebView/src"/>
+ <classpathentry kind="src" path="packages/services/Telecomm/src"/>
+ <classpathentry kind="src" path="packages/services/Telecomm/tests/src"/>
<classpathentry kind="src" path="packages/services/Telephony/src"/>
<classpathentry kind="src" path="packages/services/Telephony/common/src"/>
+ <classpathentry kind="src" path="packages/services/Telephony/tests/src"/>
<classpathentry kind="src" path="frameworks/base/cmds/am/src"/>
<classpathentry kind="src" path="frameworks/base/cmds/input/src"/>
<classpathentry kind="src" path="frameworks/base/cmds/pm/src"/>
@@ -64,13 +66,15 @@
<classpathentry kind="src" path="frameworks/base/packages/SettingsProvider/src"/>
<classpathentry kind="src" path="frameworks/base/packages/SystemUI/src"/>
<classpathentry kind="src" path="frameworks/base/policy/src"/>
+ <classpathentry kind="src" path="frameworks/base/rs/java"/>
<classpathentry kind="src" path="frameworks/base/sax/java"/>
<classpathentry kind="src" path="frameworks/base/services/core/java"/>
- <classpathentry kind="src" path="frameworks/base/services/accessibility/java"/>
- <classpathentry kind="src" path="frameworks/base/services/print/java"/>
- <classpathentry kind="src" path="frameworks/base/services/backup/java"/>
- <classpathentry kind="src" path="frameworks/base/services/devicepolicy/java"/>
- <classpathentry kind="src" path="frameworks/base/services/appwidget/java"/>
+ <classpathentry kind="src" path="frameworks/base/services/accessibility/java"/>
+ <classpathentry kind="src" path="frameworks/base/services/print/java"/>
+ <classpathentry kind="src" path="frameworks/base/services/backup/java"/>
+ <classpathentry kind="src" path="frameworks/base/services/devicepolicy/java"/>
+ <classpathentry kind="src" path="frameworks/base/services/appwidget/java"/>
+ <classpathentry kind="src" path="frameworks/base/telecomm/java"/>
<classpathentry kind="src" path="frameworks/base/telephony/java"/>
<classpathentry kind="src" path="frameworks/base/test-runner/src"/>
<classpathentry kind="src" path="frameworks/base/wifi/java"/>
@@ -84,6 +88,7 @@
<classpathentry kind="src" path="frameworks/opt/telephony/src/java"/>
<classpathentry kind="src" path="frameworks/opt/mms/src/java"/>
<classpathentry kind="src" path="frameworks/opt/net/voip/src/java"/>
+ <classpathentry kind="src" path="frameworks/opt/net/wifi/service/java"/>
<classpathentry kind="src" path="frameworks/opt/vcard/java"/>
<classpathentry kind="src" path="frameworks/support/renderscript/v8/java/src"/>
<classpathentry kind="src" path="frameworks/support/v13/java"/>
@@ -116,7 +121,6 @@
<classpathentry kind="src" path="out/target/common/obj/APPS/Gallery2_intermediates/src/renderscript/src"/>
<classpathentry kind="src" path="out/target/common/obj/APPS/MediaProvider_intermediates/src/src"/>
<classpathentry kind="src" path="out/target/common/obj/APPS/Music_intermediates/src/src"/>
- <classpathentry kind="src" path="out/target/common/obj/APPS/Phone_intermediates/src/src"/>
<classpathentry kind="src" path="out/target/common/obj/APPS/QuickSearchBox_intermediates/src/src"/>
<classpathentry kind="src" path="out/target/common/obj/APPS/SystemUI_intermediates/src/src"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/android-common-carousel_intermediates/src/renderscript/src"/>
@@ -125,6 +129,7 @@
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/keystore/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/location/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java"/>
+ <classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telecomm/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telephony/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/wifi/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/NfcLogTags_intermediates/src/src"/>
diff --git a/ide/eclipse/android-formatting.xml b/ide/eclipse/android-formatting.xml
index 9b43767..9c2af85 100644
--- a/ide/eclipse/android-formatting.xml
+++ b/ide/eclipse/android-formatting.xml
@@ -52,7 +52,7 @@
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
-<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index f202d59..55a04f0 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -37,7 +37,7 @@
<!-- For android.media.audiofx.Visualizer -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="20" />
<!-- We will request access to the camera, saying we require a camera
of some sort but not one with autofocus capability. -->
@@ -78,7 +78,7 @@
<activity android:name=".app.DialogActivity"
android:label="@string/activity_dialog"
- android:theme="@android:style/Theme.Holo.Dialog">
+ android:theme="@style/ThemeCurrentDialog">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
@@ -740,7 +740,7 @@
<!-- BEGIN_INCLUDE(interstitial_affinity) -->
<activity android:name=".app.IncomingMessageInterstitial"
android:label="You have messages"
- android:theme="@style/ThemeHoloDialog"
+ android:theme="@style/ThemeCurrentDialog"
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true">
@@ -1232,6 +1232,15 @@
</intent-filter>
</activity>
+ <activity android:name=".content.DocumentsSample"
+ android:label="@string/activity_documents"
+ android:enabled="@bool/atLeastKitKat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
<provider android:name=".content.FileProvider"
android:authorities="com.example.android.apis.content.FileProvider"
android:enabled="@bool/atLeastHoneycombMR2" />
@@ -1258,13 +1267,6 @@
</intent-filter>
</activity>
- <activity android:name=".os.Sensors" android:label="OS/Sensors">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
<activity android:name=".os.TriggerSensors" android:label="OS/TriggerSensors">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -1300,6 +1302,25 @@
<!-- ANDROID.ANIMATION PACKAGE SAMPLES -->
<!-- ************************************* -->
+ <activity android:name=".animation.ActivityTransition"
+ android:label="Animation/Activity Transition"
+ android:enabled="@bool/atLeastLRelease"
+ android:theme="@style/ActivityTransitionTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".animation.ActivityTransitionDetails"
+ android:label="Animation/Details of a specific thingy"
+ android:enabled="@bool/atLeastLRelease"
+ android:theme="@style/ActivityTransitionTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".animation.AnimationLoading"
android:label="Animation/Loading"
android:enabled="@bool/atLeastHoneycomb">
@@ -1417,6 +1438,15 @@
</intent-filter>
</activity>
+ <activity android:name=".animation.PathAnimations"
+ android:label="Animation/Path Animations"
+ android:enabled="@bool/atLeastHoneycomb">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
<!-- ************************************* -->
<!-- ANIMATION PACKAGE SAMPLES -->
<!-- ************************************* -->
@@ -1976,20 +2006,6 @@
</intent-filter>
</activity>
- <activity android:name=".view.Gallery1" android:label="Views/Gallery/1. Photos">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity android:name=".view.Gallery2" android:label="Views/Gallery/2. People">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
<activity android:name=".view.Spinner1" android:label="Views/Spinner">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -2027,14 +2043,6 @@
</intent-filter>
</activity>
- <activity android:name=".view.ImageSwitcher1"
- android:label="Views/ImageSwitcher">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
<activity android:name=".view.TextSwitcher1"
android:label="Views/TextSwitcher">
<intent-filter>
@@ -2160,8 +2168,9 @@
</activity>
<activity android:name=".view.Controls5"
- android:label="Views/Controls/5. Custom Theme"
- android:theme="@style/CustomTheme">
+ android:label="Views/Controls/5. Quantum Light Theme"
+ android:theme="@android:style/Theme.Quantum.Light"
+ android:enabled="@bool/atLeastLRelease">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
@@ -2169,8 +2178,36 @@
</activity>
<activity android:name=".view.Controls6"
- android:label="Views/Controls/6. Holo or Old Theme"
- android:theme="@style/ThemeHolo">
+ android:label="Views/Controls/6. Quantum Dark Theme"
+ android:theme="@android:style/Theme.Quantum"
+ android:enabled="@bool/atLeastLRelease">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Controls7"
+ android:label="Views/Controls/7. Custom Theme"
+ android:theme="@style/CustomTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Controls8"
+ android:label="Views/Controls/8. Current or Old Theme"
+ android:theme="@style/ThemeCurrent">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Controls9"
+ android:label="Views/Controls/9. Default Theme"
+ android:theme="@style/ThemeDefault">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
@@ -2584,7 +2621,7 @@
<activity android:name=".graphics.TriangleActivity"
android:label="Graphics/OpenGL ES/Textured Triangle"
- android:theme="@android:style/Theme.Holo.Dialog"
+ android:theme="@style/ThemeCurrentDialog"
android:configChanges="keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/drawable-nodpi/ball.jpg b/samples/ApiDemos/res/drawable-nodpi/ball.jpg
new file mode 100644
index 0000000..2960b73
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/ball.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/block.jpg b/samples/ApiDemos/res/drawable-nodpi/block.jpg
new file mode 100644
index 0000000..04c22a0
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/block.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/ducky.jpg b/samples/ApiDemos/res/drawable-nodpi/ducky.jpg
new file mode 100644
index 0000000..830bbe3
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/ducky.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/jellies.jpg b/samples/ApiDemos/res/drawable-nodpi/jellies.jpg
new file mode 100644
index 0000000..ee2b5c6
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/jellies.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/mug.jpg b/samples/ApiDemos/res/drawable-nodpi/mug.jpg
new file mode 100644
index 0000000..e149e19
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/mug.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/pencil.jpg b/samples/ApiDemos/res/drawable-nodpi/pencil.jpg
new file mode 100644
index 0000000..e348311
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/pencil.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/scissors.jpg b/samples/ApiDemos/res/drawable-nodpi/scissors.jpg
new file mode 100644
index 0000000..caf0ce8
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/scissors.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/woot.jpg b/samples/ApiDemos/res/drawable-nodpi/woot.jpg
new file mode 100644
index 0000000..ccaef67
--- /dev/null
+++ b/samples/ApiDemos/res/drawable-nodpi/woot.jpg
Binary files differ
diff --git a/samples/ApiDemos/res/layout/controls_1.xml b/samples/ApiDemos/res/layout/controls_1.xml
index e280188..cd7fd0d 100644
--- a/samples/ApiDemos/res/layout/controls_1.xml
+++ b/samples/ApiDemos/res/layout/controls_1.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!--
+ Copyright (C) 2007 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.
@@ -15,139 +16,143 @@
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
<LinearLayout
- android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <Button android:id="@+id/button"
- android:text="@string/controls_1_save"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <Button android:id="@+id/button_disabled"
- android:text="@string/controls_1_save"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- </LinearLayout>
-
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <EditText android:id="@+id/edit"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
- <EditText android:id="@+id/edit2"
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/controls_1_save" />
+
+ <Button
+ android:id="@+id/button_disabled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/controls_1_save" />
+ </LinearLayout>
+
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
- </LinearLayout>
+ <EditText
+ android:id="@+id/edit"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
- <CheckBox android:id="@+id/check1"
- android:paddingBottom="24sp"
- android:paddingTop="24sp"
+ <EditText
+ android:id="@+id/edit2"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ </LinearLayout>
+
+ <CheckBox
+ android:id="@+id/check1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingBottom="24sp"
+ android:paddingTop="24sp"
android:text="@string/controls_1_checkbox_1" />
- <CheckBox android:id="@+id/check2"
+ <CheckBox
+ android:id="@+id/check2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/controls_1_checkbox_2" />
-
+
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <RadioButton android:id="@+id/radio1"
+ android:orientation="vertical" >
+
+ <RadioButton
+ android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/controls_1_radiobutton_1" />
-
- <RadioButton android:id="@+id/radio2"
+
+ <RadioButton
+ android:id="@+id/radio2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/controls_1_radiobutton_2" />
-
</RadioGroup>
-
- <CheckBox android:id="@+id/star"
+
+ <CheckBox
+ android:id="@+id/star"
style="?android:attr/starStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/controls_1_star" />
-
- <ToggleButton android:id="@+id/toggle1"
+
+ <ToggleButton
+ android:id="@+id/toggle1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
-
- <ToggleButton android:id="@+id/toggle2"
+
+ <ToggleButton
+ android:id="@+id/toggle2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
-
- <Spinner android:id="@+id/spinner1"
+
+ <Spinner
+ android:id="@+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawSelectorOnTop="true"
- />
+ android:drawSelectorOnTop="true" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
- android:text="@string/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceLarge"
android:focusable="true"
- />
+ android:text="@string/textColorPrimary"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
+ android:focusable="true"
android:text="@string/textColorSecondary"
android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="?android:attr/textColorSecondary"
- android:focusable="true"
- />
+ android:textColor="?android:attr/textColorSecondary" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
+ android:focusable="true"
android:text="@string/textColorTertiary"
android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="?android:attr/textColorTertiary"
- android:focusable="true"
- />
+ android:textColor="?android:attr/textColorTertiary" />
<TextView
style="?android:attr/listSeparatorTextViewStyle"
- android:text="@string/listSeparatorTextViewStyle"
android:layout_marginTop="5dip"
- />
+ android:text="@string/listSeparatorTextViewStyle" />
<TextView
- android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginTop="400dip"
- android:textAppearance="?android:attr/textAppearanceLarge"
android:text="(And all inside of a ScrollView!)"
- />
-
+ android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
-</ScrollView>
+</ScrollView>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/gallery_1.xml b/samples/ApiDemos/res/layout/gallery_1.xml
deleted file mode 100644
index d884c61..0000000
--- a/samples/ApiDemos/res/layout/gallery_1.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:id="@+id/layout2"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-<Gallery android:id="@+id/gallery"
-android:layout_width="match_parent"
-android:layout_height="wrap_content"
-/>
-<EditText
- android:text="@+id/EditText01"
- android:id="@+id/EditText01"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"></EditText>
-</LinearLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/gallery_2.xml b/samples/ApiDemos/res/layout/gallery_2.xml
deleted file mode 100644
index 1192bb2..0000000
--- a/samples/ApiDemos/res/layout/gallery_2.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="10dip"
- android:text="@string/gallery_2_text"
- />
-
- <Gallery android:id="@+id/gallery"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:spacing="16dp"
- />
-
-</LinearLayout>
-
diff --git a/samples/ApiDemos/res/layout/image_block.xml b/samples/ApiDemos/res/layout/image_block.xml
new file mode 100644
index 0000000..4233717
--- /dev/null
+++ b/samples/ApiDemos/res/layout/image_block.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="true"
+ android:columnCount="2"
+ android:rowCount="4"
+ >
+ <ImageView android:id="@+id/ducky"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:layout_column="0"
+ android:layout_row="0"
+ android:src="@drawable/ducky"
+ android:onClick="clicked"
+ android:viewName="ducky"
+ />
+ <ImageView android:id="@+id/woot"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/woot"
+ android:layout_column="1"
+ android:layout_row="0"
+ android:onClick="clicked"
+ android:viewName="woot"
+ />
+ <ImageView android:id="@+id/ball"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/ball"
+ android:layout_column="0"
+ android:layout_row="1"
+ android:onClick="clicked"
+ android:viewName="ball"
+ />
+ <ImageView android:id="@+id/block"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/block"
+ android:layout_column="1"
+ android:layout_row="1"
+ android:onClick="clicked"
+ android:viewName="block"
+ />
+ <ImageView android:id="@+id/jellies"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/jellies"
+ android:layout_column="0"
+ android:layout_row="2"
+ android:onClick="clicked"
+ android:viewName="jellies"
+ />
+ <ImageView android:id="@+id/mug"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/mug"
+ android:layout_column="1"
+ android:layout_row="2"
+ android:onClick="clicked"
+ android:viewName="mug"
+ />
+ <ImageView android:id="@+id/pencil"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/pencil"
+ android:layout_column="0"
+ android:layout_row="3"
+ android:onClick="clicked"
+ android:viewName="pencil"
+ />
+ <ImageView android:id="@+id/scissors"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/scissors"
+ android:layout_column="1"
+ android:layout_row="3"
+ android:onClick="clicked"
+ android:viewName="scissors"
+ />
+</GridLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/image_details.xml b/samples/ApiDemos/res/layout/image_details.xml
new file mode 100644
index 0000000..a176ce5
--- /dev/null
+++ b/samples/ApiDemos/res/layout/image_details.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+ <ImageView android:id="@+id/titleImage"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:scaleType="centerCrop"
+ android:viewName="hero"
+ android:onClick="clicked"
+ />
+ <LinearLayout android:layout_height="0px"
+ android:layout_width="match_parent"
+ android:layout_weight="2"
+ android:orientation="vertical"
+ >
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Ducky"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Woot!"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Ball"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Block"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Jelly Bean"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Mug"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Pencil"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+ <View android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Scissors"
+ android:textSize="30sp"
+ android:textColor="#FFF"
+ />
+
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/layout/image_switcher_1.xml b/samples/ApiDemos/res/layout/image_switcher_1.xml
deleted file mode 100644
index 0fdf3f9..0000000
--- a/samples/ApiDemos/res/layout/image_switcher_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ImageSwitcher android:id="@+id/switcher"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- />
-
- <Gallery android:id="@+id/gallery"
- android:background="#55000000"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
-
- android:gravity="center_vertical"
- android:spacing="16dp"
- />
-
-</RelativeLayout>
-
diff --git a/samples/ApiDemos/res/layout/path_animations.xml b/samples/ApiDemos/res/layout/path_animations.xml
new file mode 100644
index 0000000..93abc98
--- /dev/null
+++ b/samples/ApiDemos/res/layout/path_animations.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ScrollView android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <RadioGroup android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/path_animation_type"
+ >
+ <RadioButton android:id="@+id/named_components"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Named Components"/>
+ <RadioButton android:id="@+id/property_components"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Property Components"/>
+ <RadioButton android:id="@+id/multi_int"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Multi-int"/>
+ <RadioButton android:id="@+id/multi_float"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Multi-float"/>
+ <RadioButton android:id="@+id/named_setter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Named Property"/>
+ <RadioButton android:id="@+id/property_setter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Property"/>
+ </RadioGroup>
+ </ScrollView>
+ <view class="com.example.android.apis.animation.PathAnimations$CanvasView"
+ android:id="@+id/canvas"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+ <ImageView android:id="@+id/moved_item"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/frog"/>
+ </view>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/transition/activity_transition_mgr.xml b/samples/ApiDemos/res/transition/activity_transition_mgr.xml
new file mode 100644
index 0000000..f1f461b
--- /dev/null
+++ b/samples/ApiDemos/res/transition/activity_transition_mgr.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+</transitionManager>
diff --git a/samples/ApiDemos/res/transition/explode.xml b/samples/ApiDemos/res/transition/explode.xml
new file mode 100644
index 0000000..bb93ca7
--- /dev/null
+++ b/samples/ApiDemos/res/transition/explode.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<!-- BEGIN_INCLUDE(Explode) -->
+<explode/>
+<!-- END_INCLUDE(Explode) -->
diff --git a/samples/ApiDemos/res/transition/explode_move_together.xml b/samples/ApiDemos/res/transition/explode_move_together.xml
new file mode 100644
index 0000000..80c6827
--- /dev/null
+++ b/samples/ApiDemos/res/transition/explode_move_together.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<!-- BEGIN_INCLUDE(MultipleTransform) -->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+ <explode/>
+ <transitionSet>
+ <targets>
+ <target android:excludeClass="android.widget.ImageView"/>
+ </targets>
+ <changeBounds/>
+ <changeTransform/>
+ <changeClipBounds/>
+ </transitionSet>
+ <moveImage>
+ <targets>
+ <target android:targetClass="android.widget.ImageView"/>
+ </targets>
+ </moveImage>
+</transitionSet>
+<!-- END_INCLUDE(MultipleTransform) -->
diff --git a/samples/ApiDemos/res/transition/move_image.xml b/samples/ApiDemos/res/transition/move_image.xml
new file mode 100644
index 0000000..28bdf4e
--- /dev/null
+++ b/samples/ApiDemos/res/transition/move_image.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<!-- BEGIN_INCLUDE(MoveImage) -->
+<moveImage/>
+<!-- END_INCLUDE(MoveImage) -->
diff --git a/samples/ApiDemos/res/values-v11/styles.xml b/samples/ApiDemos/res/values-v11/styles.xml
index 3b4fead..5b92c33 100644
--- a/samples/ApiDemos/res/values-v11/styles.xml
+++ b/samples/ApiDemos/res/values-v11/styles.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+ Copyright (C) 2011 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.
@@ -15,15 +16,17 @@
-->
<resources>
- <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
- <style name="ThemeHolo" parent="android:Theme.Holo">
- </style>
<!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
- <style name="ThemeHoloDialog" parent="android:Theme.Holo.Dialog">
- </style>
+ <style name="ThemeCurrent" parent="@android:Theme.Holo" />
+
+ <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
+ <style name="ThemeCurrentDialog" parent="@android:Theme.Holo.Dialog" />
<!-- For API level 11 or later, we can use the magical DialogWhenLarge theme. -->
- <style name="ThemeDialogWhenLarge" parent="android:style/Theme.Holo.DialogWhenLarge">
- </style>
-</resources>
+ <style name="ThemeDialogWhenLarge" parent="@android:style/Theme.Holo.DialogWhenLarge" />
+
+ <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
+ <style name="ThemeDefault" parent="@android:style/Theme.Holo" />
+
+</resources>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/values-v14/styles.xml b/samples/ApiDemos/res/values-v14/styles.xml
new file mode 100644
index 0000000..39e5290
--- /dev/null
+++ b/samples/ApiDemos/res/values-v14/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2011 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>
+
+ <!-- For API level 14 or later, the DeviceDefault theme is available and we prefer that. -->
+ <style name="ThemeDefault" parent="@android:style/Theme.DeviceDefault" />
+
+</resources>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/values-v19/styles.xml b/samples/ApiDemos/res/values-v19/styles.xml
new file mode 100644
index 0000000..c0bd00b
--- /dev/null
+++ b/samples/ApiDemos/res/values-v19/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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>
+ <!-- For API level XX or later, the Quantum theme is available and we prefer that. -->
+ <style name="ThemeCurrent" parent="android:Theme.Quantum">
+ </style>
+
+ <!-- For API level XX or later, the Holo theme is available and we prefer that. -->
+ <style name="ThemeCurrentDialog" parent="android:Theme.Quantum.Dialog">
+ </style>
+
+ <!-- For API level XX or later, we can use the magical DialogWhenLarge theme. -->
+ <style name="ThemeCurrentDialogWhenLarge" parent="android:style/Theme.Quantum.DialogWhenLarge">
+ </style>
+</resources>
diff --git a/samples/ApiDemos/res/values-v20/bools.xml b/samples/ApiDemos/res/values-v20/bools.xml
new file mode 100644
index 0000000..3a4b91e
--- /dev/null
+++ b/samples/ApiDemos/res/values-v20/bools.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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>
+ <!-- This resource is true if running under at least L-Release
+ API level. The default value is false; an alternative value
+ for L-Release is true. -->
+ <bool name="atLeastLRelease">true</bool>
+</resources>
diff --git a/samples/ApiDemos/res/values-v20/styles.xml b/samples/ApiDemos/res/values-v20/styles.xml
new file mode 100644
index 0000000..e454942
--- /dev/null
+++ b/samples/ApiDemos/res/values-v20/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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>
+ <!-- For API level XX or later, the Quantum theme is available and we prefer that. -->
+ <style name="ThemeCurrent" parent="android:Theme.Quantum.Light">
+ </style>
+
+ <!-- For API level XX or later, the Holo theme is available and we prefer that. -->
+ <style name="ThemeCurrentDialog" parent="android:Theme.Quantum.Light.Dialog">
+ </style>
+
+ <!-- For API level XX or later, we can use the magical DialogWhenLarge theme. -->
+ <style name="ThemeCurrentDialogWhenLarge" parent="android:style/Theme.Quantum.Light.DialogWhenLarge">
+ </style>
+</resources>
diff --git a/samples/ApiDemos/res/values/attrs.xml b/samples/ApiDemos/res/values/attrs.xml
index bf33788..558f3ef 100644
--- a/samples/ApiDemos/res/values/attrs.xml
+++ b/samples/ApiDemos/res/values/attrs.xml
@@ -21,12 +21,6 @@
<attr name="android:preferenceLayoutChild" />
</declare-styleable>
- <!-- These are the attributes that we want to retrieve from the theme
- in view/Gallery1.java -->
- <declare-styleable name="Gallery1">
- <attr name="android:galleryItemBackground" />
- </declare-styleable>
-
<declare-styleable name="LabelView">
<attr name="text" format="string" />
<attr name="textColor" format="color" />
diff --git a/samples/ApiDemos/res/values/bools.xml b/samples/ApiDemos/res/values/bools.xml
index fa3f25f..127c142 100644
--- a/samples/ApiDemos/res/values/bools.xml
+++ b/samples/ApiDemos/res/values/bools.xml
@@ -49,4 +49,9 @@
for KitKat is true. -->
<bool name="atLeastKitKat">false</bool>
+ <!-- This resource is true if running under at least L-Release
+ API level. The default value is false; an alternative value
+ for L-Release is true. -->
+ <bool name="atLeastLRelease">false</bool>
+
</resources>
diff --git a/samples/ApiDemos/res/values/colors.xml b/samples/ApiDemos/res/values/colors.xml
index f2534d1..147ba84 100644
--- a/samples/ApiDemos/res/values/colors.xml
+++ b/samples/ApiDemos/res/values/colors.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!--
+ Copyright (C) 2007 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.
@@ -15,12 +16,12 @@
-->
<resources>
+
<drawable name="red">#7f00</drawable>
<drawable name="blue">#770000ff</drawable>
<drawable name="green">#7700ff00</drawable>
- <drawable name="yellow">#77ffff00</drawable>
-
- <drawable name="screen_background_black">#ff000000</drawable>
+ <drawable name="yellow">#77ffff00</drawable>
+ <drawable name="screen_background_black">#ff000000</drawable>
<drawable name="translucent_background">#e0000000</drawable>
<drawable name="transparent_background">#00000000</drawable>
@@ -28,5 +29,10 @@
<color name="solid_blue">#0000ff</color>
<color name="solid_green">#f0f0</color>
<color name="solid_yellow">#ffffff00</color>
+ <color name="purply">#ff884488</color>
+
+ <!-- A custom theme that is a variation on the light them with a different
+ background color. -->
+ <color name="custom_theme_color">#b0b0ff</color>
</resources>
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 804087d..46ef1a2 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -463,6 +463,8 @@
<string name="ir_send">Send IR</string>
<string name="ir_get_freqs">Get Carrier Frequencies</string>
+ <string name="activity_documents">Content/Storage/Documents</string>
+
<!-- ============================== -->
<!-- app/intents examples strings -->
<!-- ============================== -->
@@ -741,10 +743,19 @@
<string name="disable_camera">Disable all device cameras</string>
<string name="disable_keyguard_widgets">Disable keyguard widgets</string>
<string name="disable_keyguard_secure_camera">Disable keyguard secure camera</string>
+ <string name="disable_keyguard_notifications">Disable keyguard notifications</string>
+ <string name="disable_keyguard_unredacted_notifications">Disable keyguard unredacted notifications</string>
+ <string name="disable_keyguard_trust_agents">Disable keyguard Trust Agents</string>
<string name="keyguard_widgets_disabled">Keyguard widgets disabled</string>
<string name="keyguard_widgets_enabled">Keyguard widgets enabled</string>
<string name="keyguard_secure_camera_disabled">Keyguard secure camera disabled</string>
<string name="keyguard_secure_camera_enabled">Keyguard secure camera enabled</string>
+ <string name="keyguard_secure_notifications_disabled">Keyguard notifications disabled</string>
+ <string name="keyguard_secure_notifications_enabled">Keyguard notifications enabled</string>
+ <string name="keyguard_unredacted_notifications_disabled">Keyguard unredacted notifications disabled</string>
+ <string name="keyguard_unredacted_notifications_enabled">Keyguard unredacted notifications enabled</string>
+ <string name="keyguard_trust_agents_disabled">Keyguard Trust Agents disabled</string>
+ <string name="keyguard_trust_agents_enabled">Keyguard Trust Agents enabled</string>
<string name="camera_disabled">Device cameras disabled</string>
<string name="camera_enabled">Device cameras enabled</string>
<string name="password_controls_category">Password controls</string>
@@ -1116,7 +1127,6 @@
<string name="focus_5_button3">3</string>
<string name="focus_5_button4">4</string>
<string name="focus_5_button5">5</string>
- <string name="gallery_2_text">Testing</string>
<string name="grid_layout_1_instructions">Type here:</string>
<string name="grid_layout_1_ok">Ok</string>
<string name="grid_layout_1_cancel">Cancel</string>
diff --git a/samples/ApiDemos/res/values/styles.xml b/samples/ApiDemos/res/values/styles.xml
index 49a1c25..6c63d54 100644
--- a/samples/ApiDemos/res/values/styles.xml
+++ b/samples/ApiDemos/res/values/styles.xml
@@ -15,9 +15,6 @@
-->
<resources>
- <!-- A custom theme that is a variation on the light them with a different
- background color. -->
- <color name="custom_theme_color">#b0b0ff</color>
<style name="CustomTheme" parent="android:Theme.Light">
<item name="android:windowBackground">@color/custom_theme_color</item>
<item name="android:colorBackground">@color/custom_theme_color</item>
@@ -26,24 +23,33 @@
<!-- This is a theme that will adjust itself depending on the API version.
The default definition is the safe one, using a theme that has always
been defined. Look at values-11/styles.xml for a variation that is
- selected when the holographic theme is available. -->
- <style name="ThemeHolo" parent="android:Theme">
- </style>
+ selected when the holographic theme is available, or look at
+ values-XX/styles.xml for a variation that is selected when the quantum
+ theme is available. -->
+ <style name="ThemeCurrent" parent="android:Theme" />
+
+ <!-- This is a theme that reflects the default theme used when no theme is
+ specified by an application or activity. In API 14 and above, this
+ refers to the DeviceDefault theme. -->
+ <style name="ThemeDefault" parent="android:Theme" />
<!-- This is a theme that will adjust itself depending on the API version.
The default definition is the safe one, using a theme that has always
been defined. Look at values-11/styles.xml for a variation that is
- selected when the holographic theme is available. -->
- <style name="ThemeHoloDialog" parent="android:Theme.Dialog">
- </style>
+ selected when the holographic theme is available, or look at
+ values-XX/styles.xml for a variation that is selected when the quantum
+ theme is available. -->
+ <style name="ThemeCurrentDialog" parent="android:Theme.Dialog" />
+
+ <!-- Older platforms don't have Theme.Holo.DialogWhenLarge; we will define
+ our own wrapper theme that uses it only when running on the appropriate
+ platform version. On older platforms, we always use the generic
+ fullscreen theme, because they don't support some feature that help
+ in correctly laying out an activity as a dialog. -->
+ <style name="ThemeCurrentDialogWhenLarge" parent="android:style/Theme" />
<!-- Base application theme is the default theme. -->
- <style name="Theme" parent="android:Theme">
- </style>
-
- <!-- Base application theme is the default theme. -->
- <style name="BadTheme" parent="@android:style/Theme.Holo.Light.NoActionBar">
- </style>
+ <style name="Theme" parent="android:Theme" />
<!-- Variation on our application theme that forces a plain
text style. -->
@@ -91,14 +97,6 @@
<item name="android:windowNoTitle">true</item>
<item name="android:colorForeground">#fff</item>
</style>
-
- <!-- Older platforms don't have Theme.Holo.DialogWhenLarge; we will define
- our own wrapper theme that uses it only when running on the appropriate
- platform version. On older platforms, we always use the generic
- fullscreen theme, because they don't support some feature that help
- in correctly laying out an activity as a dialog. -->
- <style name="ThemeDialogWhenLarge" parent="android:style/Theme">
- </style>
<style name="TextAppearance.Theme.PlainText" parent="android:TextAppearance.Theme">
<item name="android:textStyle">normal</item>
@@ -121,4 +119,15 @@
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
+
+ <style name="ActivityTransitionTheme" parent="android:Theme.Quantum">
+ <item name="android:windowEnterTransition">@transition/explode</item>
+ <item name="android:windowExitTransition">@transition/explode</item>
+ <item name="android:windowSharedElementEnterTransition">@transition/move_image</item>
+ <item name="android:windowSharedElementExitTransition">@transition/move_image</item>
+ <item name="android:windowAllowExitTransitionOverlap">true</item>
+ <item name="android:windowAllowEnterTransitionOverlap">false</item>
+ <item name="android:windowContentTransitions">true</item>
+ </style>
+
</resources>
diff --git a/samples/ApiDemos/res/xml/device_admin_general.xml b/samples/ApiDemos/res/xml/device_admin_general.xml
index 3a1dd45..cfd0048 100644
--- a/samples/ApiDemos/res/xml/device_admin_general.xml
+++ b/samples/ApiDemos/res/xml/device_admin_general.xml
@@ -43,6 +43,18 @@
android:key="key_disable_keyguard_secure_camera"
android:title="@string/disable_keyguard_secure_camera" />
+ <CheckBoxPreference
+ android:key="key_disable_notifications"
+ android:title="@string/disable_keyguard_notifications" />
+
+ <CheckBoxPreference
+ android:key="key_disable_unredacted"
+ android:title="@string/disable_keyguard_unredacted_notifications" />
+
+ <CheckBoxPreference
+ android:key="key_disable_trust_agents"
+ android:title="@string/disable_keyguard_trust_agents" />
+
</PreferenceCategory>
</PreferenceScreen>
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java
new file mode 100644
index 0000000..8a72087
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransition.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 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.example.android.apis.animation;
+
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.SharedElementListener;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class ActivityTransition extends Activity {
+
+ private static final String TAG = "ActivityTransition";
+
+ private static final String KEY_ID = "ViewTransitionValues:id";
+
+ private ImageView mHero;
+
+ public static final int[] DRAWABLES = {
+ R.drawable.ball,
+ R.drawable.block,
+ R.drawable.ducky,
+ R.drawable.jellies,
+ R.drawable.mug,
+ R.drawable.pencil,
+ R.drawable.scissors,
+ R.drawable.woot,
+ };
+
+ public static final int[] IDS = {
+ R.id.ball,
+ R.id.block,
+ R.id.ducky,
+ R.id.jellies,
+ R.id.mug,
+ R.id.pencil,
+ R.id.scissors,
+ R.id.woot,
+ };
+
+ public static final String[] NAMES = {
+ "ball",
+ "block",
+ "ducky",
+ "jellies",
+ "mug",
+ "pencil",
+ "scissors",
+ "woot",
+ };
+
+ public static int getIdForKey(String id) {
+ return IDS[getIndexForKey(id)];
+ }
+
+ public static int getDrawableIdForKey(String id) {
+ return DRAWABLES[getIndexForKey(id)];
+ }
+
+ public static int getIndexForKey(String id) {
+ for (int i = 0; i < NAMES.length; i++) {
+ String name = NAMES[i];
+ if (name.equals(id)) {
+ return i;
+ }
+ }
+ return 2;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
+ setContentView(R.layout.image_block);
+ setupHero();
+ }
+
+ private void setupHero() {
+ String name = getIntent().getStringExtra(KEY_ID);
+ mHero = null;
+ if (name != null) {
+ mHero = (ImageView) findViewById(getIdForKey(name));
+ setSharedElementListener(new SharedElementListener() {
+ @Override
+ public void remapSharedElements(List<String> names,
+ Map<String, View> sharedElements) {
+ sharedElements.put("hero", mHero);
+ }
+ });
+ }
+ }
+
+ public void clicked(View v) {
+ mHero = (ImageView) v;
+ Intent intent = new Intent(this, ActivityTransitionDetails.class);
+ intent.putExtra(KEY_ID, v.getViewName());
+ ActivityOptions activityOptions
+ = ActivityOptions.makeSceneTransitionAnimation(this, mHero, "hero");
+ startActivity(intent, activityOptions.toBundle());
+ }
+
+ private static int randomColor() {
+ int red = (int)(Math.random() * 128);
+ int green = (int)(Math.random() * 128);
+ int blue = (int)(Math.random() * 128);
+ return 0xFF000000 | (red << 16) | (green << 8) | blue;
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java
new file mode 100644
index 0000000..e657c55
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/ActivityTransitionDetails.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 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.example.android.apis.animation;
+
+import com.example.android.apis.R;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+/**
+ *
+ */
+public class ActivityTransitionDetails extends Activity {
+
+ private static final String TAG = "ActivityTransitionDetails";
+
+ private static final String KEY_ID = "ViewTransitionValues:id";
+
+ private int mImageResourceId = R.drawable.ducky;
+
+ private String mName = "ducky";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(randomColor()));
+ setContentView(R.layout.image_details);
+ ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
+ titleImage.setImageDrawable(getHeroDrawable());
+ }
+
+ private Drawable getHeroDrawable() {
+ String name = getIntent().getStringExtra(KEY_ID);
+ if (name != null) {
+ mName = name;
+ mImageResourceId = ActivityTransition.getDrawableIdForKey(name);
+ }
+
+ return getResources().getDrawable(mImageResourceId);
+ }
+
+ public void clicked(View v) {
+ Intent intent = new Intent(this, ActivityTransition.class);
+ intent.putExtra(KEY_ID, mName);
+ ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(this,
+ v, "hero");
+ startActivity(intent, activityOptions.toBundle());
+ }
+
+ private static int randomColor() {
+ int red = (int)(Math.random() * 128);
+ int green = (int)(Math.random() * 128);
+ int blue = (int)(Math.random() * 128);
+ return 0xFF000000 | (red << 16) | (green << 8) | blue;
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/PathAnimations.java b/samples/ApiDemos/src/com/example/android/apis/animation/PathAnimations.java
new file mode 100644
index 0000000..daa8d99
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/PathAnimations.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2013 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.example.android.apis.animation;
+
+import android.animation.ObjectAnimator;
+import android.animation.TypeConverter;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.FloatMath;
+import android.util.Log;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+import android.widget.RadioGroup;
+
+import com.example.android.apis.R;
+
+/** This application demonstrates the use of Path animation. */
+public class PathAnimations extends Activity implements
+ RadioGroup.OnCheckedChangeListener, View.OnLayoutChangeListener {
+
+ final static Path sTraversalPath = new Path();
+ final static float TRAVERSE_PATH_SIZE = 7.0f;
+
+ final static Property<PathAnimations, Point> POINT_PROPERTY
+ = new Property<PathAnimations, Point>(Point.class, "point") {
+ @Override
+ public Point get(PathAnimations object) {
+ View v = object.findViewById(R.id.moved_item);
+ return new Point(Math.round(v.getX()), Math.round(v.getY()));
+ }
+
+ @Override
+ public void set(PathAnimations object, Point value) {
+ object.setCoordinates(value.x, value.y);
+ }
+ };
+
+ static {
+ float inverse_sqrt8 = FloatMath.sqrt(0.125f);
+ RectF bounds = new RectF(1, 1, 3, 3);
+ sTraversalPath.addArc(bounds, 45, 180);
+ sTraversalPath.addArc(bounds, 225, 180);
+
+ bounds.set(1.5f + inverse_sqrt8, 1.5f + inverse_sqrt8, 2.5f + inverse_sqrt8,
+ 2.5f + inverse_sqrt8);
+ sTraversalPath.addArc(bounds, 45, 180);
+ sTraversalPath.addArc(bounds, 225, 180);
+
+ bounds.set(4, 1, 6, 3);
+ sTraversalPath.addArc(bounds, 135, -180);
+ sTraversalPath.addArc(bounds, -45, -180);
+
+ bounds.set(4.5f - inverse_sqrt8, 1.5f + inverse_sqrt8, 5.5f - inverse_sqrt8, 2.5f + inverse_sqrt8);
+ sTraversalPath.addArc(bounds, 135, -180);
+ sTraversalPath.addArc(bounds, -45, -180);
+
+ sTraversalPath.addCircle(3.5f, 3.5f, 0.5f, Path.Direction.CCW);
+
+ sTraversalPath.addArc(new RectF(1, 2, 6, 6), 0, 180);
+ }
+
+ private CanvasView mCanvasView;
+
+ private ObjectAnimator mAnimator;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.path_animations);
+ mCanvasView = (CanvasView) findViewById(R.id.canvas);
+ mCanvasView.addOnLayoutChangeListener(this);
+ ((RadioGroup) findViewById(R.id.path_animation_type)).setOnCheckedChangeListener(this);
+ }
+
+ public void setCoordinates(int x, int y) {
+ changeCoordinates((float) x, (float) y);
+ }
+
+ public void changeCoordinates(float x, float y) {
+ View v = findViewById(R.id.moved_item);
+ v.setX(x);
+ v.setY(y);
+ }
+
+ public void setPoint(PointF point) {
+ changeCoordinates(point.x, point.y);
+ }
+
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ startAnimator(checkedId);
+ }
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ int checkedId = ((RadioGroup)findViewById(R.id.path_animation_type)).getCheckedRadioButtonId();
+ if (checkedId != RadioGroup.NO_ID) {
+ startAnimator(checkedId);
+ }
+ }
+
+ private void startAnimator(int checkedId) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ mAnimator = null;
+ }
+
+ View view = findViewById(R.id.moved_item);
+ Path path = mCanvasView.getPath();
+ if (path.isEmpty()) {
+ return;
+ }
+
+ switch (checkedId) {
+ case R.id.named_components:
+ // Use the named "x" and "y" properties for individual (x, y)
+ // coordinates of the Path and set them on the view object.
+ // The setX(float) and setY(float) methods are called on view.
+ // An int version of this method also exists for animating
+ // int Properties.
+ mAnimator = ObjectAnimator.ofFloat(view, "x", "y", path);
+ break;
+ case R.id.property_components:
+ // Use two Properties for individual (x, y) coordinates of the Path
+ // and set them on the view object.
+ // An int version of this method also exists for animating
+ // int Properties.
+ mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
+ break;
+ case R.id.multi_int:
+ // Use a multi-int setter to animate along a Path. The method
+ // setCoordinates(int x, int y) is called on this during the animation.
+ // Either "setCoordinates" or "coordinates" are acceptable parameters
+ // because the "set" can be implied.
+ mAnimator = ObjectAnimator.ofMultiInt(this, "setCoordinates", path);
+ break;
+ case R.id.multi_float:
+ // Use a multi-float setter to animate along a Path. The method
+ // changeCoordinates(float x, float y) is called on this during the animation.
+ mAnimator = ObjectAnimator.ofMultiFloat(this, "changeCoordinates", path);
+ break;
+ case R.id.named_setter:
+ // Use the named "point" property to animate along the Path.
+ // There must be a method setPoint(PointF) on the animated object.
+ // Because setPoint takes a PointF parameter, no TypeConverter is necessary.
+ // In this case, the animated object is PathAnimations.
+ mAnimator = ObjectAnimator.ofObject(this, "point", null, path);
+ break;
+ case R.id.property_setter:
+ // Use the POINT_PROPERTY property to animate along the Path.
+ // POINT_PROPERTY takes a Point, not a PointF, so the TypeConverter
+ // PointFToPointConverter is necessary.
+ mAnimator = ObjectAnimator.ofObject(this, POINT_PROPERTY,
+ new PointFToPointConverter(), path);
+ break;
+ }
+
+ mAnimator.setDuration(10000);
+ mAnimator.setRepeatMode(Animation.RESTART);
+ mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ mAnimator.start();
+ }
+
+ public static class CanvasView extends FrameLayout {
+
+ Path mPath = new Path();
+
+ Paint mPathPaint = new Paint();
+
+ public CanvasView(Context context) {
+ super(context);
+ init();
+ }
+
+ public CanvasView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CanvasView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ setWillNotDraw(false);
+ mPathPaint.setColor(0xFFFF0000);
+ mPathPaint.setStrokeWidth(2.0f);
+ mPathPaint.setStyle(Paint.Style.STROKE);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed) {
+ Matrix scale = new Matrix();
+ float scaleWidth = (right-left)/TRAVERSE_PATH_SIZE;
+ float scaleHeight= (bottom-top)/TRAVERSE_PATH_SIZE;
+ scale.setScale(scaleWidth, scaleHeight);
+ sTraversalPath.transform(scale, mPath);
+ }
+ }
+
+ public Path getPath() {
+ return mPath;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawPath(mPath, mPathPaint);
+ super.draw(canvas);
+ }
+ }
+
+ private static class PointFToPointConverter extends TypeConverter<PointF, Point> {
+ Point mPoint = new Point();
+
+ public PointFToPointConverter() {
+ super(PointF.class, Point.class);
+ }
+
+ @Override
+ public Point convert(PointF value) {
+ mPoint.set(Math.round(value.x), Math.round(value.y));
+ return mPoint;
+ }
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
index db50185..a27dcdf 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
@@ -68,6 +68,9 @@
// The following keys are used to find each preference item
private static final String KEY_ENABLE_ADMIN = "key_enable_admin";
private static final String KEY_DISABLE_CAMERA = "key_disable_camera";
+ private static final String KEY_DISABLE_NOTIFICATIONS = "key_disable_notifications";
+ private static final String KEY_DISABLE_UNREDACTED = "key_disable_unredacted";
+ private static final String KEY_DISABLE_TRUST_AGENTS = "key_disable_trust_agents";
private static final String KEY_DISABLE_KEYGUARD_WIDGETS = "key_disable_keyguard_widgets";
private static final String KEY_DISABLE_KEYGUARD_SECURE_CAMERA
= "key_disable_keyguard_secure_camera";
@@ -128,6 +131,11 @@
return mDPM.isAdminActive(mDeviceAdminSample);
}
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ return GeneralFragment.class.getName().equals(fragmentName);
+ }
+
/**
* Common fragment code for DevicePolicyManager access. Provides two shared elements:
*
@@ -250,6 +258,9 @@
private CheckBoxPreference mDisableCameraCheckbox;
private CheckBoxPreference mDisableKeyguardWidgetsCheckbox;
private CheckBoxPreference mDisableKeyguardSecureCameraCheckbox;
+ private CheckBoxPreference mDisableKeyguardNotificationCheckbox;
+ private CheckBoxPreference mDisableKeyguardTrustAgentCheckbox;
+ private CheckBoxPreference mDisableKeyguardUnredactedCheckbox;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -257,14 +268,29 @@
addPreferencesFromResource(R.xml.device_admin_general);
mEnableCheckbox = (CheckBoxPreference) findPreference(KEY_ENABLE_ADMIN);
mEnableCheckbox.setOnPreferenceChangeListener(this);
+
mDisableCameraCheckbox = (CheckBoxPreference) findPreference(KEY_DISABLE_CAMERA);
mDisableCameraCheckbox.setOnPreferenceChangeListener(this);
+
mDisableKeyguardWidgetsCheckbox =
(CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_WIDGETS);
mDisableKeyguardWidgetsCheckbox.setOnPreferenceChangeListener(this);
+
mDisableKeyguardSecureCameraCheckbox =
(CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_SECURE_CAMERA);
mDisableKeyguardSecureCameraCheckbox.setOnPreferenceChangeListener(this);
+
+ mDisableKeyguardNotificationCheckbox =
+ (CheckBoxPreference) findPreference(KEY_DISABLE_NOTIFICATIONS);
+ mDisableKeyguardNotificationCheckbox.setOnPreferenceChangeListener(this);
+
+ mDisableKeyguardUnredactedCheckbox =
+ (CheckBoxPreference) findPreference(KEY_DISABLE_UNREDACTED);
+ mDisableKeyguardUnredactedCheckbox.setOnPreferenceChangeListener(this);
+
+ mDisableKeyguardTrustAgentCheckbox =
+ (CheckBoxPreference) findPreference(KEY_DISABLE_TRUST_AGENTS);
+ mDisableKeyguardTrustAgentCheckbox.setOnPreferenceChangeListener(this);
}
// At onResume time, reload UI with current values as required
@@ -287,6 +313,12 @@
DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL : 0;
flags |= mDisableKeyguardSecureCameraCheckbox.isChecked() ?
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA : 0;
+ flags |= mDisableKeyguardNotificationCheckbox.isChecked() ?
+ DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS : 0;
+ flags |= mDisableKeyguardUnredactedCheckbox.isChecked() ?
+ DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS : 0;
+ flags |= mDisableKeyguardTrustAgentCheckbox.isChecked() ?
+ DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS : 0;
return flags;
}
@@ -317,7 +349,10 @@
mDPM.setCameraDisabled(mDeviceAdminSample, value);
reloadSummaries();
} else if (preference == mDisableKeyguardWidgetsCheckbox
- || preference == mDisableKeyguardSecureCameraCheckbox) {
+ || preference == mDisableKeyguardSecureCameraCheckbox
+ || preference == mDisableKeyguardNotificationCheckbox
+ || preference == mDisableKeyguardUnredactedCheckbox
+ || preference == mDisableKeyguardTrustAgentCheckbox) {
mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample, createKeyguardDisabledFlag());
reloadSummaries();
}
@@ -342,6 +377,24 @@
(disabled & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0 ?
R.string.keyguard_secure_camera_disabled : R.string.keyguard_secure_camera_enabled);
mDisableKeyguardSecureCameraCheckbox.setSummary(keyguardSecureCameraSummary);
+
+ String keyguardSecureNotificationsSummary = getString(
+ (disabled & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) != 0 ?
+ R.string.keyguard_secure_notifications_disabled
+ : R.string.keyguard_secure_notifications_enabled);
+ mDisableKeyguardNotificationCheckbox.setSummary(keyguardSecureNotificationsSummary);
+
+ String keyguardUnredactedSummary = getString(
+ (disabled & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) != 0
+ ? R.string.keyguard_unredacted_notifications_disabled
+ : R.string.keyguard_unredacted_notifications_enabled);
+ mDisableKeyguardUnredactedCheckbox.setSummary(keyguardUnredactedSummary);
+
+ String keyguardEnableTrustAgentSummary = getString(
+ (disabled & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0 ?
+ R.string.keyguard_trust_agents_disabled
+ : R.string.keyguard_trust_agents_enabled);
+ mDisableKeyguardTrustAgentCheckbox.setSummary(keyguardEnableTrustAgentSummary);
}
/** Updates the device capabilities area (dis/enabling) as the admin is (de)activated */
@@ -349,6 +402,9 @@
mDisableCameraCheckbox.setEnabled(enabled);
mDisableKeyguardWidgetsCheckbox.setEnabled(enabled);
mDisableKeyguardSecureCameraCheckbox.setEnabled(enabled);
+ mDisableKeyguardNotificationCheckbox.setEnabled(enabled);
+ mDisableKeyguardUnredactedCheckbox.setEnabled(enabled);
+ mDisableKeyguardTrustAgentCheckbox.setEnabled(enabled);
}
}
diff --git a/samples/ApiDemos/src/com/example/android/apis/content/DocumentsSample.java b/samples/ApiDemos/src/com/example/android/apis/content/DocumentsSample.java
new file mode 100644
index 0000000..544e637
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/content/DocumentsSample.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2013 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.example.android.apis.content;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Example that exercises client side of {@link DocumentsContract}.
+ */
+public class DocumentsSample extends Activity {
+ private static final String TAG = "DocumentsSample";
+
+ private static final int CODE_READ = 42;
+ private static final int CODE_WRITE = 43;
+ private static final int CODE_PICK = 44;
+
+ private TextView mResult;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Context context = this;
+
+ final LinearLayout view = new LinearLayout(context);
+ view.setOrientation(LinearLayout.VERTICAL);
+
+ mResult = new TextView(context);
+ view.addView(mResult);
+
+ final CheckBox multiple = new CheckBox(context);
+ multiple.setText("ALLOW_MULTIPLE");
+ view.addView(multiple);
+ final CheckBox localOnly = new CheckBox(context);
+ localOnly.setText("LOCAL_ONLY");
+ view.addView(localOnly);
+
+ Button button;
+ button = new Button(context);
+ button.setText("OPEN_DOC */*");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ if (multiple.isChecked()) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(intent, CODE_READ);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("OPEN_DOC image/*");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("image/*");
+ if (multiple.isChecked()) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(intent, CODE_READ);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("OPEN_DOC audio/ogg");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("audio/ogg");
+ if (multiple.isChecked()) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(intent, CODE_READ);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("OPEN_DOC text/plain, application/msword");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
+ "text/plain", "application/msword" });
+ if (multiple.isChecked()) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(intent, CODE_READ);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("CREATE_DOC text/plain");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(intent, CODE_WRITE);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("CREATE_DOC image/png");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("image/png");
+ intent.putExtra(Intent.EXTRA_TITLE, "mypicture.png");
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(intent, CODE_WRITE);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("GET_CONTENT */*");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ if (multiple.isChecked()) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_READ);
+ }
+ });
+ view.addView(button);
+
+ button = new Button(context);
+ button.setText("PICK_DIRECTORY");
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_PICK_DIRECTORY);
+ if (localOnly.isChecked()) {
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ }
+ startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_PICK);
+ }
+ });
+ view.addView(button);
+
+ final ScrollView scroll = new ScrollView(context);
+ scroll.addView(view);
+
+ setContentView(scroll);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ final ContentResolver cr = getContentResolver();
+
+ clearLog();
+
+ log("resultCode=" + resultCode);
+ log("data=" + String.valueOf(data));
+
+ final Uri uri = data != null ? data.getData() : null;
+ if (uri != null) {
+ log("isDocumentUri=" + DocumentsContract.isDocumentUri(this, uri));
+ } else {
+ log("missing URI?");
+ return;
+ }
+
+ if (requestCode == CODE_READ) {
+ try {
+ cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ } catch (SecurityException e) {
+ log("FAILED TO TAKE PERMISSION", e);
+ }
+ InputStream is = null;
+ try {
+ is = cr.openInputStream(uri);
+ log("read length=" + readFullyNoClose(is).length);
+ } catch (Exception e) {
+ log("FAILED TO READ", e);
+ } finally {
+ closeQuietly(is);
+ }
+ } else if (requestCode == CODE_WRITE) {
+ try {
+ cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ } catch (SecurityException e) {
+ log("FAILED TO TAKE PERMISSION", e);
+ }
+ OutputStream os = null;
+ try {
+ os = cr.openOutputStream(uri);
+ os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
+ log("wrote data");
+ } catch (Exception e) {
+ log("FAILED TO WRITE", e);
+ } finally {
+ closeQuietly(os);
+ }
+ } else if (requestCode == CODE_PICK) {
+ // Find existing docs
+ Uri doc = DocumentsContract.buildDocumentViaUri(uri,
+ DocumentsContract.getViaDocumentId(uri));
+ Uri child = DocumentsContract.buildChildDocumentsViaUri(uri,
+ DocumentsContract.getViaDocumentId(uri));
+ Cursor c = cr.query(child, new String[] {
+ Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE }, null, null, null);
+ try {
+ while (c.moveToNext()) {
+ log("found child=" + c.getString(0) + ", mime=" + c.getString(1));
+ }
+ } finally {
+ closeQuietly(c);
+ }
+
+ // Create some documents
+ Uri pic = DocumentsContract.createDocument(cr, doc, "image/png", "pic.png");
+ Uri dir = DocumentsContract.createDocument(cr, doc, Document.MIME_TYPE_DIR, "my dir");
+ Uri dirPic = DocumentsContract.createDocument(cr, dir, "image/png", "pic2.png");
+
+ log("created " + pic);
+ log("created " + dir);
+ log("created " + dirPic);
+
+ // Write to one of them
+ OutputStream os = null;
+ try {
+ os = cr.openOutputStream(dirPic);
+ os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
+ log("wrote data");
+ } catch (Exception e) {
+ log("FAILED TO WRITE", e);
+ } finally {
+ closeQuietly(os);
+ }
+
+ // And delete the first pic
+ if (DocumentsContract.deleteDocument(cr, pic)) {
+ log("deleted untouched pic");
+ } else {
+ log("FAILED TO DELETE PIC");
+ }
+ }
+ }
+
+ private void clearLog() {
+ mResult.setText(null);
+ }
+
+ private void log(String msg) {
+ log(msg, null);
+ }
+
+ private void log(String msg, Throwable t) {
+ Log.d(TAG, msg, t);
+ mResult.setText(mResult.getText() + "\n" + msg);
+ }
+
+ public static byte[] readFullyNoClose(InputStream in) throws IOException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytes.write(buffer, 0, count);
+ }
+ return bytes.toByteArray();
+ }
+
+ public static void closeQuietly(AutoCloseable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ }
+ }
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java b/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java
deleted file mode 100644
index 9863222..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2007 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.example.android.apis.os;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-
-/**
- * <h3>Application that displays the values of the acceleration sensor graphically.</h3>
-
-<p>This demonstrates the {@link android.hardware.SensorManager android.hardware.SensorManager} class.
-
-<h4>Demo</h4>
-OS / Sensors
-
-<h4>Source files</h4>
- * <table class="LinkTable">
- * <tr>
- * <td >src/com.example.android.apis/os/Sensors.java</td>
- * <td >Sensors</td>
- * </tr>
- * </table>
- */
-public class Sensors extends Activity {
- private SensorManager mSensorManager;
- private GraphView mGraphView;
-
- private class GraphView extends View implements SensorEventListener
- {
- private Bitmap mBitmap;
- private Paint mPaint = new Paint();
- private Canvas mCanvas = new Canvas();
- private Path mPath = new Path();
- private RectF mRect = new RectF();
- private float mLastValues[] = new float[3*2];
- private float mOrientationValues[] = new float[3];
- private int mColors[] = new int[3*2];
- private float mLastX;
- private float mScale[] = new float[2];
- private float mYOffset;
- private float mMaxX;
- private float mSpeed = 1.0f;
- private float mWidth;
- private float mHeight;
-
- public GraphView(Context context) {
- super(context);
- mColors[0] = Color.argb(192, 255, 64, 64);
- mColors[1] = Color.argb(192, 64, 128, 64);
- mColors[2] = Color.argb(192, 64, 64, 255);
- mColors[3] = Color.argb(192, 64, 255, 255);
- mColors[4] = Color.argb(192, 128, 64, 128);
- mColors[5] = Color.argb(192, 255, 255, 64);
-
- mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mRect.set(-0.5f, -0.5f, 0.5f, 0.5f);
- mPath.arcTo(mRect, 0, 180);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
- mCanvas.setBitmap(mBitmap);
- mCanvas.drawColor(0xFFFFFFFF);
- mYOffset = h * 0.5f;
- mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
- mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
- mWidth = w;
- mHeight = h;
- if (mWidth < mHeight) {
- mMaxX = w;
- } else {
- mMaxX = w-50;
- }
- mLastX = mMaxX;
- super.onSizeChanged(w, h, oldw, oldh);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- synchronized (this) {
- if (mBitmap != null) {
- final Paint paint = mPaint;
- final Path path = mPath;
- final int outer = 0xFFC0C0C0;
- final int inner = 0xFFff7010;
-
- if (mLastX >= mMaxX) {
- mLastX = 0;
- final Canvas cavas = mCanvas;
- final float yoffset = mYOffset;
- final float maxx = mMaxX;
- final float oneG = SensorManager.STANDARD_GRAVITY * mScale[0];
- paint.setColor(0xFFAAAAAA);
- cavas.drawColor(0xFFFFFFFF);
- cavas.drawLine(0, yoffset, maxx, yoffset, paint);
- cavas.drawLine(0, yoffset+oneG, maxx, yoffset+oneG, paint);
- cavas.drawLine(0, yoffset-oneG, maxx, yoffset-oneG, paint);
- }
- canvas.drawBitmap(mBitmap, 0, 0, null);
-
- float[] values = mOrientationValues;
- if (mWidth < mHeight) {
- float w0 = mWidth * 0.333333f;
- float w = w0 - 32;
- float x = w0*0.5f;
- for (int i=0 ; i<3 ; i++) {
- canvas.save(Canvas.MATRIX_SAVE_FLAG);
- canvas.translate(x, w*0.5f + 4.0f);
- canvas.save(Canvas.MATRIX_SAVE_FLAG);
- paint.setColor(outer);
- canvas.scale(w, w);
- canvas.drawOval(mRect, paint);
- canvas.restore();
- canvas.scale(w-5, w-5);
- paint.setColor(inner);
- canvas.rotate(-values[i]);
- canvas.drawPath(path, paint);
- canvas.restore();
- x += w0;
- }
- } else {
- float h0 = mHeight * 0.333333f;
- float h = h0 - 32;
- float y = h0*0.5f;
- for (int i=0 ; i<3 ; i++) {
- canvas.save(Canvas.MATRIX_SAVE_FLAG);
- canvas.translate(mWidth - (h*0.5f + 4.0f), y);
- canvas.save(Canvas.MATRIX_SAVE_FLAG);
- paint.setColor(outer);
- canvas.scale(h, h);
- canvas.drawOval(mRect, paint);
- canvas.restore();
- canvas.scale(h-5, h-5);
- paint.setColor(inner);
- canvas.rotate(-values[i]);
- canvas.drawPath(path, paint);
- canvas.restore();
- y += h0;
- }
- }
-
- }
- }
- }
-
- public void onSensorChanged(SensorEvent event) {
- //Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " + values[1] + ", z: " + values[2]);
- synchronized (this) {
- if (mBitmap != null) {
- final Canvas canvas = mCanvas;
- final Paint paint = mPaint;
- if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
- for (int i=0 ; i<3 ; i++) {
- mOrientationValues[i] = event.values[i];
- }
- } else {
- float deltaX = mSpeed;
- float newX = mLastX + deltaX;
-
- int j = (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) ? 1 : 0;
- for (int i=0 ; i<3 ; i++) {
- int k = i+j*3;
- final float v = mYOffset + event.values[i] * mScale[j];
- paint.setColor(mColors[k]);
- canvas.drawLine(mLastX, mLastValues[k], newX, v, paint);
- mLastValues[k] = v;
- }
- if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
- mLastX += mSpeed;
- }
- invalidate();
- }
- }
- }
-
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
- }
-
- /**
- * Initialization of the Activity after it is first created. Must at least
- * call {@link android.app.Activity#setContentView setContentView()} to
- * describe what is to be displayed in the screen.
- */
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // Be sure to call the super class.
- super.onCreate(savedInstanceState);
-
- mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
- mGraphView = new GraphView(this);
- setContentView(mGraphView);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mSensorManager.registerListener(mGraphView,
- mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
- SensorManager.SENSOR_DELAY_FASTEST);
- mSensorManager.registerListener(mGraphView,
- mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
- SensorManager.SENSOR_DELAY_FASTEST);
- mSensorManager.registerListener(mGraphView,
- mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
- SensorManager.SENSOR_DELAY_FASTEST);
- }
-
- @Override
- protected void onStop() {
- mSensorManager.unregisterListener(mGraphView);
- super.onStop();
- }
-}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Controls7.java b/samples/ApiDemos/src/com/example/android/apis/view/Controls7.java
new file mode 100644
index 0000000..6243d3b
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Controls7.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 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.example.android.apis.view;
+
+public class Controls7 extends Controls1 {}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Controls8.java b/samples/ApiDemos/src/com/example/android/apis/view/Controls8.java
new file mode 100644
index 0000000..4dd4291
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Controls8.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 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.example.android.apis.view;
+
+public class Controls8 extends Controls1 {}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Controls9.java b/samples/ApiDemos/src/com/example/android/apis/view/Controls9.java
new file mode 100644
index 0000000..8a940aa
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/Controls9.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 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.example.android.apis.view;
+
+public class Controls9 extends Controls1 {}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java b/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java
deleted file mode 100644
index b252d5a..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2007 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.example.android.apis.view;
-
-import com.example.android.apis.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.ImageView;
-import android.widget.Toast;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-
-public class Gallery1 extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.gallery_1);
-
- // Reference the Gallery view
- Gallery g = (Gallery) findViewById(R.id.gallery);
- // Set the adapter to our custom adapter (below)
- g.setAdapter(new ImageAdapter(this));
-
- // Set a item click listener, and just Toast the clicked position
- g.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- Toast.makeText(Gallery1.this, "" + position, Toast.LENGTH_SHORT).show();
- }
- });
-
- // We also want to show context menu for longpressed items in the gallery
- registerForContextMenu(g);
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- menu.add(R.string.gallery_2_text);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
- Toast.makeText(this, "Longpress: " + info.position, Toast.LENGTH_SHORT).show();
- return true;
- }
-
- public class ImageAdapter extends BaseAdapter {
- private static final int ITEM_WIDTH = 136;
- private static final int ITEM_HEIGHT = 88;
-
- private final int mGalleryItemBackground;
- private final Context mContext;
-
- private final Integer[] mImageIds = {
- R.drawable.gallery_photo_1,
- R.drawable.gallery_photo_2,
- R.drawable.gallery_photo_3,
- R.drawable.gallery_photo_4,
- R.drawable.gallery_photo_5,
- R.drawable.gallery_photo_6,
- R.drawable.gallery_photo_7,
- R.drawable.gallery_photo_8
- };
-
- private final float mDensity;
-
- public ImageAdapter(Context c) {
- mContext = c;
- // See res/values/attrs.xml for the <declare-styleable> that defines
- // Gallery1.
- TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
- mGalleryItemBackground = a.getResourceId(
- R.styleable.Gallery1_android_galleryItemBackground, 0);
- a.recycle();
-
- mDensity = c.getResources().getDisplayMetrics().density;
- }
-
- public int getCount() {
- return mImageIds.length;
- }
-
- public Object getItem(int position) {
- return position;
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- ImageView imageView;
- if (convertView == null) {
- convertView = new ImageView(mContext);
-
- imageView = (ImageView) convertView;
- imageView.setScaleType(ImageView.ScaleType.FIT_XY);
- imageView.setLayoutParams(new Gallery.LayoutParams(
- (int) (ITEM_WIDTH * mDensity + 0.5f),
- (int) (ITEM_HEIGHT * mDensity + 0.5f)));
-
- // The preferred Gallery item background
- imageView.setBackgroundResource(mGalleryItemBackground);
- } else {
- imageView = (ImageView) convertView;
- }
-
- imageView.setImageResource(mImageIds[position]);
-
- return imageView;
- }
- }
-}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java b/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java
deleted file mode 100644
index ed33451..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2007 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.example.android.apis.view;
-
-import android.app.Activity;
-import android.database.Cursor;
-import android.provider.ContactsContract.Contacts;
-import android.os.Bundle;
-import android.widget.Gallery;
-import android.widget.SimpleCursorAdapter;
-import android.widget.SpinnerAdapter;
-
-// Need the following import to get access to the app resources, since this
-// class is in a sub-package.
-import com.example.android.apis.R;
-
-public class Gallery2 extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.gallery_2);
-
- // Get a cursor with all people
- Cursor c = getContentResolver().query(Contacts.CONTENT_URI,
- CONTACT_PROJECTION, null, null, null);
- startManagingCursor(c);
-
- SpinnerAdapter adapter = new SimpleCursorAdapter(this,
- // Use a template that displays a text view
- android.R.layout.simple_gallery_item,
- // Give the cursor to the list adatper
- c,
- // Map the NAME column in the people database to...
- new String[] {Contacts.DISPLAY_NAME},
- // The "text1" view defined in the XML template
- new int[] { android.R.id.text1 });
-
- Gallery g = (Gallery) findViewById(R.id.gallery);
- g.setAdapter(adapter);
- }
-
- private static final String[] CONTACT_PROJECTION = new String[] {
- Contacts._ID,
- Contacts.DISPLAY_NAME
- };
-}
\ No newline at end of file
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java b/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java
deleted file mode 100644
index 7f17c82..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2007 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.example.android.apis.view;
-
-import com.example.android.apis.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.animation.AnimationUtils;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.Gallery.LayoutParams;
-import android.widget.ImageSwitcher;
-import android.widget.ImageView;
-import android.widget.ViewSwitcher;
-
-
-public class ImageSwitcher1 extends Activity implements
- AdapterView.OnItemSelectedListener, ViewSwitcher.ViewFactory {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
-
- setContentView(R.layout.image_switcher_1);
-
- mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
- mSwitcher.setFactory(this);
- mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
- android.R.anim.fade_in));
- mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
- android.R.anim.fade_out));
-
- Gallery g = (Gallery) findViewById(R.id.gallery);
- g.setAdapter(new ImageAdapter(this));
- g.setOnItemSelectedListener(this);
- }
-
- public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
- mSwitcher.setImageResource(mImageIds[position]);
- }
-
- public void onNothingSelected(AdapterView<?> parent) {
- }
-
- public View makeView() {
- ImageView i = new ImageView(this);
- i.setBackgroundColor(0xFF000000);
- i.setScaleType(ImageView.ScaleType.FIT_CENTER);
- i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT));
- return i;
- }
-
- private ImageSwitcher mSwitcher;
-
- public class ImageAdapter extends BaseAdapter {
- public ImageAdapter(Context c) {
- mContext = c;
- }
-
- public int getCount() {
- return mThumbIds.length;
- }
-
- public Object getItem(int position) {
- return position;
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- ImageView i = new ImageView(mContext);
-
- i.setImageResource(mThumbIds[position]);
- i.setAdjustViewBounds(true);
- i.setLayoutParams(new Gallery.LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- i.setBackgroundResource(R.drawable.picture_frame);
- return i;
- }
-
- private Context mContext;
-
- }
-
- private Integer[] mThumbIds = {
- R.drawable.sample_thumb_0, R.drawable.sample_thumb_1,
- R.drawable.sample_thumb_2, R.drawable.sample_thumb_3,
- R.drawable.sample_thumb_4, R.drawable.sample_thumb_5,
- R.drawable.sample_thumb_6, R.drawable.sample_thumb_7};
-
- private Integer[] mImageIds = {
- R.drawable.sample_0, R.drawable.sample_1, R.drawable.sample_2,
- R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5,
- R.drawable.sample_6, R.drawable.sample_7};
-
-}
diff --git a/samples/AtscTvInput/Android.mk b/samples/AtscTvInput/Android.mk
new file mode 100644
index 0000000..f7c60a7
--- /dev/null
+++ b/samples/AtscTvInput/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := AtscTvInput
+LOCAL_MODULE_TAGS := samples
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/samples/AtscTvInput/AndroidManifest.xml b/samples/AtscTvInput/AndroidManifest.xml
new file mode 100644
index 0000000..5fe48e5
--- /dev/null
+++ b/samples/AtscTvInput/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.example.atsctvinput">
+
+ <uses-permission android:name="android.permission.READ_EPG_DATA" />
+ <uses-permission android:name="android.permission.WRITE_EPG_DATA" />
+
+ <application android:label="@string/atsc_tv_input">
+ <activity android:name="com.example.android.atsctvinput.AtscTvInputScanActivity"
+ android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.tv.SetupActivity" />
+ </intent-filter>
+ </activity>
+ <service android:name="com.example.android.atsctvinput.AtscTvInputService"
+ android:permission="android.permission.BIND_TV_INPUT"
+ android:process=":remoteAtscTvInput">
+ <intent-filter>
+ <action android:name="android.tv.TvInputService" />
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/samples/AtscTvInput/_index.html b/samples/AtscTvInput/_index.html
new file mode 100644
index 0000000..3e104d1
--- /dev/null
+++ b/samples/AtscTvInput/_index.html
@@ -0,0 +1,7 @@
+<p>
+A sample application that demonstrates how to implement TV input service.
+This sample uses captured ATSC streams which includes videos and channel
+and program information. On a setup request, this app registers channels and
+programs to the framework. Also, it plays the video when the framework tunes
+to the channel.
+</p>
diff --git a/samples/AtscTvInput/res/raw/freq_1_prog_1.mpg b/samples/AtscTvInput/res/raw/freq_1_prog_1.mpg
new file mode 100644
index 0000000..276bcca
--- /dev/null
+++ b/samples/AtscTvInput/res/raw/freq_1_prog_1.mpg
Binary files differ
diff --git a/samples/AtscTvInput/res/raw/freq_2_prog_1029.mpg b/samples/AtscTvInput/res/raw/freq_2_prog_1029.mpg
new file mode 100644
index 0000000..55a4a76
--- /dev/null
+++ b/samples/AtscTvInput/res/raw/freq_2_prog_1029.mpg
Binary files differ
diff --git a/samples/AtscTvInput/res/values/strings.xml b/samples/AtscTvInput/res/values/strings.xml
new file mode 100644
index 0000000..815c821
--- /dev/null
+++ b/samples/AtscTvInput/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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>
+ <string name="atsc_tv_input">AtscTvInput</string>
+ <string name="label">ATSC Sample Input</string>
+ <string name="channel_scan_message">Scanning channels, please wait...</string>
+</resources>
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputScanActivity.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputScanActivity.java
new file mode 100644
index 0000000..e8cb6ac
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputScanActivity.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 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.example.android.atsctvinput;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ContentValues;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.TvContract;
+import android.util.Log;
+import android.util.Pair;
+
+import com.example.android.atsctvinput.SampleTsStream.TsStream;
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+import com.example.atsctvinput.R;
+
+import java.util.List;
+
+/**
+ * The scan/setup activity for ATSC TvInput app.
+ */
+public class AtscTvInputScanActivity extends Activity {
+ private static final String TAG = "AtscTvInputScanActivity";
+ private static final long FAKE_SCANTIME_PER_CHANNEL_MS = 1000;
+ private ProgressDialog mProgressDialog;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mProgressDialog = new ProgressDialog(this);
+ mProgressDialog.setMessage(getResources().getString(R.string.channel_scan_message));
+ mProgressDialog.setCancelable(false);
+
+ mProgressDialog.show();
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ clearChannels();
+ doAutoScan();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ mProgressDialog.hide();
+ AtscTvInputScanActivity.this.setResult(Activity.RESULT_OK);
+ AtscTvInputScanActivity.this.finish();
+ }
+ }.execute();
+ }
+
+ private void clearChannels() {
+ String selection = TvContract.Channels.COLUMN_SERVICE_NAME + " = ?";
+ String[] selectionArgs = new String[] {
+ AtscTvInputService.class.getName()
+ };
+ getContentResolver().delete(TvContract.Channels.CONTENT_URI, selection, selectionArgs);
+ }
+
+ private void doAutoScan() {
+ for (TsStream s : SampleTsStream.SAMPLES) {
+ Pair<VCTItem, List<EITItem>> result = SampleTsStream.extractChannelInfo(this, s);
+ if (result != null) {
+ insertChannel(result.first, s);
+ try {
+ Thread.sleep(FAKE_SCANTIME_PER_CHANNEL_MS);
+ } catch (InterruptedException e) {
+ // Do nothing.
+ }
+ }
+ }
+ }
+
+ public void insertChannel(VCTItem channel, TsStream stream) {
+ Log.d(TAG, "Channel " + channel.getShortName() + " " + channel.getMajorChannelNumber()
+ + "-" + channel.getMinorChannelNumber() + " is detected.");
+ ContentValues values = new ContentValues();
+ values.put(TvContract.Channels.COLUMN_SERVICE_NAME, AtscTvInputService.class.getName());
+ values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER,
+ channel.getMajorChannelNumber() + "-" + channel.getMinorChannelNumber());
+ values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.getShortName());
+ values.put(TvContract.Channels.COLUMN_DATA, SampleTsStream.getTuneInfo(stream));
+ getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+ }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputService.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputService.java
new file mode 100644
index 0000000..faefcee
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/AtscTvInputService.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014 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.example.android.atsctvinput;
+
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.TvContract;
+import android.tv.TvInputService;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import com.example.android.atsctvinput.SampleTsStream.TsStream;
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+
+import java.util.List;
+
+/**
+ * A sample TvInputService which plays ATSC TV stream.
+ */
+public class AtscTvInputService extends TvInputService {
+ private static final String TAG = "AtscTvInputService";
+ private static final int SEC_IN_MS = 1000;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.d(TAG, "onCreate()");
+ setAvailable(true);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d(TAG, "onDestroy()");
+ }
+
+ @Override
+ public TvInputSessionImpl onCreateSession() {
+ return new MyTvInputSessionImpl();
+ }
+
+
+ public TsStream getTsStreamForChannel(Uri channelUri) {
+ String[] projection = { TvContract.Channels.COLUMN_DATA };
+ if (channelUri == null) {
+ return null;
+ }
+ Cursor cursor = this.getContentResolver().query(
+ channelUri, projection, null, null, null);
+ if (cursor == null) {
+ return null;
+ }
+ if (cursor.getCount() < 1) {
+ cursor.close();
+ return null;
+ }
+ cursor.moveToNext();
+ TsStream stream = SampleTsStream.getTsStreamFromTuneInfo(cursor.getString(0));
+ cursor.close();
+ return stream;
+ }
+
+ private class MyTvInputSessionImpl extends TvInputSessionImpl {
+ private MediaPlayer mPlayer;
+
+ protected MyTvInputSessionImpl() {
+ mPlayer = new MediaPlayer();
+ }
+
+ @Override
+ public void onRelease() {
+ if (mPlayer != null) {
+ mPlayer.release();
+ mPlayer = null;
+ }
+ }
+
+ @Override
+ public boolean onSetSurface(Surface surface) {
+ Log.d(TAG, "onSetSurface(" + surface + ")");
+ mPlayer.setSurface(surface);
+ return true;
+ }
+
+ @Override
+ public void onSetVolume(float volume) {
+ Log.d(TAG, "onSetVolume(" + volume + ")");
+ mPlayer.setVolume(volume, volume);
+ }
+
+ @Override
+ public boolean onTune(Uri channelUri) {
+ Log.d(TAG, "onTune(" + channelUri + ")");
+ mPlayer.reset();
+ TsStream stream = getTsStreamForChannel(channelUri);
+ if (stream == null) {
+ return false;
+ }
+ new ProgramUpdateTask().execute(stream, channelUri);
+ AssetFileDescriptor afd = getResources().openRawResourceFd(stream.mResourceId);
+ try {
+ mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
+ afd.getLength());
+ mPlayer.prepare();
+ afd.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to tune to(" + channelUri + ")");
+ mPlayer.reset();
+ return false;
+ }
+ mPlayer.start();
+ return true;
+ }
+ }
+
+ private class ProgramUpdateTask extends AsyncTask<Object, Void, Void> {
+ @Override
+ protected Void doInBackground(Object... objs) {
+ TsStream stream = (TsStream) objs[0];
+ Uri channelUri = (Uri) objs[1];
+ Pair<VCTItem, List<EITItem>> result =
+ SampleTsStream.extractChannelInfo(AtscTvInputService.this, stream);
+ if (result == null) {
+ return null;
+ }
+ clearPrograms(channelUri);
+ // The sample streams have passed timestamps. In order to show the metadata properly in
+ // TV app, we offset the time here.
+ long timeOffsetMs = Long.MIN_VALUE;
+ long currentTimeMs = System.currentTimeMillis();
+ for (EITItem i : result.second) {
+ if (timeOffsetMs == Long.MIN_VALUE) {
+ timeOffsetMs = currentTimeMs - i.getStartTime() * SEC_IN_MS;
+ }
+ insertProgram(channelUri, i, timeOffsetMs);
+ }
+ return null;
+ }
+
+ private void clearPrograms(Uri channelUri) {
+ String selection = TvContract.Programs.COLUMN_CHANNEL_ID + " = ?";
+ String[] selectionArgs =
+ new String[] { Long.toString(ContentUris.parseId(channelUri)) };
+ getContentResolver().delete(TvContract.Programs.CONTENT_URI, selection, selectionArgs);
+ }
+
+ private Uri insertProgram(Uri channelUri, EITItem event, long timeOffsetMs) {
+ Log.d(TAG, "insertProgram " + event.getTitleText());
+ ContentValues values = new ContentValues();
+ values.put(TvContract.Programs.COLUMN_CHANNEL_ID, ContentUris.parseId(channelUri));
+ values.put(TvContract.Programs.COLUMN_TITLE, event.getTitleText());
+ values.put(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, timeOffsetMs
+ + event.getStartTime() * SEC_IN_MS);
+ values.put(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, timeOffsetMs
+ + (event.getStartTime() + event.getLengthInSecond()) * SEC_IN_MS);
+ return getContentResolver().insert(
+ TvContract.Programs.CONTENT_URI, values);
+ }
+ }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/PSIPParser.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/PSIPParser.java
new file mode 100644
index 0000000..cb3480c
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/PSIPParser.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 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.example.android.atsctvinput;
+
+import android.util.Log;
+
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.MGTItem;
+import com.example.android.atsctvinput.SectionParser.OutputListener;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ATSC Program and System Information Protocol (PSIP) parser.
+ */
+public class PSIPParser {
+ private static final String TAG = "PSIPParser";
+
+ public static final int ATSC_SI_BASE_PID = 0x1ffb;
+ private static final int TS_PACKET_START_CODE = 0x47;
+ private static final int TS_PACKET_SIZE = 188;
+
+ private Map<Integer, Stream> mStreamMap = new HashMap<Integer, Stream>();
+ private Map<Integer, VCTItem> mSourceIdToVCTItemMap = new HashMap<Integer, VCTItem>();
+ private SectionParser mSectionParser;
+ private PSIPOutputListener mListener;
+
+ private int mPartialTSPacketSize;
+ private byte[] mPartialTSPacketBuf = new byte[TS_PACKET_SIZE];
+
+ public interface PSIPOutputListener {
+ void onEITPidDetected(int pid);
+ void onEITItemParsed(VCTItem channel, List<EITItem> items);
+ }
+
+ private class Stream {
+ private static final int INVALID_CONTINUITY_COUNTER = -1;
+ private static final int NUM_CONTINUITY_COUNTER = 16;
+
+ int mContinuityCounter = INVALID_CONTINUITY_COUNTER;
+ byte[] mData = new byte[0];
+
+ public void feedData(byte[] data, int continuityCounter, boolean startIndicator) {
+ if ((mContinuityCounter + 1) % NUM_CONTINUITY_COUNTER
+ != continuityCounter) {
+ mData = new byte[0];
+ }
+ mContinuityCounter = continuityCounter;
+ int startPos = 0;
+ if (mData.length == 0) {
+ if (startIndicator) {
+ startPos = (data[0] & 0xff) + 1;
+ } else {
+ // Don't know where the section starts yet. Wait until start indicator is on.
+ return;
+ }
+ } else {
+ if (startIndicator) {
+ startPos = 1;
+ }
+ }
+ int prevSize = mData.length;
+ mData = Arrays.copyOf(mData, mData.length + data.length - startPos);
+ System.arraycopy(data, startPos, mData, prevSize, data.length - startPos);
+ parseSectionIfAny();
+ }
+
+ private void parseSectionIfAny() {
+ while (mData.length >= 3) {
+ if ((mData[0] & 0xff) == 0xff) {
+ // Clear stuffing bytes according to H222.0 section 2.4.4.
+ mData = new byte[0];
+ break;
+ }
+ int sectionLength = (((mData[1] & 0x0f) << 8) | (mData[2] & 0xff) + 3);
+ if (mData.length < sectionLength) {
+ break;
+ }
+ Log.d(TAG, "parseSection 0x" + Integer.toHexString(mData[0] & 0xff));
+ parseSection(Arrays.copyOfRange(mData, 0, sectionLength));
+ mData = Arrays.copyOfRange(mData, sectionLength, mData.length);
+ }
+ }
+ }
+
+ private OutputListener mSectionListener = new OutputListener() {
+ @Override
+ public void onMGTParsed(List<MGTItem> items) {
+ for (MGTItem i : items) {
+ if (i.getTableType() == MGTItem.TABLE_TYPE_EIT_0
+ && mStreamMap.get(i.getTableTypePid()) == null) {
+ mStreamMap.put(i.getTableTypePid(), new Stream());
+ if (mListener != null) {
+ mListener.onEITPidDetected(i.getTableTypePid());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onVCTParsed(List<VCTItem> items) {
+ for (VCTItem i : items) {
+ mSourceIdToVCTItemMap.put(i.getSourceId(), i);
+ }
+ }
+
+ @Override
+ public void onEITParsed(int sourceId, List<EITItem> items) {
+ Log.d(TAG, "onEITParsed " + sourceId);
+ VCTItem channel = mSourceIdToVCTItemMap.get(sourceId);
+ if (channel != null && mListener != null) {
+ mListener.onEITItemParsed(channel, items);
+ }
+ }
+ };
+
+ public PSIPParser(PSIPOutputListener listener) {
+ mSectionParser = new SectionParser(mSectionListener);
+ mStreamMap.put(ATSC_SI_BASE_PID, new Stream());
+ mListener = listener;
+ }
+
+ private boolean feedTSPacket(byte[] tsData, int pos) {
+ if (tsData.length < pos + TS_PACKET_SIZE) {
+ Log.d(TAG, "Data should include a single TS packet.");
+ return false;
+ }
+ if (tsData[pos + 0] != TS_PACKET_START_CODE) {
+ Log.d(TAG, "Invalid ts packet.");
+ return false;
+ }
+ if ((tsData[pos + 1] & 0x80) != 0) {
+ Log.d(TAG, "Erroneous ts packet.");
+ return false;
+ }
+ // For details for the structire of TS packet, please see H.222.0 Table 2-2.
+ int pid = ((tsData[pos + 1] & 0x1f) << 8) | (tsData[pos + 2] & 0xff);
+ boolean hasAdaptation = (tsData[pos + 3] & 0x20) != 0;
+ boolean hasPayload = (tsData[pos + 3] & 0x10) != 0;
+ boolean payloadStartIndicator = (tsData[pos + 1] & 0x40) != 0;
+ int continuityCounter = tsData[pos + 3] & 0x0f;
+ Stream stream = mStreamMap.get(pid);
+ int payloadPos = pos;
+ payloadPos += hasAdaptation ? 5 + (tsData[pos + 4] & 0xff) : 4;
+ if (!hasPayload || stream == null) {
+ // We are not interested in this packet.
+ return false;
+ }
+ stream.feedData(Arrays.copyOfRange(tsData, payloadPos, pos + TS_PACKET_SIZE),
+ continuityCounter, payloadStartIndicator);
+ return true;
+ }
+
+ public void feedTSData(byte[] tsData, int pos, int length) {
+ int origPos = pos;
+ if (mPartialTSPacketSize != 0
+ && (mPartialTSPacketSize + length) > TS_PACKET_SIZE) {
+ System.arraycopy(tsData, pos, mPartialTSPacketBuf, mPartialTSPacketSize,
+ TS_PACKET_SIZE - mPartialTSPacketSize);
+ feedTSPacket(mPartialTSPacketBuf, 0);
+ pos += TS_PACKET_SIZE - mPartialTSPacketSize;
+ mPartialTSPacketSize = 0;
+ }
+ for (;pos <= length - TS_PACKET_SIZE; pos += TS_PACKET_SIZE) {
+ feedTSPacket(tsData, pos);
+ }
+ int remaining = origPos + length - pos;
+ if (remaining > 0) {
+ System.arraycopy(tsData, pos, mPartialTSPacketBuf, mPartialTSPacketSize, remaining);
+ }
+ }
+
+ private void parseSection(byte[] data) {
+ mSectionParser.parseSection(data);
+ }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/SampleTsStream.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/SampleTsStream.java
new file mode 100644
index 0000000..875d69d
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/SampleTsStream.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 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.example.android.atsctvinput;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Pair;
+
+import com.example.android.atsctvinput.PSIPParser.PSIPOutputListener;
+import com.example.android.atsctvinput.SectionParser.EITItem;
+import com.example.android.atsctvinput.SectionParser.VCTItem;
+import com.example.atsctvinput.R;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public class SampleTsStream {
+ private static final String TAG = "SampleTsStream";
+ /*
+ * Sample MPEG2 transport streams which include ATSC PSIP data.
+ * In order to play the stream with Android mediaplayer, each stream has exactly one program
+ * and video and audio tracks are transcoded to MPEG4 and AAC respectively.
+ */
+ public static final TsStream[] SAMPLES = new TsStream[] {
+ new TsStream(R.raw.freq_1_prog_1, 1, 1),
+ new TsStream(R.raw.freq_2_prog_1029, 2, 1029),
+ };
+
+ private static final int READ_BUF_SIZE = 188;
+
+ public static String getTuneInfo(TsStream stream) {
+ return Long.toString(stream.mFrequency) + "," + Integer.toString(stream.mProgramNumber);
+ }
+
+ public static TsStream getTsStreamFromTuneInfo(String tuneInfo) {
+ String values[] = tuneInfo.split(",");
+ if (values.length != 2) {
+ return null;
+ }
+ long freq = Long.parseLong(values[0]);
+ int programNumber = Integer.parseInt(values[1]);
+ for (TsStream s : SAMPLES) {
+ if (s.mFrequency == freq && s.mProgramNumber == programNumber) {
+ return s;
+ }
+ }
+ return null;
+ }
+
+ public static Pair<VCTItem, List<EITItem>> extractChannelInfo(
+ Context context, final TsStream stream) {
+ final Object[] results = new Object[2];
+ PSIPParser mPSIPParser = new PSIPParser(new PSIPOutputListener() {
+ @Override
+ public void onEITPidDetected(int pid) {
+ // Do nothing;
+ }
+
+ @Override
+ public void onEITItemParsed(VCTItem channel, List<EITItem> items) {
+ if (channel.getProgramNumber() == stream.mProgramNumber) {
+ results[0] = channel;
+ results[1] = items;
+ }
+ }
+ });
+ InputStream in = context.getResources().openRawResource(stream.mResourceId);
+ byte[] buf = new byte[READ_BUF_SIZE];
+ try {
+ while (results[0] == null && results[1] == null
+ && in.read(buf, 0, READ_BUF_SIZE) == READ_BUF_SIZE) {
+ mPSIPParser.feedTSData(buf, 0, buf.length);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error while detecting channel from freq " + stream.mFrequency
+ + " program number " + stream.mProgramNumber);
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error while closing input stream for " + stream.mFrequency);
+ }
+ }
+ if (results[0] != null && results[1] != null) {
+ return new Pair<VCTItem, List<EITItem>>(
+ (VCTItem) results[0], (List<EITItem>) results[1]);
+ }
+ return null;
+ }
+
+ public static class TsStream {
+ public final int mResourceId;
+ public final long mFrequency;
+ public final int mProgramNumber;
+
+ public TsStream(int resourceId, long frequency, int programNumber) {
+ mResourceId = resourceId;
+ mFrequency = frequency;
+ mProgramNumber = programNumber;
+ }
+ }
+}
diff --git a/samples/AtscTvInput/src/com/example/android/atsctvinput/SectionParser.java b/samples/AtscTvInput/src/com/example/android/atsctvinput/SectionParser.java
new file mode 100644
index 0000000..0c5ec28
--- /dev/null
+++ b/samples/AtscTvInput/src/com/example/android/atsctvinput/SectionParser.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2014 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.example.android.atsctvinput;
+
+
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * PSIP section parser which conforms to ATSC A/65.
+ */
+public class SectionParser {
+ private static final String TAG = "SectionParser";
+
+ private static final boolean DEBUG = false;
+
+ private static final byte TABLE_ID_MGT = (byte) 0xc7;
+ private static final byte TABLE_ID_TVCT = (byte) 0xc8;
+ private static final byte TABLE_ID_CVCT = (byte) 0xc9;
+ private static final byte TABLE_ID_EIT = (byte) 0xcb;
+
+ private static final byte COMPRESSION_TYPE_NO_COMPRESSION = (byte) 0x00;
+ private static final byte MODE_SELECTED_UNICODE_RANGE_1 = (byte) 0x00; // 0x0000 - 0x00ff
+ private static final byte MODE_UTF16 = (byte) 0x3f;
+ private static final int MAX_SHORT_NAME_BYTES = 14;
+
+ /*
+ * The following CRC table is from the generated code by the following command.
+ * $ python pycrc.py --model crc-32-mpeg --algorithm table-driven --generate c
+ * To see the details of pycrc, please visit http://www.tty1.net/pycrc/index_en.html
+ */
+ private static final int [] CRC_TABLE = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+ 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+ 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+ 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+ 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+ 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+ 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+ 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+ 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+ 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+ 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+ 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+ 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+ 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+ 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+ 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+ 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+ 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+ 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+ 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+ 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+ 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+ 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+ 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+ 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+ 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+ 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+ 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+ 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+ 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+ 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+ };
+
+ public interface OutputListener {
+ void onMGTParsed(List<MGTItem> items);
+ void onVCTParsed(List<VCTItem> items);
+ void onEITParsed(int sourceId, List<EITItem> items);
+ }
+
+ public static class MGTItem {
+ public static final int TABLE_TYPE_EIT_0 = 0x0100;
+ private int mTableType;
+ private int mTableTypePid;
+
+ public MGTItem(int tableType, int tableTypePid) {
+ mTableType = tableType;
+ mTableTypePid = tableTypePid;
+ }
+
+ public int getTableType() {
+ return mTableType;
+ }
+
+ public int getTableTypePid() {
+ return mTableTypePid;
+ }
+ }
+
+ public static class VCTItem {
+ private String mShortName;
+ private int mProgramNumber;
+ private int mMajorChannelNumber;
+ private int mMinorChannelNumber;
+ private int mSourceId;
+
+ public VCTItem(String shortName, int programNumber, int majorChannelNumber,
+ int minorChannelNumber, int sourceId) {
+ mShortName = shortName;
+ mProgramNumber = programNumber;
+ mMajorChannelNumber = majorChannelNumber;
+ mMinorChannelNumber = minorChannelNumber;
+ mSourceId = sourceId;
+ }
+
+ public String getShortName() {
+ return mShortName;
+ }
+
+ public int getProgramNumber() {
+ return mProgramNumber;
+ }
+
+ public int getMajorChannelNumber() {
+ return mMajorChannelNumber;
+ }
+
+ public int getMinorChannelNumber() {
+ return mMinorChannelNumber;
+ }
+
+ public int getSourceId() {
+ return mSourceId;
+ }
+ }
+
+ public static class EITItem {
+ private String mTitleText;
+ private long mStartTime;
+ private int mLengthInSecond;
+
+ public EITItem(String titleText, long startTime, int lengthInSecond) {
+ mTitleText = titleText;
+ mStartTime = startTime;
+ mLengthInSecond = lengthInSecond;
+ }
+
+ public String getTitleText() {
+ return mTitleText;
+ }
+
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ public int getLengthInSecond() {
+ return mLengthInSecond;
+ }
+ }
+
+ private OutputListener mListener;
+
+ public SectionParser(OutputListener listener) {
+ mListener = listener;
+ }
+
+ public void parseSection(byte[] data) {
+ if (!checkSanity(data)) {
+ Log.d(TAG, "Bad CRC!");
+ return;
+ }
+ switch (data[0]) {
+ case TABLE_ID_MGT:
+ parseMGT(data);
+ break;
+ case TABLE_ID_TVCT:
+ case TABLE_ID_CVCT:
+ parseVCT(data);
+ break;
+ case TABLE_ID_EIT:
+ parseEIT(data);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void parseMGT(byte[] data) {
+ // For details of the structure for MGT, please see ATSC A/65 Table 6.2.
+ if (DEBUG) {
+ Log.d(TAG, "MGT is discovered.");
+ }
+ int tablesDefined = ((data[9] & 0xff) << 8) | (data[10] & 0xff);
+ int pos = 11;
+ List<MGTItem> results = new ArrayList<MGTItem>();
+ for (int i = 0; i < tablesDefined; ++i) {
+ int tableType = ((data[pos] & 0xff) << 8) | (data[pos + 1] & 0xff);
+ int tableTypePid = ((data[pos + 2] & 0x1f) << 8) | (data[pos + 3] & 0xff);
+ int descriptorsLength = ((data[pos + 9] & 0x0f) << 8) | (data[pos + 10] & 0xff);
+ pos += 11 + descriptorsLength;
+ if (pos >= data.length) {
+ Log.d(TAG, "Broken MGT.");
+ return;
+ }
+ results.add(new MGTItem(tableType, tableTypePid));
+ }
+ if ((data[pos] & 0xf0) != 0xf0) {
+ Log.d(TAG, "Broken MGT.");
+ return;
+ }
+ if (mListener != null) {
+ mListener.onMGTParsed(results);
+ }
+ }
+
+ private void parseVCT(byte[] data) {
+ // For details of the structure for VCT, please see ATSC A/65 Table 6.4 and 6.8.
+ if (DEBUG) {
+ Log.d(TAG, "VCT is discovered.");
+ }
+ int sectionNumber = (data[6] & 0xff);
+ int lastSectionNumber = (data[7] & 0xff);
+ int numChannelsInSection = (data[9] & 0xff);
+ int pos = 10;
+ List<VCTItem> results = new ArrayList<VCTItem>();
+ for (int i = 0; i < numChannelsInSection; ++i) {
+ String shortName = "";
+ int shortNameSize = getShortNameSize(data, pos);
+ try {
+ shortName = new String(
+ Arrays.copyOfRange(data, pos, pos + shortNameSize), "UTF-16");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ if ((data[pos + 14] & 0xf0) != 0xf0) {
+ Log.d(TAG, "Broken VCT.");
+ return;
+ }
+ int majorNumber = ((data[pos + 14] & 0x0f) << 6) | ((data[pos + 15] & 0xff) >> 2);
+ int minorNumber = ((data[pos + 15] & 0x03) << 8) | (data[pos + 16] & 0xff);
+ if ((majorNumber & 0x3f0) == 0x3f0) {
+ // If the six MSBs are 111111, these indicate that there is only one-part channel
+ // number. To see details, please refer A/65 Section 6.3.2.
+ majorNumber = ((majorNumber & 0xf) << 10) + minorNumber;
+ minorNumber = 0;
+ }
+ int programNumber = ((data[pos + 24] & 0xff) << 8) | (data[pos + 25] & 0xff);
+ int sourceId = ((data[pos + 28] & 0xff) << 8) | (data[pos + 29] & 0xff);
+ int descriptorsLength = ((data[pos + 30] & 0x03) << 8) | (data[pos + 31] & 0xff);
+ pos += 32 + descriptorsLength;
+ if (pos >= data.length) {
+ Log.d(TAG, "Broken VCT.");
+ return;
+ }
+ results.add(new VCTItem(shortName, programNumber, majorNumber, minorNumber, sourceId));
+ }
+ if ((data[pos] & 0xfc) != 0xfc) {
+ Log.d(TAG, "Broken VCT.");
+ return;
+ }
+ if (mListener != null) {
+ mListener.onVCTParsed(results);
+ }
+ }
+
+ private void parseEIT(byte[] data) {
+ // For details of the structure for EIT, please see ATSC A/65 Table 6.11.
+ if (DEBUG) {
+ Log.d(TAG, "EIT is discovered.");
+ }
+ int sourceId = ((data[3] & 0xff) << 8) | (data[4] & 0xff);
+ int sectionNumber = (data[6] & 0xff);
+ int lastSectionNumber = (data[7] & 0xff);
+ int numEventsInSection = (data[9] & 0xff);
+
+ int pos = 10;
+ List<EITItem> results = new ArrayList<EITItem>();
+ for (int i = 0; i < numEventsInSection; ++i) {
+ if ((data[pos] & 0xc0) != 0xc0) {
+ Log.d(TAG, "Broken EIT.");
+ return;
+ }
+ long startTime = ((data[pos + 2] & (long) 0xff) << 24) | ((data[pos + 3] & 0xff) << 16)
+ | ((data[pos + 4] & 0xff) << 8) | (data[pos + 5] & 0xff);
+ int lengthInSecond = ((data[pos + 6] & 0x0f) << 16)
+ | ((data[pos + 7] & 0xff) << 8) | (data[pos + 8] & 0xff);
+ int titleLength = (data[pos + 9] & 0xff);
+ String titleText = "";
+ if (titleLength > 0) {
+ titleText = extractText(data, pos + 10);
+ }
+ if ((data[pos + 10 + titleLength] & 0xf0) != 0xf0) {
+ Log.d(TAG, "Broken EIT.");
+ return;
+ }
+ int descriptorsLength = ((data[pos + 10 + titleLength] & 0x0f) << 8)
+ | (data[pos + 10 + titleLength + 1] & 0xff);
+ pos += 10 + titleLength + 2 + descriptorsLength;
+ if (pos >= data.length) {
+ Log.d(TAG, "Broken EIT.");
+ return;
+ }
+ results.add(new EITItem(titleText, startTime, lengthInSecond));
+ }
+ if (mListener != null) {
+ mListener.onEITParsed(sourceId, results);
+ }
+ }
+
+ private int getShortNameSize(byte[] data, int offset) {
+ for (int i = 0; i < MAX_SHORT_NAME_BYTES; i += 2) {
+ if(data[offset + i] == 0 && data[offset + i + 1] == 0) {
+ return i;
+ }
+ }
+ return MAX_SHORT_NAME_BYTES;
+ }
+
+ private String extractText(byte[] data, int startOffset) {
+ int pos = startOffset;
+ int numStrings = data[pos] & 0xff;
+ pos++;
+ for (int i = 0; i < numStrings; ++i) {
+ int numSegments = data[pos + 3] & 0xff;
+ pos += 4;
+ for (int j = 0; j < numSegments; ++j) {
+ int compressionType = data[pos] & 0xff;
+ int mode = data[pos + 1] & 0xff;
+ int numBytes = data[pos + 2] & 0xff;
+ if (compressionType == COMPRESSION_TYPE_NO_COMPRESSION) {
+ try {
+ if (mode == MODE_UTF16) {
+ return new String(Arrays.copyOfRange(
+ data, pos + 3, pos + 3 + numBytes), "UTF-16");
+ } else if (mode == MODE_SELECTED_UNICODE_RANGE_1){
+ return new String(Arrays.copyOfRange(
+ data, pos + 3, pos + 3 + numBytes), "UTF-8");
+ }
+ } catch (UnsupportedEncodingException e) {
+ System.out.println("Unsupported text format.");
+ }
+ }
+ pos += 3 + numBytes;
+ }
+ }
+ return null;
+ }
+
+ private boolean checkSanity(byte[] data) {
+ boolean hasCRC = (data[1] & 0x80) != 0; // section_syntax_indicator
+ if (hasCRC) {
+ int crc = 0xffffffff;
+ for(byte b : data) {
+ int index = ((crc >> 24) ^ (b & 0xff)) & 0xff;
+ crc = CRC_TABLE[index] ^ (crc << 8);
+ }
+ if(crc != 0){
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/samples/SampleSyncAdapter/AndroidManifest.xml b/samples/SampleSyncAdapter/AndroidManifest.xml
index 48f6fad..7402f9d 100644
--- a/samples/SampleSyncAdapter/AndroidManifest.xml
+++ b/samples/SampleSyncAdapter/AndroidManifest.xml
@@ -104,7 +104,7 @@
</activity>
<activity
- android:name=".activites.InviteContactActivity"
+ android:name=".activities.InviteContactActivity"
android:theme="@android:style/Theme.Dialog">
<!--
We use the INVITE intent to add a raw contact to an existing contact.
@@ -133,34 +133,5 @@
</intent-filter>
</activity>
- <activity
- android:name=".activities.ViewStreamItemActivity"
- android:theme="@android:style/Theme.Dialog">
- <!--
- We use the VIEW intent to view a stream item in our app.
- It always comes with a lookup URI.
- -->
- <intent-filter>
- <action
- android:name="android.intent.action.VIEW" />
- <data
- android:mimeType="vnd.android.cursor.item/stream_item" />
- </intent-filter>
- </activity>
-
- <activity
- android:name=".activities.ViewStreamItemPhotoActivity"
- android:theme="@android:style/Theme.Dialog">
- <!--
- We use the VIEW intent to view a stream item photo in our app.
- It always comes with a lookup URI.
- -->
- <intent-filter>
- <action
- android:name="android.intent.action.VIEW" />
- <data
- android:mimeType="vnd.android.cursor.item/stream_item_photo" />
- </intent-filter>
- </activity>
</application>
</manifest>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
deleted file mode 100644
index a04d07f..0000000
--- a/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-/**
- * Copyright (c) 2011, 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:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:text="@string/view_stream_item_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- android:id="@+id/view_stream_item_uri"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
deleted file mode 100644
index ddc09d0..0000000
--- a/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-/**
- * Copyright (c) 2011, 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:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:text="@string/view_stream_item_photo_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- android:id="@+id/view_stream_item_photo_uri"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/values/strings.xml b/samples/SampleSyncAdapter/res/values/strings.xml
index 22fe14e..84c94d1 100644
--- a/samples/SampleSyncAdapter/res/values/strings.xml
+++ b/samples/SampleSyncAdapter/res/values/strings.xml
@@ -129,14 +129,4 @@
This is the group uri:</string>
- <!-- The description for the view stream item -->
- <string name="view_stream_item_description">This would now show the details of the stream item.
-
- This is the uri of the stream item:</string>
-
- <!-- The description for the view stream item photo -->
- <string name="view_stream_item_photo_description">This would now show the details of the stream item photo.
-
- This is the uri of the photo:</string>
-
</resources>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
index 48e079a..b4ad2a0 100644
--- a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
@@ -24,8 +24,6 @@
viewContactNotifyService="com.example.android.samplesync.notifier.NotifierService"
viewGroupActivity="com.example.android.samplesync.activities.ViewGroupActivity"
viewGroupActionLabel="@string/view_group_action_label"
- viewStreamItemActivity="com.example.android.samplesync.activities.ViewStreamItemActivity"
- viewStreamItemPhotoActivity="com.example.android.samplesync.activities.ViewStreamItemPhotoActivity"
>
<ContactsDataKind
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
deleted file mode 100644
index 6d54f31..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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.example.android.samplesync.activities;
-
-import com.example.android.samplesync.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-/**
- * Activity to handle view a stream-item. In a real app, this would show a rich view of the
- * item.
- */
-public class ViewStreamItemActivity extends Activity {
- private static final String TAG = "ViewStreamItemActivity";
-
- private TextView mUriTextView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.view_stream_item_activity);
-
- mUriTextView = (TextView) findViewById(R.id.view_stream_item_uri);
- mUriTextView.setText(getIntent().getDataString());
- }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
deleted file mode 100644
index 962bc70..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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.example.android.samplesync.activities;
-
-import com.example.android.samplesync.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-/**
- * Activity to view a stream-item-photo. In a real app, this would show a fullscreen view of the
- * photo, potentially with ways to interact with it
- */
-public class ViewStreamItemPhotoActivity extends Activity {
- private static final String TAG = "ViewStreamItemPhotoActivity";
-
- private TextView mUriTextView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.view_stream_item_photo_activity);
-
- mUriTextView = (TextView) findViewById(R.id.view_stream_item_photo_uri);
- mUriTextView.setText(getIntent().getDataString());
- }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
index 5b09eb1..22f4f26 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
@@ -24,10 +24,7 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -41,14 +38,8 @@
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.Settings;
import android.provider.ContactsContract.StatusUpdates;
-import android.provider.ContactsContract.StreamItemPhotos;
-import android.provider.ContactsContract.StreamItems;
import android.util.Log;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -244,43 +235,6 @@
}
/**
- * Demonstrate how to add stream items and stream item photos to a raw
- * contact. This just adds items for all of the contacts for this sync
- * adapter with some locally created text and an image. You should check
- * for stream items on the server that you are syncing with and use the
- * text and photo data from there instead.
- *
- * @param context The context of Authenticator Activity
- * @param rawContacts The list of users we want to update
- */
- public static void addStreamItems(Context context, List<RawContact> rawContacts,
- String accountName, String accountType) {
- final ContentResolver resolver = context.getContentResolver();
- final BatchOperation batchOperation = new BatchOperation(context, resolver);
- String text = "This is a test stream item!";
- String message = "via SampleSyncAdapter";
- for (RawContact rawContact : rawContacts) {
- addContactStreamItem(context, lookupRawContact(resolver,
- rawContact.getServerContactId()), accountName, accountType,
- text, message, batchOperation );
- }
- List<Uri> streamItemUris = batchOperation.execute();
-
- // Stream item photos are added after the stream items that they are
- // associated with, using the stream item's ID as a reference.
-
- for (Uri uri : streamItemUris){
- // All you need is the ID of the stream item, which is the last index
- // path segment returned by getPathSegments().
- long streamItemId = Long.parseLong(uri.getPathSegments().get(
- uri.getPathSegments().size()-1));
- addStreamItemPhoto(context, resolver, streamItemId, accountName,
- accountType, batchOperation);
- }
- batchOperation.execute();
- }
-
- /**
* After we've finished up a sync operation, we want to clean up the sync-state
* so that we're ready for the next time. This involves clearing out the 'dirty'
* flag on the synced contacts - but we also have to finish the DELETE operation
@@ -596,59 +550,6 @@
}
/**
- * Adds a stream item to a raw contact. The stream item is usually obtained
- * from the server you are syncing with, but we create it here locally as an
- * example.
- *
- * @param context the Authenticator Activity context
- * @param rawContactId the raw contact ID that the stream item is associated with
- * @param accountName the account name of the sync adapter
- * @param accountType the account type of the sync adapter
- * @param text the text of the stream item
- * @param comments the comments for the stream item, such as where the stream item came from
- * @param batchOperation allow us to batch together multiple operations
- */
- private static void addContactStreamItem(Context context, long rawContactId,
- String accountName, String accountType, String text, String comments,
- BatchOperation batchOperation) {
-
- final ContentValues values = new ContentValues();
- final ContentResolver resolver = context.getContentResolver();
- if (rawContactId > 0){
- values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
- values.put(StreamItems.TEXT, text);
- values.put(StreamItems.TIMESTAMP, System.currentTimeMillis());
- values.put(StreamItems.COMMENTS, comments);
- values.put(StreamItems.ACCOUNT_NAME, accountName);
- values.put(StreamItems.ACCOUNT_TYPE, accountType);
-
- batchOperation.add(ContactOperations.newInsertCpo(
- StreamItems.CONTENT_URI, false, true).withValues(values).build());
- }
- }
-
- private static void addStreamItemPhoto(Context context, ContentResolver
- resolver, long streamItemId, String accountName, String accountType,
- BatchOperation batchOperation){
-
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
- R.raw.img1);
- bitmap.compress(Bitmap.CompressFormat.JPEG, 30, stream);
- byte[] photoData = stream.toByteArray();
-
- final ContentValues values = new ContentValues();
- values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
- values.put(StreamItemPhotos.SORT_INDEX, 1);
- values.put(StreamItemPhotos.PHOTO, photoData);
- values.put(StreamItems.ACCOUNT_NAME, accountName);
- values.put(StreamItems.ACCOUNT_TYPE, accountType);
-
- batchOperation.add(ContactOperations.newInsertCpo(
- StreamItems.CONTENT_PHOTO_URI, false, true).withValues(values).build());
- }
-
- /**
* Clear the local system 'dirty' flag for a contact.
*
* @param context the Authenticator Activity context
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
index 8aa0784..7144524 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
@@ -119,18 +119,6 @@
ContactManager.updateStatusMessages(mContext, updatedContacts);
- // This is a demo of how you can add stream items for contacts on
- // the client. This probably won't apply to
- // 2-way contact sync providers - it's more likely that one-way
- // sync providers (IM clients, social networking apps, etc) would
- // use this feature. This is only supported in ICS MR1 or above.
-
- if (Build.VERSION.SDK_INT >=
- Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- ContactManager.addStreamItems(mContext, updatedContacts,
- account.name, account.type);
- }
-
// Save off the new sync marker. On our next sync, we only want to receive
// contacts that have changed since this sync...
setServerSyncMarker(account, newSyncState);
diff --git a/samples/SupportLeanbackDemos/AndroidManifest.xml b/samples/SupportLeanbackDemos/AndroidManifest.xml
index ee0707d..8cf8236 100644
--- a/samples/SupportLeanbackDemos/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/AndroidManifest.xml
@@ -9,6 +9,7 @@
<application
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
+ android:banner="@drawable/ic_launcher"
android:theme="@style/Theme.Leanback">
<activity android:name="MainActivity"
diff --git a/samples/SupportLeanbackDemos/res/drawable/text_bg.xml b/samples/SupportLeanbackDemos/res/drawable/text_bg.xml
index c67924c..2f5a213 100644
--- a/samples/SupportLeanbackDemos/res/drawable/text_bg.xml
+++ b/samples/SupportLeanbackDemos/res/drawable/text_bg.xml
@@ -26,4 +26,7 @@
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
+ <size
+ android:height="160dp"
+ android:width="100dp" />
</shape>
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index 2345ed0..ce019b3 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -27,7 +27,7 @@
public class BrowseFragment extends android.support.v17.leanback.app.BrowseFragment {
private static final String TAG = "leanback.BrowseFragment";
- private static final int NUM_ROWS = 3;
+ private static final int NUM_ROWS = 10;
private ArrayObjectAdapter mRowsAdapter;
@Override
@@ -54,7 +54,14 @@
}
private void setupRows() {
- mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
+ ListRowPresenter lrp = new ListRowPresenter();
+ float density = getActivity().getResources().getDisplayMetrics().density;
+ float height = 160 * density + 0.5f;
+ float expandedHeight = height + 52 * density + 0.5f;
+ lrp.setRowHeight((int)height);
+ lrp.setExpandedRowHeight((int)expandedHeight);
+
+ mRowsAdapter = new ArrayObjectAdapter(lrp);
for (int i = 0; i < NUM_ROWS; ++i) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
diff --git a/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
index a511221..a483374 100644
--- a/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
+++ b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -21,6 +21,7 @@
import android.os.Looper;
import android.view.Surface;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue;
@@ -136,7 +137,7 @@
* @return
*/
public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
- Surface surface) {
+ Surface surface) throws IOException {
MediaCodecWrapper result = null;
MediaCodec videoCodec = null;
diff --git a/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java b/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java
index 80aa9fd..534f218 100644
--- a/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java
+++ b/samples/training/NsdChat/src/com/example/android/nsdchat/ChatConnection.java
@@ -52,7 +52,9 @@
public void tearDown() {
mChatServer.tearDown();
- mChatClient.tearDown();
+ if (mChatClient != null) {
+ mChatClient.tearDown();
+ }
}
public void connectToServer(InetAddress address, int port) {
@@ -64,15 +66,15 @@
mChatClient.sendMessage(msg);
}
}
-
+
public int getLocalPort() {
return mPort;
}
-
+
public void setLocalPort(int port) {
mPort = port;
}
-
+
public synchronized void updateMessages(String msg, boolean local) {
Log.e(TAG, "Updating message: " + msg);
@@ -142,7 +144,7 @@
// used. Just grab an available one and advertise it via Nsd.
mServerSocket = new ServerSocket(0);
setLocalPort(mServerSocket.getLocalPort());
-
+
while (!Thread.currentThread().isInterrupted()) {
Log.d(TAG, "ServerSocket Created, awaiting connection");
setSocket(mServerSocket.accept());
diff --git a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java
index 47ee098..5782634 100644
--- a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java
+++ b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdChatActivity.java
@@ -43,6 +43,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Log.d(TAG, "Creating chat activity");
setContentView(R.layout.main);
mStatusView = (TextView) findViewById(R.id.status);
@@ -54,11 +55,6 @@
}
};
- mConnection = new ChatConnection(mUpdateHandler);
-
- mNsdHelper = new NsdHelper(this);
- mNsdHelper.initializeNsd();
-
}
public void clickAdvertise(View v) {
@@ -101,25 +97,58 @@
}
@Override
+ protected void onStart() {
+ Log.d(TAG, "Starting.");
+ mConnection = new ChatConnection(mUpdateHandler);
+
+ mNsdHelper = new NsdHelper(this);
+ mNsdHelper.initializeNsd();
+ super.onStart();
+ }
+
+
+ @Override
protected void onPause() {
+ Log.d(TAG, "Pausing.");
if (mNsdHelper != null) {
mNsdHelper.stopDiscovery();
}
super.onPause();
}
-
+
@Override
protected void onResume() {
+ Log.d(TAG, "Resuming.");
super.onResume();
if (mNsdHelper != null) {
mNsdHelper.discoverServices();
}
}
-
+
+
+ // For KitKat and earlier releases, it is necessary to remove the
+ // service registration when the application is stopped. There's
+ // no guarantee that the onDestroy() method will be called (we're
+ // killable after onStop() returns) and the NSD service won't remove
+ // the registration for us if we're killed.
+
+ // In L and later, NsdService will automatically unregister us when
+ // our connection goes away when we're killed, so this step is
+ // optional (but recommended).
+
@Override
- protected void onDestroy() {
+ protected void onStop() {
+ Log.d(TAG, "Being stopped.");
mNsdHelper.tearDown();
mConnection.tearDown();
+ mNsdHelper = null;
+ mConnection = null;
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.d(TAG, "Being destroyed.");
super.onDestroy();
}
}
diff --git a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
index 568a79b..5111318 100644
--- a/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
+++ b/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
@@ -44,8 +44,6 @@
public void initializeNsd() {
initializeResolveListener();
- initializeDiscoveryListener();
- initializeRegistrationListener();
//mNsdManager.init(mContext.getMainLooper(), this);
@@ -78,22 +76,20 @@
mService = null;
}
}
-
+
@Override
public void onDiscoveryStopped(String serviceType) {
- Log.i(TAG, "Discovery stopped: " + serviceType);
+ Log.i(TAG, "Discovery stopped: " + serviceType);
}
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
- mNsdManager.stopServiceDiscovery(this);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
- mNsdManager.stopServiceDiscovery(this);
}
};
}
@@ -125,48 +121,68 @@
@Override
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
mServiceName = NsdServiceInfo.getServiceName();
+ Log.d(TAG, "Service registered: " + mServiceName);
}
-
+
@Override
public void onRegistrationFailed(NsdServiceInfo arg0, int arg1) {
+ Log.d(TAG, "Service registration failed: " + arg1);
}
@Override
public void onServiceUnregistered(NsdServiceInfo arg0) {
+ Log.d(TAG, "Service unregistered: " + arg0.getServiceName());
}
-
+
@Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ Log.d(TAG, "Service unregistration failed: " + errorCode);
}
-
+
};
}
public void registerService(int port) {
+ tearDown(); // Cancel any previous registration request
+ initializeRegistrationListener();
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setPort(port);
serviceInfo.setServiceName(mServiceName);
serviceInfo.setServiceType(SERVICE_TYPE);
-
+
mNsdManager.registerService(
serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
-
+
}
public void discoverServices() {
+ stopDiscovery(); // Cancel any existing discovery request
+ initializeDiscoveryListener();
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
-
+
public void stopDiscovery() {
- mNsdManager.stopServiceDiscovery(mDiscoveryListener);
+ if (mDiscoveryListener != null) {
+ try {
+ mNsdManager.stopServiceDiscovery(mDiscoveryListener);
+ } finally {
+ }
+ mDiscoveryListener = null;
+ }
}
public NsdServiceInfo getChosenServiceInfo() {
return mService;
}
-
+
public void tearDown() {
- mNsdManager.unregisterService(mRegistrationListener);
+ if (mRegistrationListener != null) {
+ try {
+ mNsdManager.unregisterService(mRegistrationListener);
+ } finally {
+ }
+ mRegistrationListener = null;
+ }
}
}
diff --git a/scripts/symbol.py b/scripts/symbol.py
index 3789fa2..8c1fa68 100755
--- a/scripts/symbol.py
+++ b/scripts/symbol.py
@@ -93,6 +93,11 @@
known_toolchains = [
("i686-android-linux-4.4.3", "x86", "i686-android-linux")
]
+ elif ARCH == "mips":
+ gcc_version = os.environ["TARGET_GCC_VERSION"]
+ known_toolchains = [
+ ("mipsel-linux-android-" + gcc_version, "mips", "mipsel-linux-android")
+ ]
else:
known_toolchains = []
diff --git a/sdk/build_tools_source.prop_template b/sdk/build_tools_source.prop_template
index c9bfc2f..5d62307 100644
--- a/sdk/build_tools_source.prop_template
+++ b/sdk/build_tools_source.prop_template
@@ -1,3 +1,3 @@
Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.0.2
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
diff --git a/sdk/doc_source.prop_template b/sdk/doc_source.prop_template
index 523d6bd..d3cdfd5 100644
--- a/sdk/doc_source.prop_template
+++ b/sdk/doc_source.prop_template
@@ -1,4 +1,4 @@
Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/images_armeabi-v7a_source.prop_template b/sdk/images_armeabi-v7a_source.prop_template
index 7d13fce..9c7a332 100644
--- a/sdk/images_armeabi-v7a_source.prop_template
+++ b/sdk/images_armeabi-v7a_source.prop_template
@@ -1,6 +1,6 @@
Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
SystemImage.Abi=armeabi-v7a
diff --git a/sdk/images_armeabi_source.prop_template b/sdk/images_armeabi_source.prop_template
index ef17ea6..91e9d21 100644
--- a/sdk/images_armeabi_source.prop_template
+++ b/sdk/images_armeabi_source.prop_template
@@ -1,6 +1,6 @@
Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
SystemImage.Abi=armeabi
diff --git a/sdk/images_x86_source.prop_template b/sdk/images_x86_source.prop_template
index 84be49d..cfbe180 100644
--- a/sdk/images_x86_source.prop_template
+++ b/sdk/images_x86_source.prop_template
@@ -1,6 +1,6 @@
Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
SystemImage.Abi=x86
diff --git a/sdk/plat_tools_source.prop_template b/sdk/plat_tools_source.prop_template
index b83af7f..5d62307 100644
--- a/sdk/plat_tools_source.prop_template
+++ b/sdk/plat_tools_source.prop_template
@@ -1,3 +1,3 @@
Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.0.1
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
diff --git a/sdk/source_source.prop_template b/sdk/source_source.prop_template
index 523d6bd..d3cdfd5 100644
--- a/sdk/source_source.prop_template
+++ b/sdk/source_source.prop_template
@@ -1,4 +1,4 @@
Pkg.UserSrc=false
-Pkg.Revision=2
+Pkg.Revision=1
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/support_source.prop_template b/sdk/support_source.prop_template
index 20022d2..ba7e6fb 100644
--- a/sdk/support_source.prop_template
+++ b/sdk/support_source.prop_template
@@ -1,5 +1,5 @@
Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.2.0
+Pkg.Revision=${PLATFORM_SDK_VERSION}
Extra.Vendor=android
Extra.VendorId=android
Extra.VendorDisplay=Android
diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py
index fa394cd..dc43a93 100755
--- a/testrunner/adb_interface.py
+++ b/testrunner/adb_interface.py
@@ -506,3 +506,34 @@
def GetSerialNumber(self):
"""Returns the serial number of the targeted device."""
return self.SendCommand("get-serialno").strip()
+
+ def RuntimeReset(self, disable_keyguard=False, retry_count=3, preview_only=False):
+ """
+ Resets the Android runtime (does *not* reboot the kernel).
+
+ Blocks until the reset is complete and the package manager
+ is available.
+
+ Args:
+ disable_keyguard: if True, presses the MENU key to disable
+ key guard, after reset is finished
+ retry_count: number of times to retry reset before failing
+
+ Raises:
+ WaitForResponseTimedOutError if package manager does not respond
+ AbortError if unrecoverable error occurred
+ """
+
+ logger.Log("adb shell stop")
+ logger.Log("adb shell start")
+
+ if not preview_only:
+ self.SendShellCommand("stop", retry_count=retry_count)
+ self.SendShellCommand("start", retry_count=retry_count)
+
+ self.WaitForDevicePm()
+
+ if disable_keyguard:
+ logger.Log("input keyevent 82 ## disable keyguard")
+ if not preview_only:
+ self.SendShellCommand("input keyevent 82", retry_count=retry_count)
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index a76d9c0..d367904 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -73,11 +73,12 @@
# default value for make -jX
_DEFAULT_JOBS = 16
- _DALVIK_VERIFIER_OFF_PROP = "dalvik.vm.dexopt-flags = v=n"
+ _DALVIK_VERIFIER_PROP = "dalvik.vm.dexopt-flags"
+ _DALVIK_VERIFIER_OFF_VALUE = "v=n"
+ _DALVIK_VERIFIER_OFF_PROP = "%s = %s" %(_DALVIK_VERIFIER_PROP, _DALVIK_VERIFIER_OFF_VALUE)
# regular expression to match path to artifacts to install in make output
- _RE_MAKE_INSTALL = re.compile(r'INSTALL-PATH:\s(.+)\s(.+)')
-
+ _RE_MAKE_INSTALL = re.compile(r'INSTALL-PATH:\s([^\s]+)\s(.*)$')
def __init__(self):
# disable logging of timestamp
@@ -113,6 +114,9 @@
parser.add_option("-n", "--skip_execute", dest="preview", default=False,
action="store_true",
help="Do not execute, just preview commands")
+ parser.add_option("-i", "--build-install-only", dest="build_install_only", default=False,
+ action="store_true",
+ help="Do not execute, build tests and install to device only")
parser.add_option("-r", "--raw-mode", dest="raw_mode", default=False,
action="store_true",
help="Raw mode (for output to other tools)")
@@ -193,7 +197,6 @@
self._adb.SetDeviceTarget()
elif self._options.serial is not None:
self._adb.SetTargetSerial(self._options.serial)
-
if self._options.verbose:
logger.SetVerbose(True)
@@ -247,7 +250,9 @@
tests = self._GetTestsToRun()
# turn off dalvik verifier if necessary
- self._TurnOffVerifier(tests)
+ # TODO: skip turning off verifier for now, since it puts device in bad
+ # state b/14088982
+ #self._TurnOffVerifier(tests)
self._DoFullBuild(tests)
target_tree = make_tree.MakeTree()
@@ -267,7 +272,9 @@
target_tree.AddPath("external/emma")
target_list = target_tree.GetPrunedMakeList()
+ target_dir_list = [re.sub(r'Android[.]mk$', r'', i) for i in target_list]
target_build_string = " ".join(target_list)
+ target_dir_build_string = " ".join(target_dir_list)
extra_args_string = " ".join(extra_args_set)
# mmm cannot be used from python, so perform a similar operation using
@@ -275,9 +282,24 @@
cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" GET-INSTALL-PATH all_modules %s' % (
target_build_string, self._options.make_jobs, self._root_path,
extra_args_string)
+ # mmma equivalent, used when regular mmm fails
+ alt_cmd = 'make -j%s -C "%s" -f build/core/main.mk %s all_modules BUILD_MODULES_IN_PATHS="%s"' % (
+ self._options.make_jobs, self._root_path, extra_args_string, target_dir_build_string)
+
logger.Log(cmd)
if not self._options.preview:
- output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+ run_command.SetAbortOnError()
+ try:
+ output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+ ## Chances are this failed because it didn't build the dependencies
+ except errors.AbortError:
+ logger.Log("make failed. Trying to rebuild all dependencies.")
+ logger.Log("mmma -j%s %s" %(self._options.make_jobs, target_dir_build_string))
+ # Try again with mma equivalent, which will build the dependencies
+ run_command.RunCommand(alt_cmd, return_output=False, timeout_time=600)
+ # Run mmm again to get the install paths only
+ output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+ run_command.SetAbortOnError(False)
logger.SilentLog(output)
self._DoInstall(output)
@@ -286,19 +308,25 @@
Looks for 'install:' text from make output to find artifacts to install.
+ Files with the .apk extension get 'adb install'ed, all other files
+ get 'adb push'ed onto the device.
+
Args:
make_output: stdout from make command
"""
for line in make_output.split("\n"):
m = self._RE_MAKE_INSTALL.match(line)
if m:
- install_path = m.group(2)
- if install_path.endswith(".apk"):
- abs_install_path = os.path.join(self._root_path, install_path)
- logger.Log("adb install -r %s" % abs_install_path)
- logger.Log(self._adb.Install(abs_install_path))
- else:
- self._PushInstallFileToDevice(install_path)
+ # strip the 'INSTALL: <name>' from the left hand side
+ # the remaining string is a space-separated list of build-generated files
+ install_paths = m.group(2)
+ for install_path in re.split(r'\s+', install_paths):
+ if install_path.endswith(".apk"):
+ abs_install_path = os.path.join(self._root_path, install_path)
+ logger.Log("adb install -r %s" % abs_install_path)
+ logger.Log(self._adb.Install(abs_install_path))
+ else:
+ self._PushInstallFileToDevice(install_path)
def _PushInstallFileToDevice(self, install_path):
m = self._re_make_install_path.match(install_path)
@@ -406,7 +434,7 @@
turns off verifier and reboots device to allow change to take effect.
"""
# hack to check if these are frameworks/base tests. If so, turn off verifier
- # to allow framework tests to access package-private framework api
+ # to allow framework tests to access private/protected/package-private framework api
framework_test = False
for test in test_list:
if os.path.commonprefix([test.GetBuildPath(), "frameworks/base"]):
@@ -416,35 +444,54 @@
# necessary
output = self._adb.SendShellCommand("cat /data/local.prop")
if not self._DALVIK_VERIFIER_OFF_PROP in output:
+
+ # Read the existing dalvik verifier flags.
+ old_prop_value = self._adb.SendShellCommand("getprop %s" \
+ %(self._DALVIK_VERIFIER_PROP))
+ old_prop_value = old_prop_value.strip() if old_prop_value else ""
+
+ # Append our verifier flags to existing flags
+ new_prop_value = "%s %s" %(self._DALVIK_VERIFIER_OFF_VALUE, old_prop_value)
+
+ # Update property now, as /data/local.prop is not read until reboot
+ logger.Log("adb shell setprop %s '%s'" \
+ %(self._DALVIK_VERIFIER_PROP, new_prop_value))
+ if not self._options.preview:
+ self._adb.SendShellCommand("setprop %s '%s'" \
+ %(self._DALVIK_VERIFIER_PROP, new_prop_value))
+
+ # Write prop to /data/local.prop
+ # Every time device is booted, it will pick up this value
+ new_prop_assignment = "%s = %s" %(self._DALVIK_VERIFIER_PROP, new_prop_value)
if self._options.preview:
logger.Log("adb shell \"echo %s >> /data/local.prop\""
- % self._DALVIK_VERIFIER_OFF_PROP)
+ % new_prop_assignment)
logger.Log("adb shell chmod 644 /data/local.prop")
- logger.Log("adb reboot")
- logger.Log("adb wait-for-device")
else:
logger.Log("Turning off dalvik verifier and rebooting")
self._adb.SendShellCommand("\"echo %s >> /data/local.prop\""
- % self._DALVIK_VERIFIER_OFF_PROP)
+ % new_prop_assignment)
- self._ChmodReboot()
+ # Reset runtime so that dalvik picks up new verifier flags from prop
+ self._ChmodRuntimeReset()
elif not self._options.preview:
# check the permissions on the file
permout = self._adb.SendShellCommand("ls -l /data/local.prop")
if not "-rw-r--r--" in permout:
logger.Log("Fixing permissions on /data/local.prop and rebooting")
- self._ChmodReboot()
+ self._ChmodRuntimeReset()
- def _ChmodReboot(self):
- """Perform a chmod of /data/local.prop and reboot.
+ def _ChmodRuntimeReset(self):
+ """Perform a chmod of /data/local.prop and reset the runtime.
"""
- self._adb.SendShellCommand("chmod 644 /data/local.prop")
- self._adb.SendCommand("reboot")
- # wait for device to go offline
- time.sleep(10)
- self._adb.SendCommand("wait-for-device", timeout_time=60,
- retry_count=3)
- self._adb.EnableAdbRoot()
+ logger.Log("adb shell chmod 644 /data/local.prop ## u+w,a+r")
+ if not self._options.preview:
+ self._adb.SendShellCommand("chmod 644 /data/local.prop")
+
+ self._adb.RuntimeReset(preview_only=self._options.preview)
+
+ if not self._options.preview:
+ self._adb.EnableAdbRoot()
def RunTests(self):
@@ -459,6 +506,10 @@
if not self._options.skip_build:
self._DoBuild()
+ if self._options.build_install_only:
+ logger.Log("Skipping test execution (due to --build-install-only flag)")
+ return
+
for test_suite in self._GetTestsToRun():
try:
test_suite.Run(self._options, self._adb)
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index 751a142..c231323 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -512,11 +512,17 @@
<!-- Unit tests for the phone application. -->
<test name="phone-unit"
- build_path="packages/apps/Phone"
+ build_path="packages/services/Telephony"
package="com.android.phone.tests"
continuous="true"
coverage_target="Phone" />
+<test name="telecomm-unit"
+ build_path="packages/services/Telecomm"
+ package="com.android.telecomm.tests"
+ continuous="true"
+ coverage_target="Phone" />
+
<test name="quicksearchbox"
build_path="packages/apps/QuickSearchBox"
package="com.android.quicksearchbox.tests"
diff --git a/testrunner/test_defs/gtest.py b/testrunner/test_defs/gtest.py
index dc72f94..cceead9 100644
--- a/testrunner/test_defs/gtest.py
+++ b/testrunner/test_defs/gtest.py
@@ -73,6 +73,7 @@
- test_*.[c|cc|cpp]
- *_test.[c|cc|cpp]
- *_unittest.[c|cc|cpp]
+ - *Tests.[cc|cpp]
"""
if not sub_tests_path:
@@ -101,6 +102,7 @@
- test_*.[cc|cpp]
- *_test.[cc|cpp]
- *_unittest.[cc|cpp]
+ - *Tests.[cc|cpp]
This method is a callback for os.path.walk.
@@ -115,6 +117,6 @@
def _EvaluateFile(self, test_list, file):
(name, ext) = os.path.splitext(file)
if ext == ".cc" or ext == ".cpp" or ext == ".c":
- if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name):
+ if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_|Tests$", name):
logger.SilentLog("Found native test file %s" % file)
test_list.append(name)
diff --git a/tools/emulator/test-apps/GpsLocationTest/Android.mk b/tools/emulator/test-apps/GpsLocationTest/Android.mk
deleted file mode 100644
index 5f90f3a..0000000
--- a/tools/emulator/test-apps/GpsLocationTest/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2011 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_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := GpsLocationTest
-
-LOCAL_SDK_VERSION := 4
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml b/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
deleted file mode 100644
index 901855e..0000000
--- a/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.emulator.gps.test"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-sdk android:minSdkVersion="4" />
- <instrumentation android:targetPackage="com.android.emulator.gps.test"
- android:name="android.test.InstrumentationTestRunner" />
- <application android:label="GPS Location Test">
- <uses-library android:name="android.test.runner" />
- </application>
-</manifest>
\ No newline at end of file
diff --git a/tools/emulator/test-apps/ConnectivityTest/Android.mk b/tools/emulator/test-apps/SmokeTests/Android.mk
similarity index 80%
rename from tools/emulator/test-apps/ConnectivityTest/Android.mk
rename to tools/emulator/test-apps/SmokeTests/Android.mk
index ca20d57..ccd3eb4 100644
--- a/tools/emulator/test-apps/ConnectivityTest/Android.mk
+++ b/tools/emulator/test-apps/SmokeTests/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2011 The Android Open Source Project
+# Copyright (C) 2014 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.
@@ -15,18 +15,18 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
LOCAL_MODULE_TAGS := optional
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := ConnectivityTest
+LOCAL_PACKAGE_NAME := EmulatorSmokeTests
LOCAL_SDK_VERSION := 4
LOCAL_PROGUARD_ENABLED := disabled
-include $(BUILD_PACKAGE)
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(BUILD_PACKAGE)
diff --git a/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml b/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
similarity index 70%
rename from tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
rename to tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
index 80f65cf..8843a00 100644
--- a/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
+++ b/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2014 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.
@@ -14,14 +14,14 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.emulator.connectivity.test"
- android:versionCode="1"
- android:versionName="1.0">
+ package="com.android.emulator.smoketests">
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_SMS" />
<uses-sdk android:minSdkVersion="4" />
- <instrumentation android:targetPackage="com.android.emulator.connectivity.test" android:name="android.test.InstrumentationTestRunner" />
- <application android:label="Connectivity Test">
- <uses-library android:name="android.test.runner" />
+ <instrumentation android:targetPackage="com.android.emulator.smoketests"
+ android:name="android.support.test.runner.AndroidJUnitRunner" />
+ <application android:label="Emulator Smoke Tests">
</application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
similarity index 97%
rename from tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
rename to tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
index 9931eb8..9fe1ebe 100644
--- a/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
+++ b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.emulator.connectivity.test;
+package com.android.emulator.smoketests.connectivity;
import java.io.IOException;
import java.net.URL;
diff --git a/tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
similarity index 98%
rename from tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
rename to tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
index 6eb3834..1e0258c 100644
--- a/tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
+++ b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.emulator.gps.test;
+package com.android.emulator.smoketests.gps;
import android.content.Context;
import android.location.Location;
diff --git a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java
new file mode 100644
index 0000000..2e18cc4
--- /dev/null
+++ b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 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.emulator.smoketests.sms;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.HandlerThread;
+import android.support.test.InjectContext;
+
+import org.junit.Assert;
+import static junit.framework.Assert.assertEquals;
+
+import org.junit.Test;
+/**
+ * Sms Test
+ *
+ * Test that an SMS message has been received
+ */
+public class SmsTest {
+
+ /**
+ * Prior to running this test an sms must be sent
+ * via DDMS
+ */
+ public final static String NUMBER = "5551212";
+ public final static String BODY = "test sms";
+ private final static int SMS_POLL_TIME_MS = 10 * 1000;
+ private final static int SIXY_SECONDS_OF_LOOPS = 6;
+ @InjectContext
+ public Context mContext;
+
+ /**
+ * Verify that an SMS has been received with the correct number and body
+ */
+ @Test
+ public void testReceivedSms() throws java.lang.InterruptedException {
+ Cursor c = getSmsCursor();
+ c.moveToFirst();
+
+ String number = c.getString(c.getColumnIndexOrThrow("address"));
+ String body = c.getString(c.getColumnIndexOrThrow("body"));
+
+ c.close();
+
+ assertEquals(NUMBER, number);
+ assertEquals(BODY, body);
+ }
+
+ private Cursor getSmsCursor() throws java.lang.InterruptedException {
+ ContentResolver r = mContext.getContentResolver();
+ Uri message = Uri.parse("content://sms/");
+ Cursor c;
+
+ for(int i = 0; i < SIXY_SECONDS_OF_LOOPS; i++) {
+ c = r.query(message,null,null,null,null);
+
+ if(c.getCount() != 0) {
+ return c;
+ }
+
+ c.close();
+ Thread.sleep(SMS_POLL_TIME_MS);
+ }
+ Assert.fail("Did not find any SMS messages. Giving up");
+ // necessary for compilation
+ return null;
+ }
+
+}
diff --git a/tools/idegen/index-gen.sh b/tools/idegen/index-gen.sh
index 5b9e24b..3363308 100755
--- a/tools/idegen/index-gen.sh
+++ b/tools/idegen/index-gen.sh
@@ -38,8 +38,8 @@
exit 1
fi
fi
-tmp_file=tmp.txt
-dest_file=module-index.txt
+tmp_file=${root_dir}/tmp.txt
+dest_file=${root_dir}/module-index.txt
echo "Generating index file $dest_file..."
start=$(($(date +%s%N) / 1000000))
diff --git a/tools/idegen/intellij-gen.sh b/tools/idegen/intellij-gen.sh
index d67c1f8..860bd3c 100755
--- a/tools/idegen/intellij-gen.sh
+++ b/tools/idegen/intellij-gen.sh
@@ -32,13 +32,15 @@
set -e
progname=`basename $0`
-if [ $# -ne 1 ]
+if [ $# -lt 2 ]
then
- echo "Usage: $progname <module_name>"
+ echo "Usage: $progname project_dir module_dir <module_dir>..."
exit 1
fi
-module_name=$1
-
+project_dir=${PWD}/$1
+shift
+module_dirs=$@
+echo $module_dirs
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
root_dir=$PWD
if [ ! -e $root_dir/.repo ]; then
@@ -63,8 +65,8 @@
echo "Checking for $idegenjar"
if [ -e "$idegenjar" ]; then
- echo "Generating project files for $module_name"
- cmd="java -cp $idegenjar com.android.idegen.IntellijProject $index_file $module_name"
+ echo "Generating project files for $module_dirs"
+ cmd="java -cp $idegenjar com.android.idegen.IntellijProject $index_file $project_dir $module_dirs"
echo $cmd
$cmd
else
diff --git a/tools/idegen/src/com/android/idegen/AggregatedModule.java b/tools/idegen/src/com/android/idegen/AggregatedModule.java
deleted file mode 100644
index 1497da7..0000000
--- a/tools/idegen/src/com/android/idegen/AggregatedModule.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2012 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.idegen;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-
-/**
- * Module while is a composition of many other modules.
- * <p>
- * This is needed since intellij does not allow two modules to share the same content root.
- */
-public class AggregatedModule extends Module {
-
- private static final Logger logger = Logger.getLogger(AggregatedModule.class.getName());
-
- private String aggregatedModuleName;
- private Set<Module> modules;
- private HashSet<String> directDependencies = Sets.newHashSet();
-
- public AggregatedModule(String aggregatedName, Set<Module> modules) {
- this.aggregatedModuleName = Preconditions.checkNotNull(aggregatedName);
- this.modules = Preconditions.checkNotNull(modules);
- }
-
- public void build() throws IOException {
- // Create an iml file that contains all the srcs of modules.
- buildDependentModules();
- buildDirectDependencies();
- //buildImlFile();
- }
-
- @Override
- protected File getDir() {
- // All modules should be in the same directory so just pull the first.
- return modules.iterator().next().getDir();
- }
-
- @Override
- protected boolean isAndroidModule() {
- for (Module module : modules) {
- if (module.isAndroidModule()) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- protected List<File> getIntermediatesDirs() {
- List<File> result = Lists.newArrayList();
- for (Module module : modules) {
- Iterables.addAll(result, module.getIntermediatesDirs());
- }
- return result;
- }
-
- public void buildDirectDependencies() {
- for (Module module : modules) {
- Set<String> deps = module.getDirectDependencies();
- directDependencies.addAll(deps);
- }
- }
-
- @Override
- public Set<String> getDirectDependencies() {
- return directDependencies;
- }
-
- @Override
- protected ImmutableList<File> getSourceDirs() {
- ImmutableList.Builder<File> builder = ImmutableList.builder();
- for (Module module : modules) {
- builder.addAll(module.getSourceDirs());
- }
- return builder.build();
- }
-
-
- @Override
- protected ImmutableList<File> getExcludeDirs() {
- ImmutableList.Builder<File> builder = ImmutableList.builder();
- for (Module module : modules) {
- builder.addAll(module.getExcludeDirs());
- }
- return builder.build();
- }
-
- @Override
- public Set<File> getAllDependentImlFiles() {
- Set<File> result = Sets.newHashSet();
- for (Module module : modules) {
- result.addAll(module.getAllDependentImlFiles());
- }
- return result;
- }
-
- @Override
- public File getRepoRoot() {
- return modules.iterator().next().getRepoRoot();
- }
-
- @Override
- public String getName() {
- return aggregatedModuleName;
- }
-
-}
diff --git a/tools/idegen/src/com/android/idegen/DirectorySearch.java b/tools/idegen/src/com/android/idegen/DirectorySearch.java
index 2ff23e3..c289ac2 100644
--- a/tools/idegen/src/com/android/idegen/DirectorySearch.java
+++ b/tools/idegen/src/com/android/idegen/DirectorySearch.java
@@ -23,6 +23,7 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
+import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.logging.Level;
@@ -37,7 +38,8 @@
private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
- private static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
+ public static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
+
static {
SOURCE_DIRS.add("src");
SOURCE_DIRS.add("java");
@@ -51,37 +53,71 @@
+ REL_TEMPLATE_DIR;
/**
+ * Returns the previously initialized repo root.
+ */
+ public static File getRepoRoot() {
+ Preconditions.checkNotNull(repoRoot, "repoRoot has not been initialized yet. Call "
+ + "findAndInitRepoRoot() first.");
+ return repoRoot;
+ }
+
+ /**
* Find the repo root. This is the root branch directory of a full repo checkout.
*
* @param file any file inside the root.
* @return the root directory.
*/
- public static File findRepoRoot(File file) {
+ public static void findAndInitRepoRoot(File file) {
Preconditions.checkNotNull(file);
if (repoRoot != null) {
- return repoRoot;
+ return;
}
if (file.isDirectory()) {
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
- if (".repo".equals(name)) {
- return true;
- }
- return false;
+ return ".repo".equals(name);
}
});
if (files.length > 0) {
repoRoot = file;
- return file;
}
}
File parent = file.getParentFile();
if (parent == null) {
- return null;
+ throw new IllegalStateException("Repo root not found from starting point " +
+ file.getPath());
}
- return findRepoRoot(parent);
+ findAndInitRepoRoot(parent);
+ }
+
+ /**
+ * Searches up the parent chain to find the closes module root directory. A module root is one
+ * with an Android.mk file in it. <p> For example, the module root for directory
+ * <code>package/apps/Contacts/src</code> is <code>packages/apps/Contacts</code>
+ *
+ * @return the module root.
+ * @throws IOException when module root is not found.
+ */
+ public static File findModuleRoot(File path) throws IOException {
+ Preconditions.checkNotNull(path);
+ File dir;
+ if (path.isFile()) {
+ dir = path.getParentFile();
+ } else {
+ dir = path;
+ }
+ while (dir != null) {
+ File makeFile = new File(dir, "Android.mk");
+ if (makeFile.exists()) {
+ return dir;
+ } else {
+ dir = dir.getParentFile();
+ }
+ }
+ // At this point, there are no parents and we have not found a module. Error.
+ throw new IOException("Module root not found for path " + path.getCanonicalPath());
}
/**
@@ -105,10 +141,19 @@
File[] children = file.listFiles();
for (File child : children) {
if (child.isDirectory()) {
- if (SOURCE_DIRS.contains(child.getName())) {
- builder.add(child);
+ // Recurse further down the tree first to cover case of:
+ //
+ // src/java
+ // or
+ // java/src
+ //
+ // In either of these cases, we don't want the parent.
+ ImmutableList<File> dirs = findSourceDirs(child);
+ if (dirs.isEmpty()) {
+ if (SOURCE_DIRS.contains(child.getName())) {
+ builder.add(child);
+ }
} else {
- ImmutableList<File> dirs = findSourceDirs(child);
builder.addAll(dirs);
}
}
@@ -151,20 +196,28 @@
private static File templateDirCurrent = null;
private static File templateDirRoot = null;
- public static File findTemplateDir() throws FileNotFoundException {
+ public static File findTemplateDir() throws IOException {
// Cache optimization.
- if (templateDirCurrent != null && templateDirCurrent.exists()) return templateDirCurrent;
- if (templateDirRoot != null && templateDirRoot.exists()) return templateDirRoot;
+ if (templateDirCurrent != null && templateDirCurrent.exists()) {
+ return templateDirCurrent;
+ }
+ if (templateDirRoot != null && templateDirRoot.exists()) {
+ return templateDirRoot;
+ }
File currentDir = null;
try {
- currentDir = new File(IntellijProject.class.getProtectionDomain().getCodeSource()
- .getLocation().toURI().getPath()).getParentFile();
+ currentDir = new File(
+ IntellijProject.class.getProtectionDomain().getCodeSource().getLocation()
+ .toURI().getPath()).getParentFile();
} catch (URISyntaxException e) {
logger.log(Level.SEVERE, "Could not get jar location.", e);
return null;
}
-
+ // Support for program execution in intellij.
+ if (currentDir.getPath().endsWith("out/production")) {
+ return new File(currentDir.getParentFile().getParentFile(), REL_TEMPLATE_DIR);
+ }
// First check relative to current run directory.
templateDirCurrent = new File(currentDir, REL_TEMPLATE_DIR);
if (templateDirCurrent.exists()) {
@@ -178,7 +231,7 @@
}
throw new FileNotFoundException(
"Unable to find template dir. Tried the following locations:\n" +
- templateDirCurrent.getAbsolutePath() + "\n" +
- templateDirRoot.getAbsolutePath());
+ templateDirCurrent.getCanonicalPath() + "\n" +
+ templateDirRoot.getCanonicalPath());
}
}
diff --git a/tools/idegen/src/com/android/idegen/FrameworkModule.java b/tools/idegen/src/com/android/idegen/FrameworkModule.java
index 8743925..47ea35a 100644
--- a/tools/idegen/src/com/android/idegen/FrameworkModule.java
+++ b/tools/idegen/src/com/android/idegen/FrameworkModule.java
@@ -16,33 +16,35 @@
package com.android.idegen;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.io.File;
+import java.io.IOException;
/**
* Special module used for framework to build one off resource directory.
*/
-public class FrameworkModule extends StandardModule {
+public class FrameworkModule extends Module {
// Framework needs a special constant for it's intermediates because it does not follow
// normal conventions.
private static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
- public FrameworkModule(String moduleName, String makeFile) {
- super(IntellijProject.FRAMEWORK_MODULE, makeFile, true);
+ public FrameworkModule(File moduleDir) throws IOException {
+ super(Preconditions.checkNotNull(moduleDir), false);
}
@Override
- protected String buildIntermediates() {
+ protected String buildIntermediates() throws IOException {
StringBuilder sb = new StringBuilder();
- File intermediates = new File(repoRoot,
+ File intermediates = new File(DirectorySearch.getRepoRoot(),
REL_OUT_APP_DIR + File.separator + FRAMEWORK_INTERMEDIATES);
ImmutableList<File> intermediateSrcDirs = DirectorySearch.findSourceDirs(intermediates);
sb.append(" <content url=\"file://").append(intermediates).append("\">\n");
for (File src : intermediateSrcDirs) {
sb.append(" <sourceFolder url=\"file://")
- .append(src.getAbsolutePath()).append("\" isTestSource=\"false\" />\n");
+ .append(src.getCanonicalPath()).append("\" isTestSource=\"false\" />\n");
}
sb.append(" </content>\n");
return sb.toString();
diff --git a/tools/idegen/src/com/android/idegen/IntellijProject.java b/tools/idegen/src/com/android/idegen/IntellijProject.java
index e49a12b..e3b8d94 100644
--- a/tools/idegen/src/com/android/idegen/IntellijProject.java
+++ b/tools/idegen/src/com/android/idegen/IntellijProject.java
@@ -17,14 +17,14 @@
package com.android.idegen;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Lists;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Set;
import java.util.logging.Logger;
/**
@@ -32,7 +32,7 @@
*/
public class IntellijProject {
- public static final String FRAMEWORK_MODULE = "framework";
+ public static final String FRAMEWORK_MODULE_DIR = "frameworks/base";
public static final Charset CHARSET = Charset.forName("UTF-8");
private static final Logger logger = Logger.getLogger(IntellijProject.class.getName());
@@ -42,147 +42,116 @@
ModuleCache cache = ModuleCache.getInstance();
+ boolean buildFramework;
File indexFile;
- File repoRoot;
- File projectIdeaDir;
- String moduleName;
+ File projectPath;
+ ArrayList<String> moduleDirs;
- public IntellijProject(String indexFile, String moduleName) {
+ public IntellijProject(String indexFile, String projectPath, ArrayList<String> moduleDirs,
+ boolean buildFramework) {
this.indexFile = new File(Preconditions.checkNotNull(indexFile));
- this.moduleName = Preconditions.checkNotNull(moduleName);
- }
-
- private void init() throws IOException {
- repoRoot = DirectorySearch.findRepoRoot(indexFile);
- cache.init(indexFile);
+ this.projectPath = new File(Preconditions.checkNotNull(projectPath));
+ this.moduleDirs = Preconditions.checkNotNull(moduleDirs);
+ this.buildFramework = buildFramework;
+ DirectorySearch.findAndInitRepoRoot(this.indexFile);
}
public void build() throws IOException {
- init();
- buildFrameWorkModule();
-
- // First pass, find all dependencies and cache them.
- Module module = cache.getAndCache(moduleName);
- if (module == null) {
- logger.info("Module '" + moduleName + "' not found." +
- " Module names are case senstive.");
- return;
- }
- projectIdeaDir = new File(module.getDir(), ".idea");
- projectIdeaDir.mkdir();
- copyTemplates();
-
- // Second phase, build aggregate modules.
- Set<String> deps = module.getAllDependencies();
- for (String dep : deps) {
- cache.buildAndCacheAggregatedModule(dep);
+ cache.init(indexFile);
+ File repoRoot = DirectorySearch.getRepoRoot();
+ if (buildFramework) {
+ File frameworkDir = new File(repoRoot, FRAMEWORK_MODULE_DIR);
+ // Some unbundled apps/branches do not include the framework.
+ if (frameworkDir.exists()) {
+ buildFrameWorkModule(new File(repoRoot, FRAMEWORK_MODULE_DIR));
+ }
}
- // Third phase, replace individual modules with aggregated modules
- Iterable<Module> modules = cache.getModules();
- for (Module mod : modules) {
- replaceWithAggregate(mod);
+ for (String moduleDir : moduleDirs) {
+ // First pass, find all dependencies and cache them.
+ File dir = new File(repoRoot, moduleDir);
+ if (!dir.exists()) {
+ logger.info("Directory " + moduleDir + " does not exist in " + repoRoot +
+ ". Are you sure the directory is correct?");
+ return;
+ }
+ Module module = cache.getAndCacheByDir(dir);
+ if (module == null) {
+ logger.info("Module '" + dir.getPath() + "' not found." +
+ " Module names are case senstive.");
+ return;
+ }
}
// Finally create iml files for dependencies
+ Iterable<Module> modules = cache.getModules();
for (Module mod : modules) {
mod.buildImlFile();
}
- createModulesFile(module);
- createVcsFile(module);
- createNameFile(moduleName);
+ createProjectFiles();
}
- private void replaceWithAggregate(Module module) {
- replaceWithAggregate(module.getDirectDependencies(), module.getName());
- replaceWithAggregate(module.getAllDependencies(), module.getName());
-
- }
-
- private void replaceWithAggregate(Set<String> deps, String moduleName) {
- for (String dep : Sets.newHashSet(deps)) {
- String replacement = cache.getAggregateReplacementName(dep);
- if (replacement != null) {
-
- deps.remove(dep);
- // There could be dependencies on self due to aggregation.
- // Only add if the replacement is not self.
- if (!replacement.equals(moduleName)) {
- deps.add(replacement);
- }
- }
- }
+ private void createProjectFiles() throws IOException {
+ File ideaDir = new File(projectPath, ".idea");
+ ideaDir.mkdirs();
+ copyTemplates(ideaDir);
+ createModulesFile(ideaDir, cache.getModules());
+ createVcsFile(ideaDir, cache.getModules());
+ createNameFile(ideaDir, projectPath.getName());
}
/**
* Framework module needs special handling due to one off resource path:
* frameworks/base/Android.mk
*/
- private void buildFrameWorkModule() throws IOException {
- String makeFile = cache.getMakeFile(FRAMEWORK_MODULE);
- if (makeFile == null) {
- logger.warning("Unable to find framework module: " + FRAMEWORK_MODULE +
- ". Skipping.");
- } else {
- logger.info("makefile: " + makeFile);
- StandardModule frameworkModule = new FrameworkModule(FRAMEWORK_MODULE,
- makeFile);
- frameworkModule.build();
- cache.put(frameworkModule);
- }
+ private void buildFrameWorkModule(File frameworkModuleDir) throws IOException {
+ FrameworkModule frameworkModule = new FrameworkModule(frameworkModuleDir);
+ frameworkModule.build();
+ cache.put(frameworkModule);
}
- private void createModulesFile(Module module) throws IOException {
- String modulesContent = Files.toString(
- new File(DirectorySearch.findTemplateDir(),
- "idea" + File.separator + MODULES_TEMPLATE_FILE_NAME),
- CHARSET);
+ private void createModulesFile(File ideaDir, Iterable<Module> modules) throws IOException {
+ String modulesContent = Files.toString(new File(DirectorySearch.findTemplateDir(),
+ "idea" + File.separator + MODULES_TEMPLATE_FILE_NAME), CHARSET);
StringBuilder sb = new StringBuilder();
- File moduleIml = module.getImlFile();
- sb.append(" <module fileurl=\"file://").append(moduleIml.getAbsolutePath())
- .append("\" filepath=\"").append(moduleIml.getAbsolutePath()).append("\" />\n");
- for (String name : module.getAllDependencies()) {
- Module mod = cache.getAndCache(name);
+ for (Module mod : modules) {
File iml = mod.getImlFile();
- sb.append(" <module fileurl=\"file://").append(iml.getAbsolutePath())
- .append("\" filepath=\"").append(iml.getAbsolutePath()).append("\" />\n");
+ sb.append(" <module fileurl=\"file://").append(iml.getCanonicalPath()).append(
+ "\" filepath=\"").append(iml.getCanonicalPath()).append("\" />\n");
}
modulesContent = modulesContent.replace("@MODULES@", sb.toString());
- File out = new File(projectIdeaDir, "modules.xml");
- logger.info("Creating " + out.getAbsolutePath());
+ File out = new File(ideaDir, "modules.xml");
+ logger.info("Creating " + out.getCanonicalPath());
Files.write(modulesContent, out, CHARSET);
}
- private void createVcsFile(Module module) throws IOException {
- String vcsTemplate = Files.toString(
- new File(DirectorySearch.findTemplateDir(),
- "idea" + File.separator + VCS_TEMPLATE_FILE_NAME),
- CHARSET);
+ private void createVcsFile(File ideaDir, Iterable<Module> modules) throws IOException {
+ String vcsTemplate = Files.toString(new File(DirectorySearch.findTemplateDir(),
+ "idea" + File.separator + VCS_TEMPLATE_FILE_NAME), CHARSET);
StringBuilder sb = new StringBuilder();
- for (String name : module.getAllDependencies()) {
- Module mod = cache.getAndCache(name);
+ for (Module mod : modules) {
File dir = mod.getDir();
File gitRoot = new File(dir, ".git");
if (gitRoot.exists()) {
- sb.append(" <mapping directory=\"").append(dir.getAbsolutePath())
- .append("\" vcs=\"Git\" />\n");
+ sb.append(" <mapping directory=\"").append(dir.getCanonicalPath()).append(
+ "\" vcs=\"Git\" />\n");
}
}
vcsTemplate = vcsTemplate.replace("@VCS@", sb.toString());
- Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), CHARSET);
+ Files.write(vcsTemplate, new File(ideaDir, "vcs.xml"), CHARSET);
}
- private void createNameFile(String name) throws IOException {
- File out = new File(projectIdeaDir, ".name");
+ private void createNameFile(File ideaDir, String name) throws IOException {
+ File out = new File(ideaDir, ".name");
Files.write(name, out, CHARSET);
}
- private void copyTemplates() throws IOException {
+ private void copyTemplates(File ideaDir) throws IOException {
File templateDir = DirectorySearch.findTemplateDir();
- copyTemplates(new File(templateDir, "idea"), projectIdeaDir);
+ copyTemplates(new File(templateDir, "idea"), ideaDir);
}
private void copyTemplates(File fromDir, File toDir) throws IOException {
@@ -191,11 +160,14 @@
for (File file : files) {
if (file.isDirectory()) {
File destDir = new File(toDir, file.getName());
+ if (!destDir.exists()) {
+ destDir.mkdirs();
+ }
copyTemplates(file, destDir);
} else {
File toFile = new File(toDir, file.getName());
- logger.info("copying " + file.getAbsolutePath() + " to " +
- toFile.getAbsolutePath());
+ logger.info("copying " + file.getCanonicalPath() + " to " +
+ toFile.getCanonicalPath());
Files.copy(file, toFile);
}
}
@@ -204,10 +176,32 @@
public static void main(String[] args) {
logger.info("Args: " + Arrays.toString(args));
- String indexFile = args[0];
- String module = args[1];
+ if (args.length < 3) {
+ logger.severe("Not enough input arguments. Aborting");
+ return;
+ }
- IntellijProject intellij = new IntellijProject(indexFile, module);
+ boolean buildFramework = true;
+ int argIndex = 0;
+ String arg = args[argIndex];
+ while (arg.startsWith("--")) {
+ if (arg.equals("--no-framework")) {
+ buildFramework = false;
+ }
+ argIndex++;
+ arg = args[argIndex];
+ }
+
+ String indexFile = args[argIndex++];
+ String projectPath = args[argIndex++];
+ // Remaining args are module directories
+ ArrayList<String> moduleDirs = Lists.newArrayList();
+ for (int i = argIndex; i < args.length; i++) {
+ moduleDirs.add(args[i]);
+ }
+
+ IntellijProject intellij = new IntellijProject(indexFile, projectPath, moduleDirs,
+ buildFramework);
try {
intellij.build();
} catch (IOException e) {
diff --git a/tools/idegen/src/com/android/idegen/MakeFileParser.java b/tools/idegen/src/com/android/idegen/MakeFileParser.java
index 3594d50..9a41b09 100644
--- a/tools/idegen/src/com/android/idegen/MakeFileParser.java
+++ b/tools/idegen/src/com/android/idegen/MakeFileParser.java
@@ -22,6 +22,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
@@ -29,7 +30,9 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.logging.Logger;
@@ -41,16 +44,7 @@
private static final Logger logger = Logger.getLogger(MakeFileParser.class.getName());
public static final String VALUE_DELIMITER = "|";
- private enum State {
- NEW, CONTINUE
- }
- private enum ModuleNameKey {
- LOCAL_PACKAGE_NAME,
- LOCAL_MODULE
- };
-
private File makeFile;
- private String moduleName;
private HashMap<String, String> values;
/**
@@ -59,11 +53,9 @@
* A make file may contain multiple modules.
*
* @param makeFile The make file to parse.
- * @param moduleName The module to extract.
*/
- public MakeFileParser(File makeFile, String moduleName) {
+ public MakeFileParser(File makeFile) {
this.makeFile = Preconditions.checkNotNull(makeFile);
- this.moduleName = Preconditions.checkNotNull(moduleName);
}
public Iterable<String> getValues(String key) {
@@ -71,163 +63,214 @@
if (str == null) {
return null;
}
- return Splitter.on(VALUE_DELIMITER)
- .trimResults()
- .omitEmptyStrings()
- .split(str);
+ return Splitter.on(VALUE_DELIMITER).trimResults().omitEmptyStrings().split(str);
}
/**
- * Extracts the relevant portion of the make file and converts into key value pairs.
- * <p>
- * Since each make file may contain multiple build targets (modules), this method will determine
- * which part is the correct portion for the given module name.
- *
- * @throws IOException
+ * Extracts the relevant portion of the make file and converts into key value pairs. <p> Since
+ * each make file may contain multiple build targets (modules), this method will determine which
+ * part is the correct portion for the given module name.
*/
public void parse() throws IOException {
values = Maps.newHashMap();
- logger.info("Parsing " + makeFile.getAbsolutePath() + " for module " + moduleName);
+ logger.info("Parsing " + makeFile.getCanonicalPath());
- Files.readLines(makeFile, Charset.forName("UTF-8"), new LineProcessor<Object>() {
-
- private String key;
-
- private State state = State.NEW;
-
- @Override
- public boolean processLine(String line) throws IOException {
- String trimmed = line.trim();
- if (Strings.isNullOrEmpty(trimmed)) {
- state = State.NEW;
- return true;
- }
- if (trimmed.equals("include $(CLEAR_VARS)")) {
- // See if we are in the right module.
- if (moduleName.equals(getModuleName())) {
- return false;
- } else {
- values.clear();
- }
- } else {
- switch (state) {
- case NEW:
- trimmed = checkContinue(trimmed);
- if (trimmed.contains("=")) {
- String[] arr;
- if (trimmed.contains(":")) {
- arr = trimmed.split(":=");
- } else {
- arr = trimmed.split("\\+=");
- }
- if (arr.length > 2) {
- logger.info("Malformed line " + line);
- } else {
- // Store the key in case the line continues
- this.key = arr[0].trim();
- if (arr.length == 2) {
- // There may be multiple values on one line.
- List<String> valuesArr = tokenizeValue(arr[1].trim());
- for (String value : valuesArr) {
- appendValue(this.key, value);
- }
-
- }
- }
- } else {
- //logger.info("Skipping line " + line);
- }
- break;
- case CONTINUE:
- // append
- trimmed = checkContinue(trimmed);
- appendValue(key, trimmed);
- break;
- default:
-
- }
- }
- return true;
- }
-
- private List<String> tokenizeValue(String value) {
- // Value may contain function calls such as "$(call all-java-files-under)".
- // Tokens are separated by spaces unless it's between parens.
- StringBuilder token = new StringBuilder();
- ArrayList<String> tokens = Lists.newArrayList();
- int parenCount = 0;
- for (int i = 0; i < value.length(); i++) {
- char ch = value.charAt(i);
- if (parenCount == 0 && ch == ' ') {
- // Not in a paren and delimiter encountered.
- // end token
- if (token.length() > 0) {
- tokens.add(token.toString());
- token = new StringBuilder();
- }
- } else {
- token.append(ch);
- }
- if (ch == '(') {
- parenCount++;
- } else if (ch == ')') {
- parenCount--;
- }
- }
- // end of line check
- if (token.length() > 0) {
- tokens.add(token.toString());
- }
- return tokens;
- }
-
- private String getModuleName() {
- for (ModuleNameKey key : ModuleNameKey.values()) {
- String name = values.get(key.name());
- if (name != null) {
- return name;
- }
- }
- return null;
- }
-
- @Override
- public Object getResult() {
- return null;
- }
-
- private String checkContinue(String value) {
- // Check for continuation character
- if (value.charAt(value.length() - 1) == '\\') {
- state = State.CONTINUE;
- return value.substring(0, value.length() - 1);
- }
- state = State.NEW;
- return value;
- }
-
- /**
- * Add a value to the hash map. If the key already exists, will append instead of
- * over-writing the existing value.
- *
- * @param key The hashmap key
- * @param newValue The value to append.
- */
- private void appendValue(String key, String newValue) {
- String value = values.get(key);
- if (value == null) {
- values.put(key, newValue);
- } else {
- values.put(key, value + VALUE_DELIMITER + newValue);
- }
- }
- });
+ Files.readLines(makeFile, Charset.forName("UTF-8"), new MakeFileLineProcessor());
}
@Override
public String toString() {
- return Objects.toStringHelper(this)
- .add("values", values)
- .toString();
+ return Objects.toStringHelper(this).add("values", values).toString();
+ }
+
+ private class MakeFileLineProcessor implements LineProcessor<Object> {
+
+ private StringBuilder lineBuffer;
+
+ // Keep a list of LOCAL_ variables to clear when CLEAR_VARS is encountered.
+ private HashSet<String> localVars = Sets.newHashSet();
+
+ @Override
+ public boolean processLine(String line) throws IOException {
+ String trimmed = line.trim();
+ // Skip comments.
+ if (!trimmed.isEmpty() && trimmed.charAt(0) == '#') {
+ return true;
+ }
+ appendPartialLine(trimmed);
+
+ if (!trimmed.isEmpty() && trimmed.charAt(trimmed.length() - 1) == '\\') {
+ // This is a partial line. Do not process yet.
+ return true;
+ }
+
+ String completeLine = lineBuffer.toString().trim();
+ // Reset the line buffer.
+ lineBuffer = null;
+
+ if (Strings.isNullOrEmpty(completeLine)) {
+ return true;
+ }
+
+ processKeyValuePairs(completeLine);
+ return true;
+ }
+
+ private void processKeyValuePairs(String line) {
+ if (line.contains("=")) {
+ String[] arr;
+ if (line.contains(":")) {
+ arr = line.split(":=");
+ } else {
+ arr = line.split("\\+=");
+ }
+ if (arr.length > 2) {
+ logger.info("Malformed line " + line);
+ } else {
+ // Store the key in case the line continues
+ String key = arr[0].trim();
+ if (arr.length == 2) {
+ // There may be multiple values on one line.
+ List<String> valuesArr = tokenizeValue(arr[1]);
+ for (String value : valuesArr) {
+ appendValue(key, value);
+ }
+
+ }
+ }
+ } else {
+ //logger.info("Skipping line " + line);
+ }
+ }
+
+ private void appendPartialLine(String line) {
+ if (lineBuffer == null) {
+ lineBuffer = new StringBuilder();
+ } else {
+ lineBuffer.append(" ");
+ }
+ if (line.endsWith("\\")) {
+ lineBuffer.append(line.substring(0, line.length() - 2).trim());
+ } else {
+ lineBuffer.append(line);
+ }
+ }
+
+ private List<String> tokenizeValue(String rawValue) {
+ String value = rawValue.trim();
+ ArrayList<String> result = Lists.newArrayList();
+ if (value.isEmpty()) {
+ return result;
+ }
+
+ // Value may contain function calls such as "$(call all-java-files-under)" or refer
+ // to variables such as "$(my_var)"
+ value = findVariables(value);
+
+ String[] tokens = value.split(" ");
+ Collections.addAll(result, tokens);
+ return result;
+ }
+
+ private String findVariables(String value) {
+
+ int variableStart = value.indexOf('$');
+ // Keep going until we substituted all variables.
+ while (variableStart > -1) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(value.substring(0, variableStart));
+
+ // variable found
+ int variableEnd = findClosingParen(value, variableStart);
+ if (variableEnd > variableStart) {
+ String result = substituteVariables(value.substring(variableStart + 2, variableEnd));
+ sb.append(result);
+ } else {
+ throw new IllegalArgumentException(
+ "Malformed variable reference in make file: " + value);
+ }
+ if (variableEnd + 1 < value.length()) {
+ sb.append(value.substring(variableEnd + 1));
+ }
+ value = sb.toString();
+ variableStart = value.indexOf('$');
+ }
+ return value;
+ }
+
+ private int findClosingParen(String value, int startIndex) {
+ int openParenCount = 0;
+ for (int i = startIndex; i < value.length(); i++) {
+ char ch = value.charAt(i);
+ if (ch == ')') {
+ openParenCount--;
+ if (openParenCount == 0) {
+ return i;
+ }
+ } else if (ch == '(') {
+ openParenCount++;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Look for and handle $(...) variables.
+ */
+ private String substituteVariables(String rawValue) {
+ if (rawValue.isEmpty()) {
+ return rawValue;
+ }
+ String value = rawValue;
+ if (value.startsWith("call all-java-files-under")) {
+ // Ignore the call and function, keep the args.
+ value = value.substring(25).trim();
+ } else if (value.startsWith("call")) {
+ value = value.substring(4).trim();
+ }
+
+ // Check for single variable
+ if (value.indexOf(' ') == -1) {
+ // Substitute.
+ value = values.get(value);
+ if (value == null) {
+ value = "";
+ }
+ return value;
+ } else {
+ return findVariables(value);
+ }
+ }
+
+ @Override
+ public Object getResult() {
+ return null;
+ }
+
+ /**
+ * Add a value to the hash map. If the key already exists, will append instead of
+ * over-writing the existing value.
+ *
+ * @param key The hashmap key
+ * @param newValue The value to append.
+ */
+ private void appendValue(String key, String newValue) {
+ String value = values.get(key);
+ if (value == null) {
+ values.put(key, newValue);
+ } else {
+ values.put(key, value + VALUE_DELIMITER + newValue);
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ MakeFileParser parser = new MakeFileParser(new File(args[0]));
+ try {
+ parser.parse();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ System.out.println(parser.toString());
}
}
diff --git a/tools/idegen/src/com/android/idegen/Module.java b/tools/idegen/src/com/android/idegen/Module.java
index deb2281..4695ca3 100644
--- a/tools/idegen/src/com/android/idegen/Module.java
+++ b/tools/idegen/src/com/android/idegen/Module.java
@@ -17,24 +17,44 @@
package com.android.idegen;
import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
/**
- * Super class for all modules.
+ * Module constructed from a make file.
+ *
+ * TODO: read the make file and understand included source dirs in addition to searching
+ * sub-directories. Make files can include sources that are not sub-directories. For example, the
+ * framework module includes sources from:
+ *
+ * external/libphonenumber/java/src
+ *
+ * to provide:
+ *
+ * com.android.i18n.phonenumbers.PhoneNumberUtil;
*/
-public abstract class Module {
+public class Module {
private static final Logger logger = Logger.getLogger(Module.class.getName());
+ public static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
+
private static final String IML_TEMPLATE_FILE_NAME = "module-template.iml";
+ private static final String[] AUTO_DEPENDENCIES = new String[]{"framework", "libcore"};
+ private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{"packages", "vendor",
+ "frameworks/ex", "frameworks/opt", "frameworks/support"};
/**
* All possible attributes for the make file.
@@ -45,31 +65,155 @@
LOCAL_SRC_FILES
}
- ModuleCache moduleCache = ModuleCache.getInstance();
+ private ModuleCache moduleCache = ModuleCache.getInstance();
private File imlFile;
-
private Set<String> allDependencies = Sets.newHashSet(); // direct + indirect
-
private Set<File> allDependentImlFiles = Sets.newHashSet();
- protected abstract void build() throws IOException;
+ private File makeFile;
+ private File moduleRoot;
+ private HashSet<File> sourceFiles = Sets.newHashSet();
- protected abstract String getName();
+ // Module dependencies come from LOCAL_STATIC_JAVA_LIBRARIES or LOCAL_JAVA_LIBRARIES
+ Set<String> explicitModuleNameDependencies = Sets.newHashSet();
+ // Implicit module dependencies come from src files that fall outside the module root directory.
+ // For example, if packages/apps/Contacts includes src files from packages/apps/ContactsCommon,
+ // that is an implicit module dependency. It's not a module dependency from the build
+ // perspective but it needs to be a separate module in intellij so that the src files can be
+ // shared by multiple intellij modules.
+ Set<File> implicitModulePathDependencies = Sets.newHashSet();
- protected abstract File getDir();
+ String relativeIntermediatesDir;
+ MakeFileParser makeFileParser;
+ boolean parseMakeFileForSource;
- protected abstract boolean isAndroidModule();
+ public Module(File moduleDir) throws IOException {
+ this(moduleDir, true);
+ }
- protected abstract List<File> getIntermediatesDirs();
+ public Module(File moduleDir, boolean parseMakeFileForSource) throws IOException {
+ this.moduleRoot = Preconditions.checkNotNull(moduleDir);
+ this.makeFile = new File(moduleDir, "Android.mk");
+ this.relativeIntermediatesDir = calculateRelativePartToRepoRoot() + REL_OUT_APP_DIR +
+ File.separatorChar + getName() + "_intermediates" + File.separator + "src";
+ this.parseMakeFileForSource = parseMakeFileForSource;
- public abstract Set<String> getDirectDependencies();
+ // TODO: auto-detect when framework dependency is needed instead of using coded list.
+ for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
+ // length + 2 to account for slash
+ boolean isDir = makeFile.getCanonicalPath().startsWith(
+ DirectorySearch.getRepoRoot() + "/" + dir);
+ if (isDir) {
+ Collections.addAll(this.explicitModuleNameDependencies, AUTO_DEPENDENCIES);
+ }
+ }
- protected abstract ImmutableList<File> getSourceDirs();
+ makeFileParser = new MakeFileParser(makeFile);
+ }
- protected abstract ImmutableList<File> getExcludeDirs();
+ private String calculateRelativePartToRepoRoot() throws IOException {
+ String rel = moduleRoot.getCanonicalPath().substring(
+ DirectorySearch.getRepoRoot().getCanonicalPath().length());
+ int count = 0;
+ // Count the number of slashes to determine how far back to go.
+ for (int i = 0; i < rel.length(); i++) {
+ if (rel.charAt(i) == '/') {
+ count++;
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < count; i++) {
+ sb.append("../");
+ }
+ return sb.toString();
+ }
- public abstract File getRepoRoot();
+ public void build() throws IOException {
+ makeFileParser.parse();
+ buildDependencyList();
+ buildDependentModules();
+ logger.info("Done building module " + moduleRoot);
+ logger.info(toString());
+ }
+
+ public File getDir() {
+ return moduleRoot;
+ }
+
+ public String getName() {
+ return moduleRoot.getName();
+ }
+
+ private List<String> getRelativeIntermediatesDirs() throws IOException {
+ return Lists.newArrayList(relativeIntermediatesDir);
+ }
+
+ private ImmutableList<File> getSourceDirs() {
+ return ImmutableList.copyOf(sourceFiles);
+ }
+
+ private ImmutableList<File> getExcludeDirs() {
+ return DirectorySearch.findExcludeDirs(makeFile);
+ }
+
+ private boolean isAndroidModule() {
+ File manifest = new File(moduleRoot, "AndroidManifest.xml");
+ return manifest.exists();
+ }
+
+ private void findSourceFilesAndImplicitDependencies() throws IOException {
+ Iterable<String> values = makeFileParser.getValues(Key.LOCAL_SRC_FILES.name());
+ if (values != null) {
+ for (String value : values) {
+ File src = new File(moduleRoot, value);
+
+ // value may contain garbage at this point due to relaxed make file parsing.
+ // filter by existing file.
+ if (src.exists()) {
+ // Look for directories outside the current module directory.
+ if (value.contains("..")) {
+ // Find the closest Android make file.
+ File moduleRoot = DirectorySearch.findModuleRoot(src);
+ implicitModulePathDependencies.add(moduleRoot);
+ } else {
+ if (parseMakeFileForSource) {
+ // Check if source files are subdirectories of generic parent src
+ // directories. If so, no need to add since they are already included.
+ boolean alreadyIncluded = false;
+ for (String parentDir : DirectorySearch.SOURCE_DIRS) {
+ if (value.startsWith(parentDir)) {
+ alreadyIncluded = true;
+ break;
+ }
+ }
+
+ if (!alreadyIncluded) {
+ sourceFiles.add(src);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ sourceFiles.addAll(DirectorySearch.findSourceDirs(moduleRoot));
+ }
+
+ private void buildDependencyList() throws IOException {
+ parseDirectDependencies(Key.LOCAL_STATIC_JAVA_LIBRARIES);
+ parseDirectDependencies(Key.LOCAL_JAVA_LIBRARIES);
+ findSourceFilesAndImplicitDependencies();
+ }
+
+ private void parseDirectDependencies(Key key) {
+ Iterable<String> names = makeFileParser.getValues(key.name());
+ if (names != null) {
+ for (String dependency : names) {
+ explicitModuleNameDependencies.add(dependency);
+ }
+ }
+ }
public void buildImlFile() throws IOException {
String imlTemplate = Files.toString(
@@ -82,19 +226,24 @@
}
imlTemplate = imlTemplate.replace("@FACETS@", facetXml);
- String moduleDir = getDir().getAbsolutePath();
+ String moduleDir = getDir().getCanonicalPath();
StringBuilder sourceDirectories = new StringBuilder();
sourceDirectories.append(" <content url=\"file://$MODULE_DIR$\">\n");
ImmutableList<File> srcDirs = getSourceDirs();
for (File src : srcDirs) {
- String relative = src.getAbsolutePath().substring(moduleDir.length());
+ String relative = src.getCanonicalPath().substring(moduleDir.length());
+ boolean isTestSource = false;
+ if (relative.startsWith("/test")) {
+ isTestSource = true;
+ }
sourceDirectories.append(" <sourceFolder url=\"file://$MODULE_DIR$")
- .append(relative).append("\" isTestSource=\"false\" />\n");
+ .append(relative).append("\" isTestSource=\"").append(isTestSource)
+ .append("\" />\n");
}
ImmutableList<File> excludeDirs = getExcludeDirs();
for (File src : excludeDirs) {
- String relative = src.getAbsolutePath().substring(moduleDir.length());
+ String relative = src.getCanonicalPath().substring(moduleDir.length());
sourceDirectories.append(" <excludeFolder url=\"file://$MODULE_DIR$")
.append(relative).append("\"/>\n");
}
@@ -106,43 +255,62 @@
imlTemplate = imlTemplate.replace("@SOURCES@", sourceDirectories.toString());
StringBuilder moduleDependencies = new StringBuilder();
- for (String dependency : getDirectDependencies()) {
+ for (String dependency : getAllDependencies()) {
+ Module module = moduleCache.getAndCacheByDir(new File(dependency));
moduleDependencies.append(" <orderEntry type=\"module\" module-name=\"")
- .append(dependency).append("\" />\n");
+ .append(module.getName()).append("\" />\n");
}
imlTemplate = imlTemplate.replace("@MODULE_DEPENDENCIES@", moduleDependencies.toString());
imlFile = new File(moduleDir, getName() + ".iml");
- logger.info("Creating " + imlFile.getAbsolutePath());
+ logger.info("Creating " + imlFile.getCanonicalPath());
Files.write(imlTemplate, imlFile, IntellijProject.CHARSET);
}
- protected String buildIntermediates() {
+ protected String buildIntermediates() throws IOException {
StringBuilder sb = new StringBuilder();
- for (File intermediatesDir : getIntermediatesDirs()) {
- sb.append(" <content url=\"file://").append(intermediatesDir).append("\">\n");
- sb.append(" <sourceFolder url=\"file://")
- .append(intermediatesDir.getAbsolutePath())
+ for (String intermediatesDir : getRelativeIntermediatesDirs()) {
+ sb.append(" <content url=\"file://$MODULE_DIR$/").append(intermediatesDir)
+ .append("\">\n");
+ sb.append(" <sourceFolder url=\"file://$MODULE_DIR$/")
+ .append(intermediatesDir)
.append("\" isTestSource=\"false\" />\n");
sb.append(" </content>\n");
}
return sb.toString();
}
- protected void buildDependentModules() throws IOException {
- Set<String> directDependencies = getDirectDependencies();
- String[] copy = directDependencies.toArray(new String[directDependencies.size()]);
- for (String dependency : copy) {
+ private void buildDependentModules() throws IOException {
+ Set<String> moduleNameDependencies = explicitModuleNameDependencies;
- Module child = moduleCache.getAndCache(dependency);
+ String[] copy = moduleNameDependencies.toArray(new String[moduleNameDependencies.size()]);
+ for (String dependency : copy) {
+ logger.info("Building dependency " + dependency);
+ Module child = moduleCache.getAndCacheByName(dependency);
if (child == null) {
- directDependencies.remove(dependency);
+ moduleNameDependencies.remove(dependency);
} else {
- addAllDependencies(dependency);
- addAllDependencies(child.getAllDependencies());
+ allDependencies.add(child.getDir().getCanonicalPath());
+ //allDependencies.addAll(child.getAllDependencies());
//logger.info("Adding iml " + child.getName() + " " + child.getImlFile());
allDependentImlFiles.add(child.getImlFile());
- allDependentImlFiles.addAll(child.getAllDependentImlFiles());
+ //allDependentImlFiles.addAll(child.getAllDependentImlFiles());
+ }
+ }
+ // Don't include self. The current module may have been brought in by framework
+ // dependencies which will create a circular reference.
+ allDependencies.remove(this.getDir().getCanonicalPath());
+ allDependentImlFiles.remove(this.getImlFile());
+
+ // TODO: add implicit dependencies. Convert all modules to be based on directory.
+ for (File dependency : implicitModulePathDependencies) {
+ Module child = moduleCache.getAndCacheByDir(dependency);
+ if (child != null) {
+ allDependencies.add(child.getDir().getCanonicalPath());
+ //allDependencies.addAll(child.getAllDependencies());
+ //logger.info("Adding iml " + child.getName() + " " + child.getImlFile());
+ allDependentImlFiles.add(child.getImlFile());
+ //allDependentImlFiles.addAll(child.getAllDependentImlFiles());
}
}
}
@@ -155,29 +323,22 @@
return allDependencies;
}
- public void addAllDependencies(String dependency) {
- this.allDependencies.add(dependency);
- }
-
- public void addAllDependencies(Set<String> dependencies) {
- this.allDependencies.addAll(dependencies);
- }
-
public Set<File> getAllDependentImlFiles() {
return allDependentImlFiles;
}
- private String buildAndroidFacet() {
+ private String buildAndroidFacet() throws IOException {
// Not sure how to handle android facet for multi-module since there could be more than
// one intermediates directory.
- String dir = getIntermediatesDirs().get(0).getAbsolutePath();
+ String dir = getRelativeIntermediatesDirs().get(0);
String xml = ""
+ " <component name=\"FacetManager\">\n"
+ " <facet type=\"android\" name=\"Android\">\n"
+ " <configuration>\n"
- + " <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"" + dir + "\" />\n"
- + " <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"" + dir
- + "\" />\n"
+ + " <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"" +
+ dir + "\" />\n"
+ + " <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"" +
+ dir + "\" />\n"
+ " <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\""
+ "/AndroidManifest.xml\" />\n"
+ " <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/res\" />\n"
@@ -200,12 +361,33 @@
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(getName());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ Module other = (Module) obj;
+ return Objects.equal(getName(), other.getName());
+ }
+
+ @Override
public String toString() {
- return Objects.toStringHelper(Module.class)
+ return Objects.toStringHelper(this)
.add("name", getName())
.add("allDependencies", allDependencies)
- .add("iml files", allDependentImlFiles)
- .add("imlFile", imlFile)
+ .add("iml files", allDependentImlFiles).add("imlFile", imlFile)
+ .add("makeFileParser", makeFileParser)
+ .add("explicitModuleNameDependencies", Iterables.toString(
+ explicitModuleNameDependencies))
+ .add("implicitModulePathDependencies", Iterables.toString(
+ implicitModulePathDependencies))
.toString();
}
}
diff --git a/tools/idegen/src/com/android/idegen/ModuleCache.java b/tools/idegen/src/com/android/idegen/ModuleCache.java
index 093242a..eb12283 100644
--- a/tools/idegen/src/com/android/idegen/ModuleCache.java
+++ b/tools/idegen/src/com/android/idegen/ModuleCache.java
@@ -18,12 +18,10 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
-import java.util.Set;
import java.util.logging.Logger;
/**
@@ -37,7 +35,9 @@
ModuleIndexes indexes;
- HashMap<String, Module> modulesByName = Maps.newHashMap();
+ // Mapping of canonical module directory to module. Use string instead of File since File
+ // does not provide equality based on canonical path.
+ HashMap<String, Module> modulesByPath = Maps.newHashMap();
private ModuleCache() {
}
@@ -51,57 +51,48 @@
indexes.build();
}
- public Module getAndCache(String moduleName) throws IOException {
- Preconditions.checkState(indexes != null, "You must call init() first.");
+ public Module getAndCacheByDir(File moduleDir) throws IOException {
+ Preconditions.checkNotNull(moduleDir);
- Module module = modulesByName.get(moduleName);
- if (module == null) {
- String makeFile = indexes.getMakeFile(moduleName);
- if (makeFile == null) {
- logger.warning("Unable to find make file for module: " + moduleName);
- } else {
- module = new StandardModule(moduleName, makeFile);
+ if (moduleDir.exists()) {
+ Module module = getModule(moduleDir);
+ if (module == null) {
+ module = new Module(moduleDir);
+ // Must put module before building it. Otherwise infinite loop.
+ putModule(moduleDir, module);
module.build();
- modulesByName.put(moduleName, module);
}
+ return module;
}
- return module;
+ return null;
}
- public void buildAndCacheAggregatedModule(String moduleName) throws IOException {
- if (indexes.isPartOfAggregatedModule(moduleName)) {
- Set<String> moduleNames = indexes.getAggregatedModules(moduleName);
- Set<Module> modules = Sets.newHashSet();
- for (String name : moduleNames) {
- Module m = modulesByName.get(name);
- if (m != null) {
- modules.add(m);
- }
- }
- String aggregatedName = indexes.getAggregateName(moduleName);
- AggregatedModule module = new AggregatedModule(aggregatedName, modules);
- module.build();
- modulesByName.put(aggregatedName, module);
+ public Module getAndCacheByName(String moduleName) throws IOException {
+ Preconditions.checkState(indexes != null, "You must call init() first.");
+ Preconditions.checkNotNull(moduleName);
+
+ String makeFile = indexes.getMakeFile(moduleName);
+ if (makeFile == null) {
+ logger.warning("Unable to find make file for module: " + moduleName);
+ return null;
}
+ return getAndCacheByDir(new File(makeFile).getParentFile());
+ }
+
+ private void putModule(File moduleDir, Module module) throws IOException {
+ modulesByPath.put(moduleDir.getCanonicalPath(), module);
+ }
+
+ private Module getModule(File moduleDir) throws IOException {
+ return modulesByPath.get(moduleDir.getCanonicalPath());
}
public Iterable<Module> getModules() {
- return modulesByName.values();
+ return modulesByPath.values();
}
- public String getMakeFile(String moduleName) {
- return indexes.getMakeFile(moduleName);
- }
-
- public void put(StandardModule module) {
+ public void put(Module module) throws IOException {
Preconditions.checkNotNull(module);
- modulesByName.put(module.getName(), module);
- }
-
- public String getAggregateReplacementName(String moduleName) {
- if (indexes.isPartOfAggregatedModule(moduleName)) {
- return indexes.getAggregateName(moduleName);
- }
- return null;
+ putModule(module.getDir(), module);
}
}
diff --git a/tools/idegen/src/com/android/idegen/ModuleIndexes.java b/tools/idegen/src/com/android/idegen/ModuleIndexes.java
index 890389f..371c2ba 100644
--- a/tools/idegen/src/com/android/idegen/ModuleIndexes.java
+++ b/tools/idegen/src/com/android/idegen/ModuleIndexes.java
@@ -49,7 +49,7 @@
moduleNameToMakeFileMap = Maps.newHashMap();
makeFileToModuleNamesMap = Maps.newHashMap();
- logger.info("Building index from " + indexFile.getAbsolutePath());
+ logger.info("Building index from " + indexFile.getCanonicalPath());
Files.readLines(indexFile, Charset.forName("UTF-8"),
new LineProcessor<Object>() {
int count = 0;
@@ -84,7 +84,7 @@
makeFileToModuleNamesMap.put(makeFile, moduleNames);
} else {
// Create a aggregate module place holder.
- //moduleNameToMakeFileMap.put(getAggregateName(moduleName), makeFile);
+ //moduleNameToMakeFileMap.put(getAggregateName(moduleDir), makeFile);
}
moduleNames.add(moduleName);
}
@@ -92,31 +92,7 @@
public String getMakeFile(String moduleName) {
Preconditions.checkState(moduleNameToMakeFileMap != null,
"Index not built. Call build() first.");
+
return moduleNameToMakeFileMap.get(moduleName);
}
-
- public Set<String> getAggregatedModules(String moduleName) {
- Preconditions.checkState(makeFileToModuleNamesMap != null,
- "Index not built. Call build() first.");
- String makeFile = getMakeFile(moduleName);
- return makeFileToModuleNamesMap.get(makeFile);
- }
-
- public boolean isPartOfAggregatedModule(String moduleName) {
- String makeFile = getMakeFile(moduleName);
- if (makeFile == null) {
- return false;
- }
- Set<String> moduleNames = makeFileToModuleNamesMap.get(makeFile);
- if (moduleNames == null) {
- return false;
- }
- return moduleNames.size() > 1;
- }
-
- public String getAggregateName(String moduleName) {
- String fileName = getMakeFile(moduleName);
- File file = new File(fileName);
- return file.getParentFile().getName() + "-aggregate";
- }
}
diff --git a/tools/idegen/src/com/android/idegen/StandardModule.java b/tools/idegen/src/com/android/idegen/StandardModule.java
deleted file mode 100644
index f7b24b0..0000000
--- a/tools/idegen/src/com/android/idegen/StandardModule.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2012 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.idegen;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Module constructed from a make file.
- *
- * TODO: read the make file and understand included source dirs in addition to searching
- * sub-directories. Make files can include sources that are not sub-directories. For example,
- * the framework module includes sources from:
- *
- * external/libphonenumber/java/src
- *
- * to provide:
- *
- * com.android.i18n.phonenumbers.PhoneNumberUtil;
- */
-public class StandardModule extends Module {
-
- static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
-
- private static final Logger logger = Logger.getLogger(StandardModule.class.getName());
-
- private static final Pattern SRC_PATTERN = Pattern.compile(
- ".*\\(call all-java-files-under, (.*)\\)");
- private static final String[] AUTO_DEPENDENCIES = new String[]{
- IntellijProject.FRAMEWORK_MODULE, "libcore"
- };
- private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{
- "packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
- };
-
- String moduleName;
- File makeFile;
- File moduleRoot;
- File repoRoot;
-
- Set<String> directDependencies = Sets.newHashSet();
-
- File intermediatesDir;
- MakeFileParser makeFileParser;
- boolean searchForSrc;
-
- public StandardModule(String moduleName, String makeFile) {
- this(moduleName, new File(makeFile), false);
- }
-
- public StandardModule(String moduleName, String makeFile, boolean searchForSrc) {
- this(Preconditions.checkNotNull(moduleName), new File(Preconditions.checkNotNull(makeFile)),
- searchForSrc);
- }
-
- public StandardModule(String moduleName, File makeFile, boolean searchForSrc) {
- this.moduleName = moduleName;
- this.makeFile = makeFile;
- this.moduleRoot = makeFile.getParentFile();
- this.repoRoot = DirectorySearch.findRepoRoot(makeFile);
- this.intermediatesDir = new File(repoRoot.getAbsolutePath() + File.separator +
- REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
- File.separator + "src");
- this.searchForSrc = searchForSrc;
-
- // TODO: auto-detect when framework dependency is needed instead of using coded list.
- for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
- // length + 2 to account for slash
- boolean isDir = makeFile.getAbsolutePath().startsWith(repoRoot + "/" + dir);
- if (isDir) {
- for (String dependency : AUTO_DEPENDENCIES) {
- this.directDependencies.add(dependency);
- }
- }
- }
-
- makeFileParser = new MakeFileParser(makeFile, moduleName);
- }
-
- protected void build() throws IOException {
- makeFileParser.parse();
- buildDependencyList();
- buildDependentModules();
- //buildImlFile();
- logger.info("Done building module " + moduleName);
- logger.info(toString());
- }
-
- @Override
- protected File getDir() {
- return moduleRoot;
- }
-
- @Override
- protected String getName() {
- return moduleName;
- }
-
- @Override
- protected List<File> getIntermediatesDirs() {
- return Lists.newArrayList(intermediatesDir);
- }
-
- @Override
- public File getRepoRoot() {
- return this.repoRoot;
- }
-
- public Set<String> getDirectDependencies() {
- return this.directDependencies;
- }
-
- @Override
- protected ImmutableList<File> getSourceDirs() {
- ImmutableList<File> srcDirs;
- if (searchForSrc) {
- srcDirs = DirectorySearch.findSourceDirs(makeFile);
- } else {
- srcDirs = parseSourceFiles(makeFile);
- }
- return srcDirs;
- }
-
- @Override
- protected ImmutableList<File> getExcludeDirs() {
- return DirectorySearch.findExcludeDirs(makeFile);
- }
-
- @Override
- protected boolean isAndroidModule() {
- File manifest = new File(moduleRoot, "AndroidManifest.xml");
- return manifest.exists();
- }
-
- private ImmutableList<File> parseSourceFiles(File root) {
- ImmutableList.Builder<File> builder = ImmutableList.builder();
- File rootDir;
- if (root.isFile()) {
- rootDir = root.getParentFile();
- } else {
- rootDir = root;
- }
-
- Iterable<String> values = makeFileParser.getValues(Key.LOCAL_SRC_FILES.name());
- if (values != null) {
- for (String value : values) {
- Matcher matcher = SRC_PATTERN.matcher(value);
- if (matcher.matches()) {
- String dir = matcher.group(1);
- builder.add(new File(rootDir, dir));
- } else if (value.contains("/")) {
- // Treat as individual file.
- builder.add(new File(rootDir, value));
- }
- }
- }
- return builder.build();
- }
-
- private void buildDependencyList() {
- parseDirectDependencies(Key.LOCAL_STATIC_JAVA_LIBRARIES);
- parseDirectDependencies(Key.LOCAL_JAVA_LIBRARIES);
- }
-
- private void parseDirectDependencies(Key key) {
- Iterable<String> names = makeFileParser.getValues(key.name());
- if (names != null) {
- for (String dependency : names) {
- directDependencies.add(dependency);
- }
- }
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(getName());
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- StandardModule other = (StandardModule) obj;
- return Objects.equal(getName(), other.getName());
- }
-
- @Override
- public String toString() {
- return Objects.toStringHelper(this)
- .add("super", super.toString())
- .add("makeFileParser", makeFileParser)
- .add("directDependencies", Iterables.toString(directDependencies))
- .toString();
- }
-}
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-az-rAZ/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-az-rAZ/strings.xml
index 5f48a2d..3435573 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-az-rAZ/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"Sistem güncəlləməsi quraşdırılır..."</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"Silinir..."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"Əmr yoxdur."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"Xəta!"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-az/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-az/strings.xml
index 5f48a2d..3435573 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-az/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"Sistem güncəlləməsi quraşdırılır..."</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"Silinir..."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"Əmr yoxdur."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"Xəta!"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-en-rIN/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-en-rIN/strings.xml
index 5f48a2d..b70d678c 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-en-rIN/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"Installing system update…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"Erasing…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"No command."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"Error!"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-et/strings.xml b/tools/recovery_l10n/res/values-et-rEE/strings.xml
similarity index 100%
rename from tools/recovery_l10n/res/values-et/strings.xml
rename to tools/recovery_l10n/res/values-et-rEE/strings.xml
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-fr-rCA/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-fr-rCA/strings.xml
index 5f48a2d..f2a85d8 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-fr-rCA/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"Installation de la mise à jour du système en cours…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"Effacement en cours…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"Aucune commande."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"Erreur!"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-hi/strings.xml b/tools/recovery_l10n/res/values-hi/strings.xml
index 3dfab3e..a470d12 100644
--- a/tools/recovery_l10n/res/values-hi/strings.xml
+++ b/tools/recovery_l10n/res/values-hi/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"सिस्टम अपडेट इंस्टॉल कर रहा है…"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"सिस्टम के बारे में नई जानकारी मिल रही है…"</string>
<string name="recovery_erasing" msgid="4612809744968710197">"मिटा रहा है…"</string>
<string name="recovery_no_command" msgid="1915703879031023455">"कोई आदेश नहीं."</string>
<string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-hy-rAM/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-hy-rAM/strings.xml
index 5f48a2d..7babe80 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-hy-rAM/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"Համակարգի թարմացման տեղադրում…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"Ջնջում…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"Հրամանը տրված չէ:"</string>
+ <string name="recovery_error" msgid="4550265746256727080">"Սխալ"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-ka-rGE/strings.xml b/tools/recovery_l10n/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..2d27c17
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ka-rGE/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"სისტემის განახლების დაყენება…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"მიმდინარეობს წაშლა…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"ბრძანება არ არის."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"შეცდომა!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-km-rKH/strings.xml b/tools/recovery_l10n/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..0c1c272
--- /dev/null
+++ b/tools/recovery_l10n/res/values-km-rKH/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"កំពុងដំឡើងបច្ចុប្បន្នភាពប្រព័ន្ធ…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"កំពុងលុប…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"គ្មានពាក្យបញ្ជា។"</string>
+ <string name="recovery_error" msgid="4550265746256727080">"កំហុស!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-lo-rLA/strings.xml b/tools/recovery_l10n/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..5880cca
--- /dev/null
+++ b/tools/recovery_l10n/res/values-lo-rLA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"ກຳລັງຕິດຕັ້ງການອັບເດດລະບົບ..."</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"ກຳລັງລຶບ..."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"ບໍ່ມີຄຳສັ່ງ."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"ຜິດພາດ!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-mn-rMN/strings.xml
similarity index 69%
rename from tools/recovery_l10n/res/values-be/strings.xml
rename to tools/recovery_l10n/res/values-mn-rMN/strings.xml
index 5f48a2d..463cafe 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-mn-rMN/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"Системийн шинэчлэлтийг суулгаж байна…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"Арилгаж байна…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"Команд байхгүй."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"Алдаа!"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-ms/strings.xml b/tools/recovery_l10n/res/values-ms-rMY/strings.xml
similarity index 100%
rename from tools/recovery_l10n/res/values-ms/strings.xml
rename to tools/recovery_l10n/res/values-ms-rMY/strings.xml
diff --git a/tools/recovery_l10n/res/values-ne-rNP/strings.xml b/tools/recovery_l10n/res/values-ne-rNP/strings.xml
new file mode 100644
index 0000000..835f275
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ne-rNP/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"प्रणाली अद्यावधिक स्थापना गर्दै..."</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"मेटाइदै..."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"कुनै आदेश छैन।"</string>
+ <string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-ne/strings.xml b/tools/recovery_l10n/res/values-ne/strings.xml
new file mode 100644
index 0000000..835f275
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ne/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"प्रणाली अद्यावधिक स्थापना गर्दै..."</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"मेटाइदै..."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"कुनै आदेश छैन।"</string>
+ <string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-si-rLK/strings.xml b/tools/recovery_l10n/res/values-si-rLK/strings.xml
new file mode 100644
index 0000000..e717a97
--- /dev/null
+++ b/tools/recovery_l10n/res/values-si-rLK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"පද්ධති යාවත්කාල ස්ථාපනය කරමින්…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"මකමින්...."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"විධානයක් නොමැත."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"දෝෂය!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-si/strings.xml b/tools/recovery_l10n/res/values-si/strings.xml
new file mode 100644
index 0000000..e717a97
--- /dev/null
+++ b/tools/recovery_l10n/res/values-si/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="recovery_installing" msgid="7864047928003865598">"පද්ධති යාවත්කාල ස්ථාපනය කරමින්…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"මකමින්...."</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"විධානයක් නොමැත."</string>
+ <string name="recovery_error" msgid="4550265746256727080">"දෝෂය!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
similarity index 61%
copy from tools/recovery_l10n/res/values-be/strings.xml
copy to tools/recovery_l10n/res/values-zh-rHK/strings.xml
index 5f48a2d..f615c7a 100644
--- a/tools/recovery_l10n/res/values-be/strings.xml
+++ b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="7864047928003865598">"Усталёўка абнаўлення сістэмы..."</string>
- <string name="recovery_erasing" msgid="4612809744968710197">"Выдаленне..."</string>
- <string name="recovery_no_command" msgid="1915703879031023455">"Няма каманды"</string>
- <string name="recovery_error" msgid="4550265746256727080">"Памылка"</string>
+ <string name="recovery_installing" msgid="7864047928003865598">"正在安裝系統更新…"</string>
+ <string name="recovery_erasing" msgid="4612809744968710197">"正在清除…"</string>
+ <string name="recovery_no_command" msgid="1915703879031023455">"沒有指令。"</string>
+ <string name="recovery_error" msgid="4550265746256727080">"錯誤!"</string>
</resources>
diff --git a/tools/rmtypedefs/.gitignore b/tools/rmtypedefs/.gitignore
new file mode 100644
index 0000000..04d423f
--- /dev/null
+++ b/tools/rmtypedefs/.gitignore
@@ -0,0 +1,3 @@
+out
+.idea/workspace.xml
+.DS_Store
diff --git a/tools/rmtypedefs/.idea/compiler.xml b/tools/rmtypedefs/.idea/compiler.xml
new file mode 100644
index 0000000..217af47
--- /dev/null
+++ b/tools/rmtypedefs/.idea/compiler.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <option name="DEFAULT_COMPILER" value="Javac" />
+ <resourceExtensions />
+ <wildcardResourcePatterns>
+ <entry name="!?*.java" />
+ <entry name="!?*.form" />
+ <entry name="!?*.class" />
+ <entry name="!?*.groovy" />
+ <entry name="!?*.scala" />
+ <entry name="!?*.flex" />
+ <entry name="!?*.kt" />
+ <entry name="!?*.clj" />
+ </wildcardResourcePatterns>
+ <annotationProcessing>
+ <profile default="true" name="Default" enabled="false">
+ <processorPath useClasspath="true" />
+ </profile>
+ </annotationProcessing>
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/copyright/profiles_settings.xml b/tools/rmtypedefs/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..3572571
--- /dev/null
+++ b/tools/rmtypedefs/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,5 @@
+<component name="CopyrightManager">
+ <settings default="">
+ <module2copyright />
+ </settings>
+</component>
\ No newline at end of file
diff --git a/tools/rmtypedefs/.idea/encodings.xml b/tools/rmtypedefs/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/tools/rmtypedefs/.idea/encodings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+</project>
+
diff --git a/tools/rmtypedefs/.idea/misc.xml b/tools/rmtypedefs/.idea/misc.xml
new file mode 100644
index 0000000..9732041
--- /dev/null
+++ b/tools/rmtypedefs/.idea/misc.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="EntryPointsManager">
+ <entry_points version="2.0" />
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/modules.xml b/tools/rmtypedefs/.idea/modules.xml
new file mode 100644
index 0000000..52f04c3
--- /dev/null
+++ b/tools/rmtypedefs/.idea/modules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/rmtypedefs.iml" filepath="$PROJECT_DIR$/rmtypedefs.iml" />
+ </modules>
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/scopes/scope_settings.xml b/tools/rmtypedefs/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/tools/rmtypedefs/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+<component name="DependencyValidationManager">
+ <state>
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+ </state>
+</component>
\ No newline at end of file
diff --git a/tools/rmtypedefs/.idea/uiDesigner.xml b/tools/rmtypedefs/.idea/uiDesigner.xml
new file mode 100644
index 0000000..3b00020
--- /dev/null
+++ b/tools/rmtypedefs/.idea/uiDesigner.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/vcs.xml b/tools/rmtypedefs/.idea/vcs.xml
new file mode 100644
index 0000000..a5dd086
--- /dev/null
+++ b/tools/rmtypedefs/.idea/vcs.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsDirectoryMappings">
+ <mapping directory="" vcs="" />
+ <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/Android.mk b/tools/rmtypedefs/Android.mk
new file mode 100644
index 0000000..d79d2ff
--- /dev/null
+++ b/tools/rmtypedefs/Android.mk
@@ -0,0 +1,46 @@
+# Copyright (C) 2013 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)
+
+# We use copy-file-to-new-target so that the installed
+# script file's timestamp is at least as new as the
+# .jar file it wraps.
+
+# the execution script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := rmtypedefs
+
+#LOCAL_STATIC_JAVA_LIBRARIES := \
+# asm-tools \
+# guavalib
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/rmtypedefs$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/rmtypedefs | $(ACP)
+ @echo "Copy: $(PRIVATE_MODULE) ($@)"
+ $(copy-file-to-new-target)
+ $(hide) chmod 755 $@
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+ src \
+ ))
+
+include $(subdirs)
diff --git a/tools/rmtypedefs/README.txt b/tools/rmtypedefs/README.txt
new file mode 100644
index 0000000..9f3fb8b
--- /dev/null
+++ b/tools/rmtypedefs/README.txt
@@ -0,0 +1,13 @@
+Android TypeDef Remover 1.0
+
+This utility finds and removes all .class files that have been
+annotated with the @IntDef annotation (android.annotations.IntDef) or
+the @StringDef annotation (android.annotations.StringDef).
+
+It also makes sure that these annotations have source level retention
+(@Retention(RetentionPolicy.SOURCE)), since otherwise uses of the
+typedef will appear in .class files as well.
+
+This is intended to be used during the build to strip out any typedef
+annotation classes, since these are not needed (or desirable) in the
+system image.
diff --git a/tools/rmtypedefs/etc/manifest.txt b/tools/rmtypedefs/etc/manifest.txt
new file mode 100644
index 0000000..39f2e29
--- /dev/null
+++ b/tools/rmtypedefs/etc/manifest.txt
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.tools.rmtypedefs.RmTypeDefs
diff --git a/tools/rmtypedefs/etc/rmtypedefs b/tools/rmtypedefs/etc/rmtypedefs
new file mode 100755
index 0000000..bc0cbe2
--- /dev/null
+++ b/tools/rmtypedefs/etc/rmtypedefs
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+ newProg=`/bin/ls -ld "${prog}"`
+ newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+ if expr "x${newProg}" : 'x/' >/dev/null; then
+ prog="${newProg}"
+ else
+ progdir=`dirname "${prog}"`
+ prog="${progdir}/${newProg}"
+ fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+libdir=`dirname $progdir`/framework
+
+javaOpts=""
+while expr "x$1" : 'x-J' >/dev/null; do
+ opt=`expr "$1" : '-J\(.*\)'`
+ javaOpts="${javaOpts} -${opt}"
+ shift
+done
+
+exec java $javaOpts -jar $libdir/rmtypedefs.jar "$@"
diff --git a/tools/rmtypedefs/rmtypedefs.iml b/tools/rmtypedefs/rmtypedefs.iml
new file mode 100644
index 0000000..6e0f0fc
--- /dev/null
+++ b/tools/rmtypedefs/rmtypedefs.iml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/../../../out/rmtypedefs" />
+ <output-test url="file://$MODULE_DIR$/../../../out/rmtypedefs" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/asm-tools/asm-4.0.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/asm-tools/src-4.0.zip!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/guava-tools/guava-13.0.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/guava-tools/src.zip!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ </component>
+</module>
+
diff --git a/tools/rmtypedefs/src/Android.mk b/tools/rmtypedefs/src/Android.mk
new file mode 100644
index 0000000..067a2e6
--- /dev/null
+++ b/tools/rmtypedefs/src/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2013 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)
+
+
+# rmtypedefs java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ asm-tools \
+ guava-tools
+
+LOCAL_MODULE:= rmtypedefs
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java b/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java
new file mode 100644
index 0000000..9375590
--- /dev/null
+++ b/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 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.tools.rmtypedefs;
+
+import com.google.common.io.Files;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.ASM4;
+
+/**
+ * Finds and deletes typedef annotation classes (and also warns if their
+ * retention was wrong, such that uses embeds
+ */
+public class RmTypeDefs {
+
+ private static final String ANNOTATION = "java/lang/annotation/Annotation";
+ private static final String STRING_DEF = "android/annotation/StringDef";
+ private static final String INT_DEF = "android/annotation/IntDef";
+ private static final String INT_DEF_DESC = "L" + INT_DEF + ";";
+ private static final String STRING_DEF_DESC = "L" + STRING_DEF + ";";
+ private static final String RETENTION_DESC = "Ljava/lang/annotation/Retention;";
+ private static final String RETENTION_POLICY_DESC = "Ljava/lang/annotation/RetentionPolicy;";
+ private static final String SOURCE_RETENTION_VALUE = "SOURCE";
+
+ private boolean mQuiet;
+ private boolean mVerbose;
+ private boolean mHaveError;
+ private boolean mDryRun;
+
+ public static void main(String[] args) {
+ new RmTypeDefs().run(args);
+ }
+
+ private void run(String[] args) {
+ if (args.length == 0) {
+ usage(System.err);
+ System.exit(1);
+ }
+
+ List<File> dirs = new ArrayList<File>();
+ for (String arg : args) {
+ if (arg.equals("--help") || arg.equals("-h")) {
+ usage(System.out);
+ return;
+ } else if (arg.equals("-q") || arg.equals("--quiet") || arg.equals("--silent")) {
+ mQuiet = true;
+ } else if (arg.equals("-v") || arg.equals("--verbose")) {
+ mVerbose = true;
+ } else if (arg.equals("-n") || arg.equals("--dry-run")) {
+ mDryRun = true;
+ } else if (arg.startsWith("-")) {
+ System.err.println("Unknown argument " + arg);
+ usage(System.err);
+ System.exit(1);
+
+ } else {
+ // Other arguments should be file names
+ File file = new File(arg);
+ if (file.exists()) {
+ dirs.add(file);
+ } else {
+ System.err.println(file + " does not exist");
+ usage(System.err);
+ System.exit(1);
+ }
+ }
+ }
+
+ if (!mQuiet) {
+ System.out.println("Deleting @IntDef and @StringDef annotation class files");
+ }
+
+ for (File dir : dirs) {
+ find(dir);
+ }
+
+ System.exit(mHaveError ? -1 : 0);
+ }
+
+ private void find(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ find(f);
+ }
+ }
+ } else if (file.isFile()) {
+ String path = file.getPath();
+ if (path.endsWith(".class")) {
+ checkClass(file);
+ } else if (path.endsWith(".jar")) {
+ System.err.println(path + ": Warning: Encountered .jar file; .class files "
+ + "are not scanned and removed inside .jar files");
+ }
+ }
+ }
+
+ private void checkClass(File file) {
+ try {
+ byte[] bytes = Files.toByteArray(file);
+ ClassReader classReader = new ClassReader(bytes);
+ classReader.accept(new MyVisitor(file), 0);
+ } catch (IOException e) {
+ System.err.println("Could not read " + file + ": " + e.getLocalizedMessage());
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Prints usage statement.
+ */
+ static void usage(PrintStream out) {
+ out.println("Android TypeDef Remover 1.0");
+ out.println("Copyright (C) 2013 The Android Open Source Project\n");
+ out.println("Usage: rmtypedefs folder1 [folder2 [folder3...]]\n");
+ out.println("Options:");
+ out.println(" -h,--help show this message");
+ out.println(" -q,--quiet quiet");
+ out.println(" -v,--verbose verbose");
+ out.println(" -n,--dry-run dry-run only, leaves files alone");
+ }
+
+ private class MyVisitor extends ClassVisitor {
+
+ /** Class file name */
+ private File mFile;
+
+ /** Class name */
+ private String mName;
+
+ /** Is this class an annotation? */
+ private boolean mAnnotation;
+
+ /** Is this annotation a typedef? Only applies if {@link #mAnnotation} */
+ private boolean mTypedef;
+
+ /** Does the annotation have source retention? Only applies if {@link #mAnnotation} */
+ private boolean mSourceRetention;
+
+ public MyVisitor(File file) {
+ super(ASM4);
+ mFile = file;
+ }
+
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ mName = name;
+ mAnnotation = interfaces != null && interfaces.length >= 1
+ && ANNOTATION.equals(interfaces[0]);
+
+ // Special case: Also delete the actual @IntDef and @StringDef .class files.
+ // These have class file retention
+ mTypedef = name.equals(INT_DEF) || name.equals(STRING_DEF);
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ mTypedef = desc.equals(INT_DEF_DESC) || desc.equals(STRING_DEF_DESC);
+ if (desc.equals(RETENTION_DESC)) {
+ return new AnnotationVisitor(ASM4) {
+ public void visitEnum(String name, String desc, String value) {
+ if (desc.equals(RETENTION_POLICY_DESC)) {
+ mSourceRetention = SOURCE_RETENTION_VALUE.equals(value);
+ }
+ }
+ };
+ }
+ return null;
+ }
+
+ public void visitEnd() {
+ if (mAnnotation && mTypedef) {
+ if (!mSourceRetention && !mName.equals(STRING_DEF) && !mName.equals(INT_DEF)) {
+ System.err.println(mFile + ": Warning: Annotation should be annotated "
+ + "with @Retention(RetentionPolicy.SOURCE)");
+ mHaveError = true;
+ }
+ if (mVerbose) {
+ if (mDryRun) {
+ System.out.println("Would delete " + mFile);
+ } else {
+ System.out.println("Deleting " + mFile);
+ }
+ }
+ if (!mDryRun) {
+ boolean deleted = mFile.delete();
+ if (!deleted) {
+ System.err.println("Could not delete " + mFile);
+ mHaveError = true;
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/tutorials/MoarRam/README.txt b/tutorials/MoarRam/README.txt
index 028389b..8f1a487 100644
--- a/tutorials/MoarRam/README.txt
+++ b/tutorials/MoarRam/README.txt
@@ -12,3 +12,6 @@
Each allocation can be freed by clicking the corresponding free button in the
UI.
+
+NOTE 09/16/2013
+A new feature is added to force a double free. Both debug libc and Valgrind can capture it.
diff --git a/tutorials/MoarRam/jni/Android.mk b/tutorials/MoarRam/jni/Android.mk
index 933cbdf..b1eec37 100644
--- a/tutorials/MoarRam/jni/Android.mk
+++ b/tutorials/MoarRam/jni/Android.mk
@@ -41,3 +41,12 @@
LOCAL_SHARED_LIBRARIES += liblog
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libmoarram-doublefree
+LOCAL_SRC_FILES := df.c
+LOCAL_SHARED_LIBRARIES += liblog
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tutorials/MoarRam/jni/df.c b/tutorials/MoarRam/jni/df.c
new file mode 100644
index 0000000..bfea6b8
--- /dev/null
+++ b/tutorials/MoarRam/jni/df.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 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.
+ *
+ */
+
+#include <jni.h>
+#include <cutils/log.h>
+
+#if defined(LOG_TAG)
+#undef LOG_TAG
+#define LOG_TAG "MOARRAM"
+#endif
+
+void
+Java_com_android_benchmark_moarram_MainActivity_forceDoubleFreeNative(
+ JNIEnv* env,
+ jobject this)
+{
+ char *ptr = (char *) malloc(4);
+ *ptr = 0;
+ ALOGW("About to double free %p", ptr);
+ free(ptr);
+ free(ptr);
+}
diff --git a/tutorials/MoarRam/res/layout/activity_main.xml b/tutorials/MoarRam/res/layout/activity_main.xml
index 8319bd7..50b6745 100644
--- a/tutorials/MoarRam/res/layout/activity_main.xml
+++ b/tutorials/MoarRam/res/layout/activity_main.xml
@@ -101,4 +101,19 @@
android:layout_weight="1"
android:onClick="freeVariableSizedBlocks" />
</LinearLayout>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:text="@string/force_double_free"
+ android:layout_weight="1"
+ android:onClick="forceDoubleFree" />
+ </LinearLayout>
+
</LinearLayout>
diff --git a/tutorials/MoarRam/res/values/strings.xml b/tutorials/MoarRam/res/values/strings.xml
index 0c0031d..e289fd8 100644
--- a/tutorials/MoarRam/res/values/strings.xml
+++ b/tutorials/MoarRam/res/values/strings.xml
@@ -13,4 +13,5 @@
<string name="free_variable">Free 17 or 71 bytes</string>
<string name="_17byte">17 bytes</string>
<string name="_71byte">71 bytes</string>
+ <string name="force_double_free">Force a Double Free</string>
</resources>
diff --git a/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java b/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java
index aa83b8c..0b7dcbc 100644
--- a/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java
+++ b/tutorials/MoarRam/src/com/android/benchmark/moarram/MainActivity.java
@@ -14,6 +14,7 @@
System.loadLibrary("moarram-32");
System.loadLibrary("moarram-2M");
System.loadLibrary("moarram-17_71");
+ System.loadLibrary("moarram-doublefree");
setContentView(R.layout.activity_main);
}
@@ -55,10 +56,15 @@
freeVariableSizedBlocksNative(sizeId == R.id.radio17 ? 0 : 1);
}
+ public void forceDoubleFree(View view) {
+ forceDoubleFreeNative();
+ }
+
public native void add32ByteBlocksNative();
public native void free32ByteBlocksNative();
public native void add2MByteBlocksNative();
public native void free2MByteBlocksNative();
public native void addVariableSizedBlocksNative(int sizeId);
public native void freeVariableSizedBlocksNative(int sizeId);
+ public native void forceDoubleFreeNative();
}