summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--samples/ApiDemos/Android.mk2
-rw-r--r--samples/ApiDemos/AndroidManifest.xml36
-rw-r--r--samples/ApiDemos/res/layout/motogp_stat_item.xml59
-rw-r--r--samples/ApiDemos/res/layout/print_bitmap.xml23
-rw-r--r--samples/ApiDemos/res/layout/print_html_from_screen.xml22
-rw-r--r--samples/ApiDemos/res/layout/print_html_off_screen.xml24
-rw-r--r--samples/ApiDemos/res/menu/print_custom_content.xml21
-rw-r--r--samples/ApiDemos/res/raw/android_logo.pngbin0 -> 10722 bytes
-rw-r--r--samples/ApiDemos/res/raw/motogp_stats.html333
-rw-r--r--samples/ApiDemos/res/values/arrays.xml205
-rw-r--r--samples/ApiDemos/res/values/strings.xml13
-rw-r--r--samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java82
-rw-r--r--samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java562
-rw-r--r--samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java93
-rw-r--r--samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.java132
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/README7
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle43
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml138
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java203
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java68
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java69
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java24
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java24
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java24
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java24
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java58
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java46
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 3964 bytes
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 2424 bytes
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 5527 bytes
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 9889 bytes
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml93
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml23
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml26
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml19
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml19
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml20
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml19
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml28
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml35
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/build.gradle1
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/local.properties.sample7
-rw-r--r--samples/devbytes/telephony/SmsSampleProject/settings.gradle1
-rw-r--r--samples/devbytes/ui/ImmersiveMode/build.gradle39
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml50
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java117
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java49
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11345 bytes
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.pngbin0 -> 3624 bytes
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml50
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml23
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml31
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml20
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml22
-rw-r--r--samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml36
-rw-r--r--scripts/app_engine_server/redirects.yaml4
56 files changed, 3067 insertions, 0 deletions
diff --git a/samples/ApiDemos/Android.mk b/samples/ApiDemos/Android.mk
index 066c497cb..ca48f581d 100644
--- a/samples/ApiDemos/Android.mk
+++ b/samples/ApiDemos/Android.mk
@@ -12,6 +12,8 @@ LOCAL_SRC_FILES += \
LOCAL_JAVA_LIBRARIES := telephony-common mms-common
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
+
LOCAL_PACKAGE_NAME := ApiDemos
LOCAL_SDK_VERSION := current
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index 3d1d2c1c2..d7bda3125 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -996,6 +996,42 @@
</intent-filter>
</activity>
+ <activity android:name=".app.PrintBitmap"
+ android:label="@string/print_bitmap"
+ android:enabled="@bool/atLeastKitKat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".app.PrintHtmlFromScreen"
+ android:label="@string/print_html_from_screen"
+ android:enabled="@bool/atLeastKitKat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".app.PrintHtmlOffScreen"
+ android:label="@string/print_html_off_screen"
+ android:enabled="@bool/atLeastKitKat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".app.PrintCustomContent"
+ android:label="@string/print_custom_content"
+ android:enabled="@bool/atLeastKitKat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
<!-- Application Updating Samples -->
<!-- BEGIN_INCLUDE(app_update_declaration) -->
diff --git a/samples/ApiDemos/res/layout/motogp_stat_item.xml b/samples/ApiDemos/res/layout/motogp_stat_item.xml
new file mode 100644
index 000000000..e09fd6786
--- /dev/null
+++ b/samples/ApiDemos/res/layout/motogp_stat_item.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:minHeight="64dip"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/year"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:gravity="start"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textIsSelectable="false">
+ </TextView>
+
+ <TextView
+ android:id="@+id/champion"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textIsSelectable="false"
+ android:duplicateParentState="true">
+ </TextView>
+
+ <TextView
+ android:id="@+id/constructor"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:gravity="end"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textIsSelectable="false">
+ </TextView>
+
+</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/print_bitmap.xml b/samples/ApiDemos/res/layout/print_bitmap.xml
new file mode 100644
index 000000000..cce522acb
--- /dev/null
+++ b/samples/ApiDemos/res/layout/print_bitmap.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/image"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:src="@raw/android_logo"
+ android:contentDescription="@string/android_logo">
+</ImageView>
diff --git a/samples/ApiDemos/res/layout/print_html_from_screen.xml b/samples/ApiDemos/res/layout/print_html_from_screen.xml
new file mode 100644
index 000000000..535bcb2d1
--- /dev/null
+++ b/samples/ApiDemos/res/layout/print_html_from_screen.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<WebView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/web_view"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dip">
+</WebView>
diff --git a/samples/ApiDemos/res/layout/print_html_off_screen.xml b/samples/ApiDemos/res/layout/print_html_off_screen.xml
new file mode 100644
index 000000000..799b07927
--- /dev/null
+++ b/samples/ApiDemos/res/layout/print_html_off_screen.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textIsSelectable="false"
+ android:text="@string/print_html_off_screen_msg">
+</TextView>
diff --git a/samples/ApiDemos/res/menu/print_custom_content.xml b/samples/ApiDemos/res/menu/print_custom_content.xml
new file mode 100644
index 000000000..ace8039e8
--- /dev/null
+++ b/samples/ApiDemos/res/menu/print_custom_content.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 Google Inc.
+
+ 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_print"
+ android:title="@string/print"
+ android:showAsAction="never" />
+</menu>
diff --git a/samples/ApiDemos/res/raw/android_logo.png b/samples/ApiDemos/res/raw/android_logo.png
new file mode 100644
index 000000000..f970c262e
--- /dev/null
+++ b/samples/ApiDemos/res/raw/android_logo.png
Binary files differ
diff --git a/samples/ApiDemos/res/raw/motogp_stats.html b/samples/ApiDemos/res/raw/motogp_stats.html
new file mode 100644
index 000000000..b55ed9eb3
--- /dev/null
+++ b/samples/ApiDemos/res/raw/motogp_stats.html
@@ -0,0 +1,333 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table>
+<caption>500cc/MotoGP champions</caption>
+<thead><tr>
+<th scope="col">Season</td>
+<th scope="col">Rider</td>
+<th scope="col">Constructor</td>
+</tr></thead><tbody>
+<tr>
+<td>2012</td>
+<td>Jorge Lorenzo</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2011</td>
+<td>Casey Stoner</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2010</td>
+<td>Jorge Lorenzo</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2009</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2008</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2007</td>
+<td>Casey Stoner</td>
+<td>Ducati</td>
+</tr>
+<tr>
+<td>2006</td>
+<td>Nicky Hayden</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2005</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2004</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2003</td>
+<td>Valentino Rossi</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2002</td>
+<td>Valentino Rossi</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2001</td>
+<td>Valentino Rossi</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2000</td>
+<td>Kenny Roberts, Jr.</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1999</td>
+<td>Ëlex CrivillŽ</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1998</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1997</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1996</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1995</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1994</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1993</td>
+<td>Kevin Schwantz</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1992</td>
+<td>Wayne Rainey</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1991</td>
+<td>Wayne Rainey</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1990</td>
+<td>Wayne Rainey</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1989</td>
+<td>Eddie Lawson</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1988</td>
+<td>Eddie Lawson</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1987</td>
+<td>Wayne Gardner</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1986</td>
+<td>Eddie Lawson</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1985</td>
+<td>Freddie Spencer</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1984</td>
+<td>Eddie Lawson</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1983</td>
+<td>Freddie Spencer</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1982</td>
+<td>Franco Uncini</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1981</td>
+<td>Marco Lucchinelli</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1980</td>
+<td>Kenny Roberts</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1979</td>
+<td>Kenny Roberts</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1978</td>
+<td>Kenny Roberts</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1977</td>
+<td>Barry Sheene</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1976</td>
+<td>Barry Sheene</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1975</td>
+<td>Giacomo Agostini</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1974</td>
+<td>Phil Read</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1973</td>
+<td>Phil Read</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1972</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1971</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1970</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1969</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1968</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1967</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1966</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1965</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1964</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1963</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1962</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1961</td>
+<td>Gary Hocking</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1960</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1959</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1958</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1957</td>
+<td>Libero Liberati</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1956</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1955</td>
+<td>Geoff Duke</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1954</td>
+<td>Geoff Duke</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1953</td>
+<td>Geoff Duke</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1952</td>
+<td>Umberto Masetti</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1951</td>
+<td>Geoff Duke</td>
+<td>Norton</td>
+</tr>
+<tr>
+<td>1950</td>
+<td>Umberto Masetti</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1949</td>
+<td>Leslie Graham</td>
+<td>AJS</td>
+</tr>
+</tbody><tfoot></tfoot></table>
+</body>
+</html> \ No newline at end of file
diff --git a/samples/ApiDemos/res/values/arrays.xml b/samples/ApiDemos/res/values/arrays.xml
index b06220975..8f987ae43 100644
--- a/samples/ApiDemos/res/values/arrays.xml
+++ b/samples/ApiDemos/res/values/arrays.xml
@@ -154,4 +154,209 @@
<item>No.</item>
<item>Mmm... cheese.</item>
</string-array>
+
+ <!-- Used in app/Print/Custom Layout example -->
+ <string-array name="motogp_years">
+ <item>2012</item>
+ <item>2011</item>
+ <item>2010</item>
+ <item>2009</item>
+ <item>2008</item>
+ <item>2007</item>
+ <item>2006</item>
+ <item>2005</item>
+ <item>2004</item>
+ <item>2003</item>
+ <item>2002</item>
+ <item>2001</item>
+ <item>2000</item>
+ <item>1999</item>
+ <item>1998</item>
+ <item>1997</item>
+ <item>1996</item>
+ <item>1995</item>
+ <item>1994</item>
+ <item>1993</item>
+ <item>1992</item>
+ <item>1991</item>
+ <item>1990</item>
+ <item>1989</item>
+ <item>1988</item>
+ <item>1987</item>
+ <item>1986</item>
+ <item>1985</item>
+ <item>1984</item>
+ <item>1983</item>
+ <item>1982</item>
+ <item>1981</item>
+ <item>1980</item>
+ <item>1979</item>
+ <item>1978</item>
+ <item>1977</item>
+ <item>1976</item>
+ <item>1975</item>
+ <item>1974</item>
+ <item>1973</item>
+ <item>1972</item>
+ <item>1971</item>
+ <item>1970</item>
+ <item>1969</item>
+ <item>1968</item>
+ <item>1967</item>
+ <item>1966</item>
+ <item>1965</item>
+ <item>1964</item>
+ <item>1963</item>
+ <item>1962</item>
+ <item>1961</item>
+ <item>1960</item>
+ <item>1959</item>
+ <item>1958</item>
+ <item>1957</item>
+ <item>1956</item>
+ <item>1955</item>
+ <item>1954</item>
+ <item>1953</item>
+ <item>1952</item>
+ <item>1951</item>
+ <item>1950</item>
+ <item>1949</item>
+ </string-array>
+
+ <!-- Used in app/Print/Custom Layout example -->
+ <string-array name="motogp_champions">
+ <item>Jorge Lorenzo</item>
+ <item>Casey Stoner</item>
+ <item>Jorge Lorenzo</item>
+ <item>Valentino Rossi</item>
+ <item>Valentino Rossi</item>
+ <item>Casey Stoner</item>
+ <item>Nicky Hayden</item>
+ <item>Valentino Rossi</item>
+ <item>Valentino Rossi</item>
+ <item>Valentino Rossi</item>
+ <item>Valentino Rossi</item>
+ <item>Valentino Rossi</item>
+ <item>Kenny Roberts, Jr.</item>
+ <item>Àlex Crivillé</item>
+ <item>Michael Doohan</item>
+ <item>Michael Doohan</item>
+ <item>Michael Doohan</item>
+ <item>Michael Doohan</item>
+ <item>Michael Doohan</item>
+ <item>Kevin Schwantz</item>
+ <item>Wayne Rainey</item>
+ <item>Wayne Rainey</item>
+ <item>Wayne Rainey</item>
+ <item>Eddie Lawson</item>
+ <item>Eddie Lawson</item>
+ <item>Wayne Gardner</item>
+ <item>Eddie Lawson</item>
+ <item>Freddie Spencer</item>
+ <item>Eddie Lawson</item>
+ <item>Freddie Spencer</item>
+ <item>Franco Uncini</item>
+ <item>Marco Lucchinelli</item>
+ <item>Kenny Roberts</item>
+ <item>Kenny Roberts</item>
+ <item>Kenny Roberts</item>
+ <item>Barry Sheene</item>
+ <item>Barry Sheene</item>
+ <item>Giacomo Agostini</item>
+ <item>Phil Read</item>
+ <item>Phil Read</item>
+ <item>Giacomo Agostini</item>
+ <item>Giacomo Agostini</item>
+ <item>Giacomo Agostini</item>
+ <item>Giacomo Agostini</item>
+ <item>Giacomo Agostini</item>
+ <item>Giacomo Agostini</item>
+ <item>Giacomo Agostini</item>
+ <item>Mike Hailwood</item>
+ <item>Mike Hailwood</item>
+ <item>Mike Hailwood</item>
+ <item>Mike Hailwood</item>
+ <item>Gary Hocking</item>
+ <item>John Surtees</item>
+ <item>John Surtees</item>
+ <item>John Surtees</item>
+ <item>Libero Liberati</item>
+ <item>John Surtees</item>
+ <item>Geoff Duke</item>
+ <item>Geoff Duke</item>
+ <item>Geoff Duke</item>
+ <item>Umberto Masetti</item>
+ <item>Geoff Duke</item>
+ <item>Umberto Masetti</item>
+ <item>Leslie Graham</item>
+ </string-array>
+
+ <!-- Used in app/Print/Custom Layout example -->
+ <string-array name="motogp_constructors">
+ <item>Yamaha</item>
+ <item>Honda</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Ducati</item>
+ <item>Honda</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Suzuki</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Honda</item>
+ <item>Suzuki</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Honda</item>
+ <item>Yamaha</item>
+ <item>Honda</item>
+ <item>Yamaha</item>
+ <item>Honda</item>
+ <item>Yamaha</item>
+ <item>Honda</item>
+ <item>Suzuki</item>
+ <item>Suzuki</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Yamaha</item>
+ <item>Suzuki</item>
+ <item>Suzuki</item>
+ <item>Giacomo Agostini</item>
+ <item>Phil Read</item>
+ <item>Phil Read</item>
+ <item>Yamaha</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>MV Agusta</item>
+ <item>Gilera</item>
+ <item>MV Agusta</item>
+ <item>Gilera</item>
+ <item>Gilera</item>
+ <item>Gilera</item>
+ <item>Gilera</item>
+ <item>Norton</item>
+ <item>Gilera</item>
+ <item>AJS</item>
+ </string-array>
+
</resources>
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 47445dde8..804087dd5 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -871,6 +871,19 @@
<string name="btn_toggle_tabs">Toggle tab mode</string>
<string name="btn_remove_all_tabs">Remove all tabs</string>
+ <!-- ================================= -->
+ <!-- app/print print examples strings -->
+ <!-- ================================= -->
+
+ <string name="print_bitmap">App/Print/Print Bitmap</string>
+ <string name="print_html_from_screen">App/Print/Print HTML from screen</string>
+ <string name="print_html_off_screen">App/Print/Print HTML off screen</string>
+ <string name="print_custom_content">App/Print/Print Custom Layout</string>
+ <string name="print">Print</string>
+ <string name="print_html_off_screen_msg">From the overflow menu you can print some
+ off screen content.</string>
+ <string name="android_logo">Android logo</string>
+
<!-- ============================ -->
<!-- graphics examples strings -->
<!-- ============================ -->
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java
new file mode 100644
index 000000000..762478a99
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java
@@ -0,0 +1,82 @@
+package com.example.android.apis.app;
+/*
+ * 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.
+ */
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.support.v4.print.PrintHelper;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.widget.ImageView;
+
+import com.example.android.apis.R;
+
+/**
+ * This class demonstrates how to implement bitmap printing.
+ * <p>
+ * This activity shows an image and offers a print option in the overflow
+ * menu. When the user chooses to print a helper class from the support
+ * library is used to print the image.
+ * </p>
+ *
+ * @see PrintManager
+ * @see WebView
+ */
+public class PrintBitmap extends Activity {
+
+ private ImageView mImageView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.print_bitmap);
+ mImageView = (ImageView) findViewById(R.id.image);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.print_custom_content, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.menu_print) {
+ print();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void print() {
+ // Get the print manager.
+ PrintHelper printHelper = new PrintHelper(this);
+
+ // Set the desired scale mode.
+ printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT);
+
+ // Get the bitmap for the ImageView's drawable.
+ Bitmap bitmap = ((BitmapDrawable) mImageView.getDrawable()).getBitmap();
+
+ // Print the bitmap.
+ printHelper.printBitmap("Print Bitmap", bitmap);
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java
new file mode 100644
index 000000000..7a7e7ed80
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java
@@ -0,0 +1,562 @@
+/*
+ * 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.app;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.pdf.PdfDocument.Page;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CancellationSignal.OnCancelListener;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.print.PrintManager;
+import android.print.pdf.PrintedPdfDocument;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.example.android.apis.R;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class demonstrates how to implement custom printing support.
+ * <p>
+ * This activity shows the list of the MotoGP champions by year and
+ * brand. The print option in the overflow menu allows the user to
+ * print the content. The list list of items is laid out to such that
+ * it fits the options selected by the user from the UI such as page
+ * size. Hence, for different page sizes the printed content will have
+ * different page count.
+ * </p>
+ * <p>
+ * This sample demonstrates how to completely implement a {@link
+ * PrintDocumentAdapter} in which:
+ * <ul>
+ * <li>Layout based on the selected print options is performed.</li>
+ * <li>Layout work is performed only if print options change would change the content.</li>
+ * <li>Layout result is properly reported.</li>
+ * <li>Only requested pages are written.</li>
+ * <li>Write result is properly reported.</li>
+ * <li>Both Layout and write respond to cancellation.</li>
+ * <li>Layout and render of views is demonstrated.</li>
+ * </ul>
+ * </p>
+ *
+ * @see PrintManager
+ * @see PrintDocumentAdapter
+ */
+public class PrintCustomContent extends ListActivity {
+
+ private static final int MILS_IN_INCH = 1000;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setListAdapter(new MotoGpStatAdapter(loadMotoGpStats(),
+ getLayoutInflater()));
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.print_custom_content, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.menu_print) {
+ print();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void print() {
+ PrintManager printManager = (PrintManager) getSystemService(
+ Context.PRINT_SERVICE);
+
+ printManager.print("MotoGP stats",
+ new PrintDocumentAdapter() {
+ private int mRenderPageWidth;
+ private int mRenderPageHeight;
+
+ private PrintAttributes mPrintAttributes;
+ private PrintDocumentInfo mDocumentInfo;
+ private Context mPrintContext;
+
+ @Override
+ public void onLayout(final PrintAttributes oldAttributes,
+ final PrintAttributes newAttributes,
+ final CancellationSignal cancellationSignal,
+ final LayoutResultCallback callback,
+ final Bundle metadata) {
+
+ // If we are already cancelled, don't do any work.
+ if (cancellationSignal.isCanceled()) {
+ callback.onLayoutCancelled();
+ return;
+ }
+
+ // Now we determined if the print attributes changed in a way that
+ // would change the layout and if so we will do a layout pass.
+ boolean layoutNeeded = false;
+
+ final int density = Math.max(newAttributes.getResolution().getHorizontalDpi(),
+ newAttributes.getResolution().getVerticalDpi());
+
+ // Note that we are using the PrintedPdfDocument class which creates
+ // a PDF generating canvas whose size is in points (1/72") not screen
+ // pixels. Hence, this canvas is pretty small compared to the screen.
+ // The recommended way is to layout the content in the desired size,
+ // in this case as large as the printer can do, and set a translation
+ // to the PDF canvas to shrink in. Note that PDF is a vector format
+ // and you will not lose data during the transformation.
+
+ // The content width is equal to the page width minus the margins times
+ // the horizontal printer density. This way we get the maximal number
+ // of pixels the printer can put horizontally.
+ final int marginLeft = (int) (density * (float) newAttributes.getMinMargins()
+ .getLeftMils() / MILS_IN_INCH);
+ final int marginRight = (int) (density * (float) newAttributes.getMinMargins()
+ .getRightMils() / MILS_IN_INCH);
+ final int contentWidth = (int) (density * (float) newAttributes.getMediaSize()
+ .getWidthMils() / MILS_IN_INCH) - marginLeft - marginRight;
+ if (mRenderPageWidth != contentWidth) {
+ mRenderPageWidth = contentWidth;
+ layoutNeeded = true;
+ }
+
+ // The content height is equal to the page height minus the margins times
+ // the vertical printer resolution. This way we get the maximal number
+ // of pixels the printer can put vertically.
+ final int marginTop = (int) (density * (float) newAttributes.getMinMargins()
+ .getTopMils() / MILS_IN_INCH);
+ final int marginBottom = (int) (density * (float) newAttributes.getMinMargins()
+ .getBottomMils() / MILS_IN_INCH);
+ final int contentHeight = (int) (density * (float) newAttributes.getMediaSize()
+ .getHeightMils() / MILS_IN_INCH) - marginTop - marginBottom;
+ if (mRenderPageHeight != contentHeight) {
+ mRenderPageHeight = contentHeight;
+ layoutNeeded = true;
+ }
+
+ // Create a context for resources at printer density. We will
+ // be inflating views to render them and would like them to use
+ // resources for a density the printer supports.
+ if (mPrintContext == null || mPrintContext.getResources()
+ .getConfiguration().densityDpi != density) {
+ Configuration configuration = new Configuration();
+ configuration.densityDpi = density;
+ mPrintContext = createConfigurationContext(
+ configuration);
+ mPrintContext.setTheme(android.R.style.Theme_Holo_Light);
+ }
+
+ // If no layout is needed that we did a layout at least once and
+ // the document info is not null, also the second argument is false
+ // to notify the system that the content did not change. This is
+ // important as if the system has some pages and the content didn't
+ // change the system will ask, the application to write them again.
+ if (!layoutNeeded) {
+ callback.onLayoutFinished(mDocumentInfo, false);
+ return;
+ }
+
+ // For demonstration purposes we will do the layout off the main
+ // thread but for small content sizes like this one it is OK to do
+ // that on the main thread.
+
+ // Store the data as we will layout off the main thread.
+ final List<MotoGpStatItem> items = ((MotoGpStatAdapter)
+ getListAdapter()).cloneItems();
+
+ new AsyncTask<Void, Void, PrintDocumentInfo>() {
+ @Override
+ protected void onPreExecute() {
+ // First register for cancellation requests.
+ cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel() {
+ cancel(true);
+ }
+ });
+ // Stash the attributes as we will need them for rendering.
+ mPrintAttributes = newAttributes;
+ }
+
+ @Override
+ protected PrintDocumentInfo doInBackground(Void... params) {
+ try {
+ // Create an adapter with the stats and an inflater
+ // to load resources for the printer density.
+ MotoGpStatAdapter adapter = new MotoGpStatAdapter(items,
+ (LayoutInflater) mPrintContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE));
+
+ int currentPage = 0;
+ int pageContentHeight = 0;
+ int viewType = -1;
+ View view = null;
+ LinearLayout dummyParent = new LinearLayout(mPrintContext);
+ dummyParent.setOrientation(LinearLayout.VERTICAL);
+
+ final int itemCount = adapter.getCount();
+ for (int i = 0; i < itemCount; i++) {
+ // Be nice and respond to cancellation.
+ if (isCancelled()) {
+ return null;
+ }
+
+ // Get the next view.
+ final int nextViewType = adapter.getItemViewType(i);
+ if (viewType == nextViewType) {
+ view = adapter.getView(i, view, dummyParent);
+ } else {
+ view = adapter.getView(i, null, dummyParent);
+ }
+ viewType = nextViewType;
+
+ // Measure the next view
+ measureView(view);
+
+ // Add the height but if the view crosses the page
+ // boundary we will put it to the next page.
+ pageContentHeight += view.getMeasuredHeight();
+ if (pageContentHeight > mRenderPageHeight) {
+ pageContentHeight = view.getMeasuredHeight();
+ currentPage++;
+ }
+ }
+
+ // Create a document info describing the result.
+ PrintDocumentInfo info = new PrintDocumentInfo
+ .Builder("MotoGP_stats.pdf")
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(currentPage + 1)
+ .build();
+
+ // We completed the layout as a result of print attributes
+ // change. Hence, if we are here the content changed for
+ // sure which is why we pass true as the second argument.
+ callback.onLayoutFinished(info, true);
+ return info;
+ } catch (Exception e) {
+ // An unexpected error, report that we failed and
+ // one may pass in a human readable localized text
+ // for what the error is if known.
+ callback.onLayoutFailed(null);
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(PrintDocumentInfo result) {
+ // Update the cached info to send it over if the next
+ // layout pass does not result in a content change.
+ mDocumentInfo = result;
+ }
+
+ @Override
+ protected void onCancelled(PrintDocumentInfo result) {
+ // Task was cancelled, report that.
+ callback.onLayoutCancelled();
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
+ @Override
+ public void onWrite(final PageRange[] pages,
+ final ParcelFileDescriptor destination,
+ final CancellationSignal cancellationSignal,
+ final WriteResultCallback callback) {
+
+ // If we are already cancelled, don't do any work.
+ if (cancellationSignal.isCanceled()) {
+ callback.onWriteCancelled();
+ return;
+ }
+
+ // Store the data as we will layout off the main thread.
+ final List<MotoGpStatItem> items = ((MotoGpStatAdapter)
+ getListAdapter()).cloneItems();
+
+ new AsyncTask<Void, Void, Void>() {
+ private final SparseIntArray mWrittenPages = new SparseIntArray();
+ private final PrintedPdfDocument mPdfDocument = new PrintedPdfDocument(
+ PrintCustomContent.this, mPrintAttributes);
+
+ @Override
+ protected void onPreExecute() {
+ // First register for cancellation requests.
+ cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel() {
+ cancel(true);
+ }
+ });
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ // Go over all the pages and write only the requested ones.
+ // Create an adapter with the stats and an inflater
+ // to load resources for the printer density.
+ MotoGpStatAdapter adapter = new MotoGpStatAdapter(items,
+ (LayoutInflater) mPrintContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE));
+
+ int currentPage = -1;
+ int pageContentHeight = 0;
+ int viewType = -1;
+ View view = null;
+ Page page = null;
+ LinearLayout dummyParent = new LinearLayout(mPrintContext);
+ dummyParent.setOrientation(LinearLayout.VERTICAL);
+
+ // The content is laid out and rendered in screen pixels with
+ // the width and height of the paper size times the print
+ // density but the PDF canvas size is in points which are 1/72",
+ // so we will scale down the content.
+ final float scale = Math.min(
+ (float) mPdfDocument.getPageContentRect().width()
+ / mRenderPageWidth,
+ (float) mPdfDocument.getPageContentRect().height()
+ / mRenderPageHeight);
+
+ final int itemCount = adapter.getCount();
+ for (int i = 0; i < itemCount; i++) {
+ // Be nice and respond to cancellation.
+ if (isCancelled()) {
+ return null;
+ }
+
+ // Get the next view.
+ final int nextViewType = adapter.getItemViewType(i);
+ if (viewType == nextViewType) {
+ view = adapter.getView(i, view, dummyParent);
+ } else {
+ view = adapter.getView(i, null, dummyParent);
+ }
+ viewType = nextViewType;
+
+ // Measure the next view
+ measureView(view);
+
+ // Add the height but if the view crosses the page
+ // boundary we will put it to the next one.
+ pageContentHeight += view.getMeasuredHeight();
+ if (currentPage < 0 || pageContentHeight > mRenderPageHeight) {
+ pageContentHeight = view.getMeasuredHeight();
+ currentPage++;
+ // Done with the current page - finish it.
+ if (page != null) {
+ mPdfDocument.finishPage(page);
+ }
+ // If the page is requested, render it.
+ if (containsPage(pages, currentPage)) {
+ page = mPdfDocument.startPage(currentPage);
+ page.getCanvas().scale(scale, scale);
+ // Keep track which pages are written.
+ mWrittenPages.append(mWrittenPages.size(), currentPage);
+ } else {
+ page = null;
+ }
+ }
+
+ // If the current view is on a requested page, render it.
+ if (page != null) {
+ // Layout an render the content.
+ view.layout(0, 0, view.getMeasuredWidth(),
+ view.getMeasuredHeight());
+ view.draw(page.getCanvas());
+ // Move the canvas for the next view.
+ page.getCanvas().translate(0, view.getHeight());
+ }
+ }
+
+ // Done with the last page.
+ if (page != null) {
+ mPdfDocument.finishPage(page);
+ }
+
+ // Write the data and return success or failure.
+ try {
+ mPdfDocument.writeTo(new FileOutputStream(
+ destination.getFileDescriptor()));
+ // Compute which page ranges were written based on
+ // the bookkeeping we maintained.
+ PageRange[] pageRanges = computeWrittenPageRanges(mWrittenPages);
+ callback.onWriteFinished(pageRanges);
+ } catch (IOException ioe) {
+ callback.onWriteFailed(null);
+ } finally {
+ mPdfDocument.close();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onCancelled(Void result) {
+ // Task was cancelled, report that.
+ callback.onWriteCancelled();
+ mPdfDocument.close();
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
+ private void measureView(View view) {
+ final int widthMeasureSpec = ViewGroup.getChildMeasureSpec(
+ MeasureSpec.makeMeasureSpec(mRenderPageWidth,
+ MeasureSpec.EXACTLY), 0, view.getLayoutParams().width);
+ final int heightMeasureSpec = ViewGroup.getChildMeasureSpec(
+ MeasureSpec.makeMeasureSpec(mRenderPageHeight,
+ MeasureSpec.EXACTLY), 0, view.getLayoutParams().height);
+ view.measure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ private PageRange[] computeWrittenPageRanges(SparseIntArray writtenPages) {
+ List<PageRange> pageRanges = new ArrayList<PageRange>();
+
+ int start = -1;
+ int end = -1;
+ final int writtenPageCount = writtenPages.size();
+ for (int i = 0; i < writtenPageCount; i++) {
+ if (start < 0) {
+ start = writtenPages.valueAt(i);
+ }
+ int oldEnd = end = start;
+ while (i < writtenPageCount && (end - oldEnd) <= 1) {
+ oldEnd = end;
+ end = writtenPages.valueAt(i);
+ i++;
+ }
+ PageRange pageRange = new PageRange(start, end);
+ pageRanges.add(pageRange);
+ start = end = -1;
+ }
+
+ PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+ pageRanges.toArray(pageRangesArray);
+ return pageRangesArray;
+ }
+
+ private boolean containsPage(PageRange[] pageRanges, int page) {
+ final int pageRangeCount = pageRanges.length;
+ for (int i = 0; i < pageRangeCount; i++) {
+ if (pageRanges[i].getStart() <= page
+ && pageRanges[i].getEnd() >= page) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }, null);
+ }
+
+ private List<MotoGpStatItem> loadMotoGpStats() {
+ String[] years = getResources().getStringArray(R.array.motogp_years);
+ String[] champions = getResources().getStringArray(R.array.motogp_champions);
+ String[] constructors = getResources().getStringArray(R.array.motogp_constructors);
+
+ List<MotoGpStatItem> items = new ArrayList<MotoGpStatItem>();
+
+ final int itemCount = years.length;
+ for (int i = 0; i < itemCount; i++) {
+ MotoGpStatItem item = new MotoGpStatItem();
+ item.year = years[i];
+ item.champion = champions[i];
+ item.constructor = constructors[i];
+ items.add(item);
+ }
+
+ return items;
+ }
+
+ private static final class MotoGpStatItem {
+ String year;
+ String champion;
+ String constructor;
+ }
+
+ private class MotoGpStatAdapter extends BaseAdapter {
+ private final List<MotoGpStatItem> mItems;
+ private final LayoutInflater mInflater;
+
+ public MotoGpStatAdapter(List<MotoGpStatItem> items, LayoutInflater inflater) {
+ mItems = items;
+ mInflater = inflater;
+ }
+
+ public List<MotoGpStatItem> cloneItems() {
+ return new ArrayList<MotoGpStatItem>(mItems);
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.motogp_stat_item, parent, false);
+ }
+
+ MotoGpStatItem item = (MotoGpStatItem) getItem(position);
+
+ TextView yearView = (TextView) convertView.findViewById(R.id.year);
+ yearView.setText(item.year);
+
+ TextView championView = (TextView) convertView.findViewById(R.id.champion);
+ championView.setText(item.champion);
+
+ TextView constructorView = (TextView) convertView.findViewById(R.id.constructor);
+ constructorView.setText(item.constructor);
+
+ return convertView;
+ }
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java
new file mode 100644
index 000000000..55c98ffc9
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java
@@ -0,0 +1,93 @@
+/*
+ * 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.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.example.android.apis.R;
+
+/**
+ * This class demonstrates how to implement HTML content printing
+ * from a {@link WebView} which is shown on the screen.
+ * <p>
+ * This activity shows a simple HTML content in a {@link WebView}
+ * and allows the user to print that content via an action in the
+ * action bar. The shown {@link WebView} is doing the printing.
+ * </p>
+ *
+ * @see PrintManager
+ * @see WebView
+ */
+public class PrintHtmlFromScreen extends Activity {
+
+ private WebView mWebView;
+
+ private boolean mDataLoaded;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.print_html_from_screen);
+ mWebView = (WebView) findViewById(R.id.web_view);
+
+ // Important: Only enable the print option after the page is loaded.
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ // Data loaded, so now we want to show the print option.
+ mDataLoaded = true;
+ invalidateOptionsMenu();
+ }
+ });
+
+ // Load an HTML page.
+ mWebView.loadUrl("file:///android_res/raw/motogp_stats.html");
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ if (mDataLoaded) {
+ getMenuInflater().inflate(R.menu.print_custom_content, menu);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.menu_print) {
+ print();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void print() {
+ // Get the print manager.
+ PrintManager printManager = (PrintManager) getSystemService(
+ Context.PRINT_SERVICE);
+ // Pass in the ViewView's document adapter.
+ printManager.print("MotoGP stats", mWebView.createPrintDocumentAdapter(), null);
+ }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.java
new file mode 100644
index 000000000..9c239b867
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.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.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.example.android.apis.R;
+
+/**
+ * This class demonstrates how to implement HTML content printing
+ * from a {@link WebView} which is not shown on the screen.
+ * <p>
+ * This activity shows a text prompt and when the user chooses the
+ * print option from the overflow menu an HTML page with content that
+ * is not on the screen is printed via an off-screen {@link WebView}.
+ * </p>
+ *
+ * @see PrintManager
+ * @see WebView
+ */
+public class PrintHtmlOffScreen extends Activity {
+
+ private WebView mWebView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.print_html_off_screen);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.print_custom_content, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.menu_print) {
+ print();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void print() {
+ // Create a WebView and hold on to it as the printing will start when
+ // load completes and we do not want the WbeView to be garbage collected.
+ mWebView = new WebView(this);
+
+ // Important: Only after the page is loaded we will do the print.
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ doPrint();
+ }
+ });
+
+ // Load an HTML page.
+ mWebView.loadUrl("file:///android_res/raw/motogp_stats.html");
+ }
+
+ private void doPrint() {
+ // Get the print manager.
+ PrintManager printManager = (PrintManager) getSystemService(
+ Context.PRINT_SERVICE);
+
+ // Create a wrapper PrintDocumentAdapter to clean up when done.
+ PrintDocumentAdapter adapter = new PrintDocumentAdapter() {
+ private final PrintDocumentAdapter mWrappedInstance =
+ mWebView.createPrintDocumentAdapter();
+
+ @Override
+ public void onStart() {
+ mWrappedInstance.onStart();
+ }
+
+ @Override
+ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ Bundle extras) {
+ mWrappedInstance.onLayout(oldAttributes, newAttributes, cancellationSignal,
+ callback, extras);
+ }
+
+ @Override
+ public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ mWrappedInstance.onWrite(pages, destination, cancellationSignal, callback);
+ }
+
+ @Override
+ public void onFinish() {
+ mWrappedInstance.onFinish();
+ // Intercept the finish call to know when printing is done
+ // and destroy the WebView as it is expensive to keep around.
+ mWebView.destroy();
+ mWebView = null;
+ }
+ };
+
+ // Pass in the ViewView's document adapter.
+ printManager.print("MotoGP stats", adapter, null);
+ }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/README b/samples/devbytes/telephony/SmsSampleProject/README
new file mode 100644
index 000000000..a26768cab
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/README
@@ -0,0 +1,7 @@
+This is an Android Studio project:
+http://developer.android.com/sdk/installing/studio.html
+
+To build you should first copy local.properties.sample to
+local.properties and set your SDK path.
+
+Then use Android Studio to import the project.
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle b/samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle
new file mode 100644
index 000000000..d0f9b9766
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.6.+'
+ }
+}
+apply plugin: 'android'
+
+repositories {
+ mavenCentral()
+}
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "18.1.1"
+
+ defaultConfig {
+ minSdkVersion 10
+ targetSdkVersion 19
+ }
+}
+
+dependencies {
+ compile 'com.android.support:support-v4:18.0.0'
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..d6d43799d
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml
@@ -0,0 +1,138 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.smssample"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="10"
+ android:targetSdkVersion="19" />
+
+ <uses-permission android:name="android.permission.WRITE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_MMS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <action android:name="android.intent.action.SENDTO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ </intent-filter>
+
+ </activity>
+
+ <!-- BroadcastReceiver that listens for incoming SMS messages -->
+ <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+ is enabled on KitKat devices and above -->
+ <receiver android:name=".receiver.SmsReceiver"
+ android:enabled="@bool/hasKitKat"
+ android:permission="android.permission.BROADCAST_SMS">
+
+ <!-- KitKat+ SMS received action -->
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_DELIVER" />
+ </intent-filter>
+
+ </receiver>
+
+ <!-- BroadcastReceiver that listens for incoming SMS messages -->
+ <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+ is enabled on preKitKat devices -->
+ <receiver android:name=".receiver.SmsReceiverLegacy"
+ android:enabled="@bool/preKitKat">
+
+ <!-- Pre-KitKat SMS received action -->
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_RECEIVED" />
+ </intent-filter>
+
+ </receiver>
+
+ <!-- BroadcastReceiver that listens for incoming MMS messages -->
+ <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+ is enabled on KitKat devices and above -->
+ <receiver android:name=".receiver.MmsReceiver"
+ android:enabled="@bool/hasKitKat"
+ android:permission="android.permission.BROADCAST_WAP_PUSH">
+
+ <!-- KitKat+ MMS received action -->
+ <intent-filter>
+ <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+ <data android:mimeType="application/vnd.wap.mms-message" />
+ </intent-filter>
+
+ </receiver>
+
+ <!-- BroadcastReceiver that listens for incoming MMS messages -->
+ <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+ is enabled on preKitKat devices -->
+ <receiver android:name=".receiver.MmsReceiverLegacy"
+ android:enabled="@bool/preKitKat">
+
+ <!-- Pre-KitKat MMS received action -->
+ <intent-filter>
+ <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
+ <data android:mimeType="application/vnd.wap.mms-message" />
+ </intent-filter>
+
+ </receiver>
+
+ <!-- Service that delivers SMS messages received from the phone "quick response" -->
+ <service android:name=".service.RespondService"
+ android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ </intent-filter>
+ </service>
+
+ <!-- A service used internally to process incoming SMS/MMS -->
+ <service android:name=".service.MessagingService"
+ android:exported="false" />
+
+ </application>
+
+</manifest>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java
new file mode 100644
index 000000000..c94939704
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java
@@ -0,0 +1,203 @@
+/*
+ * 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.smssample;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Telephony.Sms.Inbox;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.SimpleCursorAdapter;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+/**
+ * The main Activity that provides a sample of a few things:
+ * -detecting if this app is the default SMS app and then showing/hiding UI and enabling/disabling
+ * functionality. the UI that is shown has a button to prompt the user to set this app as the
+ * default.
+ * -a simple query to the SMS content provider to show a list of SMS messages in the inbox. even
+ * though the query uses KitKat APIs this query should still work on earlier versions of Android
+ * as the contract class and ContentProvider were still around (with essentially the same
+ * structure) but were private.
+ * -being triggered from another application when creating a new SMS. a good example is creating
+ * a new SMS from the system People application. although nothing is done with the incoming
+ * Intent in this case (just a Toast is displayed)
+ *
+ * Obviously this is far from a full implementation and should just be used as a sample of how
+ * an app could be set up to correctly integrate with the new Android 4.4 KitKat APIs while
+ * running normally on earlier Android versions.
+ */
+public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
+ private RelativeLayout mSetDefaultSmsLayout;
+ private Button mSendSmsButton;
+ private EditText mSendSmsEditText;
+ private SimpleCursorAdapter mAdapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Find some views
+ mSetDefaultSmsLayout = (RelativeLayout) findViewById(R.id.set_default_sms_layout);
+ mSendSmsEditText = (EditText) findViewById(R.id.send_sms_edittext);
+ ListView listView = (ListView) findViewById(android.R.id.list);
+ listView.setEmptyView(findViewById(android.R.id.empty));
+ mSendSmsButton = (Button) findViewById(R.id.send_sms_button);
+ mSendSmsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ sendSms(mSendSmsEditText.getText().toString());
+ }
+ });
+
+ // Create adapter and set it to our ListView
+ final String[] fromFields = new String[] {
+ SmsQuery.PROJECTION[SmsQuery.ADDRESS], SmsQuery.PROJECTION[SmsQuery.BODY] };
+ final int[] toViews = new int[] { android.R.id.text1, android.R.id.text2 };
+ mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null,
+ fromFields, toViews, 0);
+ listView.setAdapter(mAdapter);
+
+ // Placeholder to process incoming SEND/SENDTO intents
+ String intentAction = getIntent() == null ? null : getIntent().getAction();
+ if (!TextUtils.isEmpty(intentAction) && (Intent.ACTION_SENDTO.equals(intentAction)
+ || Intent.ACTION_SEND.equals(intentAction))) {
+ // TODO: Handle incoming SEND and SENDTO intents by pre-populating UI components
+ Toast.makeText(this, "Handle SEND and SENDTO intents: " + getIntent().getDataString(),
+ Toast.LENGTH_SHORT).show();
+ }
+
+ // Simple query to show the most recent SMS messages in the inbox
+ getSupportLoaderManager().initLoader(SmsQuery.TOKEN, null, this);
+ }
+
+ /**
+ * Dummy sendSms method, would need the "to" address to actually send a message :)
+ */
+ private void sendSms(String smsText) {
+ if (!TextUtils.isEmpty(smsText)) {
+ if (Utils.isDefaultSmsApp(this)) {
+ // TODO: Use SmsManager to send SMS and then record the message in the system SMS
+ // ContentProvider
+ Toast.makeText(this, "Sending text message: " + smsText, Toast.LENGTH_SHORT).show();
+ } else {
+ // TODO: Notify the user the app is not default and provide a way to trigger
+ // Utils.setDefaultSmsApp() so they can set it.
+ Toast.makeText(this, "Not default", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Only do these checks/changes on KitKat+, the "mSetDefaultSmsLayout" has its visibility
+ // set to "gone" in the xml layout so it won't show at all on earlier Android versions.
+ if (Utils.hasKitKat()) {
+ if (Utils.isDefaultSmsApp(this)) {
+ // This app is the default, remove the "make this app the default" layout and
+ // enable message sending components.
+ mSetDefaultSmsLayout.setVisibility(View.GONE);
+ mSendSmsEditText.setHint(R.string.sms_send_new_hint);
+ mSendSmsEditText.setEnabled(true);
+ mSendSmsButton.setEnabled(true);
+ } else {
+ // Not the default, show the "make this app the default" layout and disable
+ // message sending components.
+ mSetDefaultSmsLayout.setVisibility(View.VISIBLE);
+ mSendSmsEditText.setText("");
+ mSendSmsEditText.setHint(R.string.sms_send_disabled);
+ mSendSmsEditText.setEnabled(false);
+ mSendSmsButton.setEnabled(false);
+
+ Button button = (Button) findViewById(R.id.set_default_sms_button);
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Utils.setDefaultSmsApp(MainActivity.this);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
+ if (i == SmsQuery.TOKEN) {
+ // This will fetch all SMS messages in the inbox, ordered by date desc
+ return new CursorLoader(this, SmsQuery.CONTENT_URI, SmsQuery.PROJECTION, null, null,
+ SmsQuery.SORT_ORDER);
+ }
+ return null;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
+ if (cursorLoader.getId() == SmsQuery.TOKEN && cursor != null) {
+ // Standard swap cursor in when load is done
+ mAdapter.swapCursor(cursor);
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> cursorLoader) {
+ // Standard swap cursor to null when loader is reset
+ mAdapter.swapCursor(null);
+ }
+
+ /**
+ * A basic SmsQuery on android.provider.Telephony.Sms.Inbox
+ */
+ private interface SmsQuery {
+ int TOKEN = 1;
+
+ static final Uri CONTENT_URI = Inbox.CONTENT_URI;
+
+ static final String[] PROJECTION = {
+ Inbox._ID,
+ Inbox.ADDRESS,
+ Inbox.BODY,
+ };
+
+ static final String SORT_ORDER = Inbox.DEFAULT_SORT_ORDER;
+
+ int ID = 0;
+ int ADDRESS = 1;
+ int BODY = 2;
+ }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java
new file mode 100644
index 000000000..00dc7d600
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.smssample;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.provider.Telephony;
+import android.provider.Telephony.Sms.Intents;
+
+public class Utils {
+
+ /**
+ * Check if the device runs Android 4.3 (JB MR2) or higher.
+ */
+ public static boolean hasJellyBeanMR2() {
+ return Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2;
+ }
+
+ /**
+ * Check if the device runs Android 4.4 (KitKat) or higher.
+ */
+ public static boolean hasKitKat() {
+ return Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT;
+ }
+
+ /**
+ * Check if your app is the default system SMS app.
+ * @param context The Context
+ * @return True if it is default, False otherwise. Pre-KitKat will always return True.
+ */
+ public static boolean isDefaultSmsApp(Context context) {
+ if (hasKitKat()) {
+ return context.getPackageName().equals(Telephony.Sms.getDefaultSmsPackage(context));
+ }
+
+ return true;
+ }
+
+ /**
+ * Trigger the intent to open the system dialog that asks the user to change the default
+ * SMS app.
+ * @param context The Context
+ */
+ public static void setDefaultSmsApp(Context context) {
+ // This is a new intent which only exists on KitKat
+ if (hasKitKat()) {
+ Intent intent = new Intent(Intents.ACTION_CHANGE_DEFAULT);
+ intent.putExtra(Intents.EXTRA_PACKAGE_NAME, context.getPackageName());
+ context.startActivity(intent);
+ }
+ }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java
new file mode 100644
index 000000000..4dcb05533
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java
@@ -0,0 +1,69 @@
+/*
+ * 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.smssample.receiver;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Telephony.Sms.Intents;
+import android.support.v4.content.WakefulBroadcastReceiver;
+
+import com.example.android.smssample.service.MessagingService;
+import com.example.android.smssample.Utils;
+
+/**
+ * The main messaging receiver class. Note that this is not directly included in
+ * AndroidManifest.xml, instead, subclassed versions of this are included which allows
+ * them to be enabled/disabled independently as they will have a unique component name.
+ */
+public class MessagingReceiver extends WakefulBroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent == null ? null : intent.getAction();
+
+ // If on KitKat+ and default messaging app then look for new deliver actions actions.
+ if (Utils.hasKitKat() && Utils.isDefaultSmsApp(context)) {
+ if (Intents.SMS_DELIVER_ACTION.equals(action)) {
+ handleIncomingSms(context, intent);
+ } else if (Intents.WAP_PUSH_DELIVER_ACTION.equals(action)) {
+ handleIncomingMms(context, intent);
+ }
+ } else { // Otherwise look for old pre-KitKat actions
+ if (Intents.SMS_RECEIVED_ACTION.equals(action)) {
+ handleIncomingSms(context, intent);
+ } else if (Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
+ handleIncomingMms(context, intent);
+ }
+ }
+ }
+
+ private void handleIncomingSms(Context context, Intent intent) {
+ // TODO: Handle SMS here
+ // As an example, we'll start a wakeful service to handle the SMS
+ intent.setAction(MessagingService.ACTION_MY_RECEIVE_SMS);
+ intent.setClass(context, MessagingService.class);
+ startWakefulService(context, intent);
+ }
+
+ private void handleIncomingMms(Context context, Intent intent) {
+ // TODO: Handle MMS here
+ // As an example, we'll start a wakeful service to handle the MMS
+ intent.setAction(MessagingService.ACTION_MY_RECEIVE_MMS);
+ intent.setClass(context, MessagingService.class);
+ startWakefulService(context, intent);
+ }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java
new file mode 100644
index 000000000..40f04bb60
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java
@@ -0,0 +1,24 @@
+/*
+ * 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.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class MmsReceiver extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java
new file mode 100644
index 000000000..181fe45c5
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java
@@ -0,0 +1,24 @@
+/*
+ * 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.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class MmsReceiverLegacy extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java
new file mode 100644
index 000000000..0c4a2cc76
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java
@@ -0,0 +1,24 @@
+/*
+ * 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.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class SmsReceiver extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java
new file mode 100644
index 000000000..a02d18813
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java
@@ -0,0 +1,24 @@
+/*
+ * 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.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class SmsReceiverLegacy extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java
new file mode 100644
index 000000000..af191e8b2
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java
@@ -0,0 +1,58 @@
+/*
+ * 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.smssample.service;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+import com.example.android.smssample.receiver.MessagingReceiver;
+
+/**
+ * This service is triggered internally only and is used to process incoming SMS and MMS messages
+ * that the {@link com.example.android.smssample.receiver.MessagingReceiver} passes over. It's
+ * preferable to handle these in a service in case there is significant work to do which may exceed
+ * the time allowed in a receiver.
+ */
+public class MessagingService extends IntentService {
+ private static final String TAG = "MessagingService";
+
+ // These actions are for this app only and are used by MessagingReceiver to start this service
+ public static final String ACTION_MY_RECEIVE_SMS = "com.example.android.smssample.RECEIVE_SMS";
+ public static final String ACTION_MY_RECEIVE_MMS = "com.example.android.smssample.RECEIVE_MMS";
+
+ public MessagingService() {
+ super(TAG);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ if (intent != null) {
+ String intentAction = intent.getAction();
+ if (ACTION_MY_RECEIVE_SMS.equals(intentAction)) {
+ // TODO: Handle incoming SMS
+
+ // Ensure wakelock is released that was created by the WakefulBroadcastReceiver
+ MessagingReceiver.completeWakefulIntent(intent);
+ } else if (ACTION_MY_RECEIVE_MMS.equals(intentAction)) {
+ // TODO: Handle incoming MMS
+
+ // Ensure wakelock is released that was created by the WakefulBroadcastReceiver
+ MessagingReceiver.completeWakefulIntent(intent);
+ }
+ }
+ }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java
new file mode 100644
index 000000000..d88a762bc
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java
@@ -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.
+ */
+
+package com.example.android.smssample.service;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.telephony.TelephonyManager;
+
+import com.example.android.smssample.Utils;
+
+/**
+ * This service handles the system intent ACTION_RESPOND_VIA_MESSAGE when we are the default SMS
+ * app.
+ */
+public class RespondService extends IntentService {
+ private static final String TAG = "RespondService";
+
+ public RespondService() {
+ super(TAG);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ if (intent != null) {
+ if (Utils.hasJellyBeanMR2() && Utils.isDefaultSmsApp(this) &&
+ // ACTION_RESPOND_VIA_MESSAGE was added in JB MR2
+ TelephonyManager.ACTION_RESPOND_VIA_MESSAGE.equals(intent.getAction())) {
+ // TODO: Handle "respond via message" quick reply
+ }
+ }
+ }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..98cfcc5a8
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..6ccb6e05e
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..893b1ee4c
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..c51e62f69
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml
new file mode 100644
index 000000000..3005568e3
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,93 @@
+<!--
+ 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".MainActivity">
+
+ <RelativeLayout
+ android:id="@+id/set_default_sms_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:background="@color/alert_orange">
+
+ <Button
+ android:id="@+id/set_default_sms_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_margin="@dimen/standard_margin"
+ android:text="@string/choose_sms_app" />
+
+ <TextView
+ android:id="@+id/set_default_sms_textview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@+id/set_default_sms_button"
+ android:layout_centerVertical="true"
+ android:layout_margin="@dimen/standard_margin"
+ android:text="@string/set_default_sms_text" />
+
+ </RelativeLayout>
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:fastScrollEnabled="true" />
+
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:visibility="gone"
+ android:layout_margin="@dimen/standard_margin"
+ style="?android:textAppearanceMedium"
+ android:text="@string/sms_empty" />
+
+ <RelativeLayout
+ android:id="@+id/send_sms_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/standard_margin"
+ android:background="@color/light_gray">
+
+ <Button
+ android:id="@+id/send_sms_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:text="@string/sms_send" />
+
+ <EditText
+ android:id="@+id/send_sms_edittext"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@+id/send_sms_button"
+ android:layout_centerVertical="true"
+ android:hint="@string/sms_send_new_hint"/>
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml
new file mode 100644
index 000000000..e4ee086db
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml
@@ -0,0 +1,23 @@
+<!--
+ 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:id="@+id/action_default"
+ android:title="@string/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+
+</menu>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml
new file mode 100644
index 000000000..425c775b3
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml
@@ -0,0 +1,26 @@
+<!--
+ 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.
+-->
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml
new file mode 100644
index 000000000..20c993a7c
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml
@@ -0,0 +1,19 @@
+<!--
+ 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.
+-->
+<resources>
+ <bool name="hasKitKat">true</bool>
+ <bool name="preKitKat">false</bool>
+</resources> \ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml
new file mode 100644
index 000000000..1bded920c
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml
@@ -0,0 +1,19 @@
+<!--
+ 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.
+-->
+<resources>
+ <bool name="hasKitKat">false</bool>
+ <bool name="preKitKat">true</bool>
+</resources> \ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml
new file mode 100644
index 000000000..7f13ecd5a
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<resources>
+ <color name="alert_orange">#FFBB33</color>
+ <color name="light_gray">#F4F4F4</color>
+</resources> \ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..020e4d3f6
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+ 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.
+-->
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="standard_margin">8dp</dimen>
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml
new file mode 100644
index 000000000..c0f18e3de
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<resources>
+
+ <string name="app_name">SmsDemoApp</string>
+ <string name="action_settings">Settings</string>
+ <string name="choose_sms_app">Set as default</string>
+ <string name="sms_empty">No SMS messages</string>
+ <string name="set_default_sms_text">This app is not the default SMS app</string>
+ <string name="sms_send_new_hint">Send new SMS</string>
+ <string name="sms_send">Send</string>
+ <string name="sms_send_disabled">SMS Sending Disabled</string>
+
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml
new file mode 100644
index 000000000..848be93ad
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml
@@ -0,0 +1,35 @@
+<!--
+ 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.
+-->
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/build.gradle b/samples/devbytes/telephony/SmsSampleProject/build.gradle
new file mode 100644
index 000000000..495c5038e
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/build.gradle
@@ -0,0 +1 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
diff --git a/samples/devbytes/telephony/SmsSampleProject/local.properties.sample b/samples/devbytes/telephony/SmsSampleProject/local.properties.sample
new file mode 100644
index 000000000..37317f492
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/local.properties.sample
@@ -0,0 +1,7 @@
+# This file should be copied to local.properties and path set to point
+# to your Android SDK.
+
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/usr/local/lib/android-sdk \ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/settings.gradle b/samples/devbytes/telephony/SmsSampleProject/settings.gradle
new file mode 100644
index 000000000..e0867f09e
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/settings.gradle
@@ -0,0 +1 @@
+include ':SmsSample' \ No newline at end of file
diff --git a/samples/devbytes/ui/ImmersiveMode/build.gradle b/samples/devbytes/ui/ImmersiveMode/build.gradle
new file mode 100644
index 000000000..da6ff3598
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.6.+'
+ }
+}
+apply plugin: 'android'
+
+repositories {
+ mavenCentral()
+}
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "18.0.1"
+
+ defaultConfig {
+ minSdkVersion 19
+ targetSdkVersion 19
+ }
+}
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml b/samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..b4a35321f
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0"
+ package="com.example.android.immersive">
+
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+ <application android:icon="@drawable/ic_launcher"
+ android:label="@string/immersive_mode"
+ android:allowBackup="true">
+
+ <activity android:name=".ImmersiveActivity"
+ android:label="@string/immersive_mode"
+ android:configChanges="orientation|keyboardHidden|screenSize"
+ android:theme="@style/ImmersiveTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".ImmersiveStickyActivity"
+ android:taskAffinity=""
+ android:label="@string/immersive_sticky"
+ android:configChanges="orientation|keyboardHidden|screenSize"
+ android:theme="@style/ImmersiveStickyTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java
new file mode 100644
index 000000000..8fdde0853
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 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.immersive;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class ImmersiveActivity extends Activity {
+ private static final int INITIAL_HIDE_DELAY = 300;
+
+ private View mDecorView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.immersive_activity);
+
+ final View controlsView = findViewById(R.id.fullscreen_content_controls);
+ final View contentView = findViewById(R.id.fullscreen_content);
+
+ mDecorView = getWindow().getDecorView();
+ mDecorView.setOnSystemUiVisibilityChangeListener(
+ new View.OnSystemUiVisibilityChangeListener() {
+ @Override
+ public void onSystemUiVisibilityChange(int flags) {
+ boolean visible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+ controlsView.animate()
+ .alpha(visible ? 1 : 0)
+ .translationY(visible ? 0 : controlsView.getHeight());
+ }
+ });
+ contentView.setClickable(true);
+ final GestureDetector clickDetector = new GestureDetector(this,
+ new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ boolean visible = (mDecorView.getSystemUiVisibility()
+ & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+ if (visible) {
+ hideSystemUI();
+ } else {
+ showSystemUI();
+ }
+ return true;
+ }
+ });
+ contentView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ return clickDetector.onTouchEvent(motionEvent);
+ }
+ });
+
+ showSystemUI();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+
+ // When the window loses focus (e.g. the action overflow is shown),
+ // cancel any pending hide action. When the window gains focus,
+ // hide the system UI.
+ if (hasFocus) {
+ delayedHide(INITIAL_HIDE_DELAY);
+ } else {
+ mHideHandler.removeMessages(0);
+ }
+ }
+
+ private void hideSystemUI() {
+ mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LOW_PROFILE
+ | View.SYSTEM_UI_FLAG_IMMERSIVE);
+ }
+
+ private void showSystemUI() {
+ mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+ }
+
+ private final Handler mHideHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ hideSystemUI();
+ }
+ };
+
+ private void delayedHide(int delayMillis) {
+ mHideHandler.removeMessages(0);
+ mHideHandler.sendEmptyMessageDelayed(0, delayMillis);
+ }
+}
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java
new file mode 100644
index 000000000..d6dfd3695
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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.immersive;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class ImmersiveStickyActivity extends Activity {
+ private View mDecorView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.immersive_sticky_activity);
+ mDecorView = getWindow().getDecorView();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (hasFocus) {
+ mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ }
+ }
+}
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..f47fc3203
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.png b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.png
new file mode 100644
index 000000000..bf344ad86
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.png
Binary files differ
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml
new file mode 100644
index 000000000..e4ce45540
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/include_content" />
+
+ <!-- This FrameLayout insets its children based on system windows using
+ android:fitsSystemWindows. These insets will be stable across system
+ UI visibility changes because we use the SYSTEM_UI_FLAG_LAYOUT_STABLE
+ flag in addition to SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and
+ SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION. -->
+ <FrameLayout android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:fitsSystemWindows="true">
+
+ <LinearLayout android:id="@+id/fullscreen_content_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:background="@color/fullscreen_control_overlay_color"
+ android:orientation="horizontal">
+
+ <Button android:id="@+id/placeholder_button"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_weight="1"
+ android:text="@string/placeholder_button"
+ android:background="?android:selectableItemBackground" />
+
+ </LinearLayout>
+ </FrameLayout>
+
+</FrameLayout>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml
new file mode 100644
index 000000000..b98b923aa
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml
@@ -0,0 +1,23 @@
+<!--
+ Copyright 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/include_content" />
+
+</FrameLayout>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml
new file mode 100644
index 000000000..967573b3d
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright 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.
+ -->
+
+<!-- The primary full-screen view. This can be replaced with whatever view
+ is needed to present your content, e.g. VideoView, SurfaceView,
+ TextureView, etc. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fullscreen_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:keepScreenOn="true"
+ android:textColor="#fb3"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="bold"
+ android:lineSpacingMultiplier="0.8"
+ android:textSize="50sp"
+ android:gravity="center"
+ android:text="@string/placeholder_content" />
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml
new file mode 100644
index 000000000..7e91c5094
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright 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.
+ -->
+
+<resources>
+ <color name="background">#f80</color>
+ <color name="fullscreen_control_overlay_color">#66000000</color>
+</resources>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml
new file mode 100644
index 000000000..3c520f939
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 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.
+ -->
+
+<resources>
+ <string name="immersive_mode">Immersive Mode</string>
+ <string name="immersive_sticky">Immersive/Sticky</string>
+ <string name="placeholder_button">Placeholder Button</string>
+ <string name="placeholder_content">IMMERSIVE\nCONTENT</string>
+</resources>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml
new file mode 100644
index 000000000..2d7d458b3
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 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.
+ -->
+
+<resources>
+
+ <style name="ImmersiveTheme" parent="android:Theme.Holo">
+ <item name="android:windowBackground">@color/background</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowActionBarOverlay">true</item>
+ <item name="android:actionBarStyle">@style/ImmersiveActionBarStyle</item>
+ </style>
+
+ <style name="ImmersiveStickyTheme" parent="ImmersiveTheme">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowActionBar">false</item>
+ </style>
+
+ <style name="ImmersiveActionBarStyle" parent="android:Widget.Holo.ActionBar.Solid">
+ <item name="android:background">@color/fullscreen_control_overlay_color</item>
+ <item name="android:icon">@drawable/ic_launcher_translucent_actionbar</item>
+ </style>
+
+</resources>
diff --git a/scripts/app_engine_server/redirects.yaml b/scripts/app_engine_server/redirects.yaml
index 4f83713f8..d15017a4d 100644
--- a/scripts/app_engine_server/redirects.yaml
+++ b/scripts/app_engine_server/redirects.yaml
@@ -634,6 +634,10 @@ redirects:
dst: /about/versions/android-4.0.html
type: permanent
+- src: /(k|kk|kitkat)/?$
+ dst: /about/versions/kitkat.html
+ type: permanent
+
- src: /(j|jb|jellybean)/?$
dst: /about/versions/jelly-bean.html
type: permanent