diff options
| author | Bruno Oliveira <btco@google.com> | 2011-12-09 12:07:31 -0800 |
|---|---|---|
| committer | Android Git Automerger <android-git-automerger@android.com> | 2011-12-09 12:07:31 -0800 |
| commit | 7e3475caf3c397b4a416ccf2f9f373e4edc34fcf (patch) | |
| tree | b23e95cc67bbb77079dccecd191d8b718280e5fd /samples | |
| parent | 61cffb06334cd0677b70ef224f40d35822f720b3 (diff) | |
| parent | 4ea24bff40770c987add689970c64cf63077dd3f (diff) | |
| download | android_development-7e3475caf3c397b4a416ccf2f9f373e4edc34fcf.tar.gz android_development-7e3475caf3c397b4a416ccf2f9f373e4edc34fcf.tar.bz2 android_development-7e3475caf3c397b4a416ccf2f9f373e4edc34fcf.zip | |
am 4ea24bff: cherrypick from master cl Change-Id: I45f91fd9cfe0cb89789017deec63565e4757063e Adding the NewsReader sample.
* commit '4ea24bff40770c987add689970c64cf63077dd3f':
cherrypick from master cl Change-Id: I45f91fd9cfe0cb89789017deec63565e4757063e Adding the NewsReader sample.
Diffstat (limited to 'samples')
53 files changed, 1486 insertions, 0 deletions
diff --git a/samples/training/multiscreen/newsreader/AndroidManifest.xml b/samples/training/multiscreen/newsreader/AndroidManifest.xml new file mode 100644 index 000000000..04ddf292f --- /dev/null +++ b/samples/training/multiscreen/newsreader/AndroidManifest.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.newsreader" + android:versionCode="1" + android:versionName="1.0"> + <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14" /> + + <application android:icon="@drawable/icon" android:label="@string/app_name" + android:logo="@drawable/logo" android:theme="@style/NewsReaderStyle"> + <activity android:name=".NewsReaderActivity" android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name=".ArticleActivity" + android:theme="@style/NewsReaderStyle_NoActionBar" /> + </application> + <supports-screens + android:smallScreens="true" + android:normalScreens="true" + android:largeScreens="true" + android:xlargeScreens="true" + /> +</manifest> diff --git a/samples/training/multiscreen/newsreader/proguard.cfg b/samples/training/multiscreen/newsreader/proguard.cfg new file mode 100644 index 000000000..b1cdf17b5 --- /dev/null +++ b/samples/training/multiscreen/newsreader/proguard.cfg @@ -0,0 +1,40 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +-keepclasseswithmembernames class * { + native <methods>; +} + +-keepclasseswithmembers class * { + public <init>(android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public <init>(android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/samples/training/multiscreen/newsreader/project.properties b/samples/training/multiscreen/newsreader/project.properties new file mode 100644 index 000000000..730e911f2 --- /dev/null +++ b/samples/training/multiscreen/newsreader/project.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-14 diff --git a/samples/training/multiscreen/newsreader/res/drawable-hdpi/button_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-hdpi/button_normal.9.png Binary files differnew file mode 100644 index 000000000..1f53bc9fe --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-hdpi/button_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-hdpi/button_pressed.9.png b/samples/training/multiscreen/newsreader/res/drawable-hdpi/button_pressed.9.png Binary files differnew file mode 100644 index 000000000..71d157e72 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-hdpi/button_pressed.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-hdpi/icon.png b/samples/training/multiscreen/newsreader/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 000000000..a40bd0e6a --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-hdpi/icon.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-hdpi/logo.png b/samples/training/multiscreen/newsreader/res/drawable-hdpi/logo.png Binary files differnew file mode 100644 index 000000000..858562a04 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-hdpi/logo.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-hdpi/tab_bg_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-hdpi/tab_bg_normal.9.png Binary files differnew file mode 100644 index 000000000..51799f833 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-hdpi/tab_bg_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-hdpi/tab_bg_selected.9.png b/samples/training/multiscreen/newsreader/res/drawable-hdpi/tab_bg_selected.9.png Binary files differnew file mode 100644 index 000000000..f6873f369 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-hdpi/tab_bg_selected.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-ldpi/button_pressed.9.png b/samples/training/multiscreen/newsreader/res/drawable-ldpi/button_pressed.9.png Binary files differnew file mode 100644 index 000000000..be3414724 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-ldpi/button_pressed.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-ldpi/icon.png b/samples/training/multiscreen/newsreader/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 000000000..4a733c5f1 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-ldpi/icon.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-ldpi/logo.png b/samples/training/multiscreen/newsreader/res/drawable-ldpi/logo.png Binary files differnew file mode 100644 index 000000000..58cc2b78e --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-ldpi/logo.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-ldpi/tab_bg_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-ldpi/tab_bg_normal.9.png Binary files differnew file mode 100644 index 000000000..64eefeaf5 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-ldpi/tab_bg_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-ldpi/tab_bg_selected.9.png b/samples/training/multiscreen/newsreader/res/drawable-ldpi/tab_bg_selected.9.png Binary files differnew file mode 100644 index 000000000..23cbccc13 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-ldpi/tab_bg_selected.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-mdpi/button_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-mdpi/button_normal.9.png Binary files differnew file mode 100644 index 000000000..23733d7ec --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-mdpi/button_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-mdpi/button_pressed.9.png b/samples/training/multiscreen/newsreader/res/drawable-mdpi/button_pressed.9.png Binary files differnew file mode 100644 index 000000000..d228e6006 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-mdpi/button_pressed.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-mdpi/icon.png b/samples/training/multiscreen/newsreader/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 000000000..6b42690d6 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-mdpi/icon.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-mdpi/logo.png b/samples/training/multiscreen/newsreader/res/drawable-mdpi/logo.png Binary files differnew file mode 100644 index 000000000..397f96a5c --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-mdpi/logo.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-mdpi/tab_bg_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-mdpi/tab_bg_normal.9.png Binary files differnew file mode 100644 index 000000000..5406bb303 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-mdpi/tab_bg_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-mdpi/tab_bg_selected.9.png b/samples/training/multiscreen/newsreader/res/drawable-mdpi/tab_bg_selected.9.png Binary files differnew file mode 100644 index 000000000..c6d3a7c33 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-mdpi/tab_bg_selected.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-xhdpi/button_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/button_normal.9.png Binary files differnew file mode 100644 index 000000000..2bd38435b --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/button_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-xhdpi/button_pressed.9.png b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/button_pressed.9.png Binary files differnew file mode 100644 index 000000000..50921cbf4 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/button_pressed.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-xhdpi/icon.png b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/icon.png Binary files differnew file mode 100644 index 000000000..76a886899 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/icon.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-xhdpi/logo.png b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/logo.png Binary files differnew file mode 100644 index 000000000..340016455 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/logo.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-xhdpi/tab_bg_normal.9.png b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/tab_bg_normal.9.png Binary files differnew file mode 100644 index 000000000..028afde86 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/tab_bg_normal.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable-xhdpi/tab_bg_selected.9.png b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/tab_bg_selected.9.png Binary files differnew file mode 100644 index 000000000..5de99e99e --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable-xhdpi/tab_bg_selected.9.png diff --git a/samples/training/multiscreen/newsreader/res/drawable/button_bg.xml b/samples/training/multiscreen/newsreader/res/drawable/button_bg.xml new file mode 100644 index 000000000..cf7b9d58d --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable/button_bg.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" + android:drawable="@drawable/button_pressed" /> + <item android:state_focused="true" + android:drawable="@drawable/button_pressed" /> + <item android:state_selected="true" + android:drawable="@drawable/button_pressed" /> + <item android:drawable="@drawable/button_normal" /> +</selector>
\ No newline at end of file diff --git a/samples/training/multiscreen/newsreader/res/drawable/tab_bg.xml b/samples/training/multiscreen/newsreader/res/drawable/tab_bg.xml new file mode 100644 index 000000000..39a8119a8 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/drawable/tab_bg.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" + android:drawable="@drawable/tab_bg_selected" /> + <item android:drawable="@drawable/tab_bg_normal" /> +</selector> diff --git a/samples/training/multiscreen/newsreader/res/layout/actionbar_list_item.xml b/samples/training/multiscreen/newsreader/res/layout/actionbar_list_item.xml new file mode 100644 index 000000000..452d16b29 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/layout/actionbar_list_item.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="14sp" + android:textColor="#01511a" + android:padding="5dp"> +</TextView> diff --git a/samples/training/multiscreen/newsreader/res/layout/headline_item.xml b/samples/training/multiscreen/newsreader/res/layout/headline_item.xml new file mode 100644 index 000000000..980e43c4e --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/layout/headline_item.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textColor="#01511a" + android:padding="10dp"> +</TextView> diff --git a/samples/training/multiscreen/newsreader/res/layout/onepane.xml b/samples/training/multiscreen/newsreader/res/layout/onepane.xml new file mode 100644 index 000000000..83eeb86a6 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/layout/onepane.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <fragment android:id="@+id/headlines" android:layout_height="fill_parent" + android:name="com.example.android.newsreader.HeadlinesFragment" + android:layout_width="match_parent" /> + +</LinearLayout> diff --git a/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml b/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml new file mode 100644 index 000000000..0ff3a2465 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout android:layout_width="match_parent" android:id="@+id/linearLayout1" android:gravity="center" android:layout_height="50dp"> + <ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/logo" android:paddingRight="30dp" android:layout_gravity="left" android:layout_weight="0"></ImageView> + <View android:layout_height="wrap_content" android:id="@+id/view1" android:layout_width="wrap_content" android:layout_weight="1"></View> + <Button android:id="@+id/categorybutton" android:text="one" android:background="@drawable/button_bg" android:layout_height="match_parent" android:layout_weight="0" android:layout_width="120dp" style="@style/CategoryButtonStyle"/> + </LinearLayout> + + <fragment android:id="@+id/headlines" android:layout_height="fill_parent" + android:name="com.example.android.newsreader.HeadlinesFragment" + android:layout_width="match_parent" /> + +</LinearLayout> diff --git a/samples/training/multiscreen/newsreader/res/layout/twopanes.xml b/samples/training/multiscreen/newsreader/res/layout/twopanes.xml new file mode 100644 index 000000000..96c958acf --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/layout/twopanes.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" android:orientation="horizontal"> + <fragment android:id="@+id/headlines" android:layout_height="fill_parent" + android:name="com.example.android.newsreader.HeadlinesFragment" + android:layout_width="400dp" android:layout_marginRight="10dp"/> + <fragment android:id="@+id/article" android:layout_height="fill_parent" + android:name="com.example.android.newsreader.ArticleFragment" + android:layout_width="fill_parent" /> +</LinearLayout> diff --git a/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml b/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml new file mode 100644 index 000000000..98d951639 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" android:orientation="horizontal"> + <fragment android:id="@+id/headlines" android:layout_height="fill_parent" + android:name="com.example.android.newsreader.HeadlinesFragment" + android:layout_width="200dp" android:layout_marginRight="10dp"/> + <fragment android:id="@+id/article" android:layout_height="fill_parent" + android:name="com.example.android.newsreader.ArticleFragment" + android:layout_width="fill_parent" /> +</LinearLayout> diff --git a/samples/training/multiscreen/newsreader/res/values-sw600dp-land/main.xml b/samples/training/multiscreen/newsreader/res/values-sw600dp-land/main.xml new file mode 100644 index 000000000..85e596673 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values-sw600dp-land/main.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="main_layout" type="layout">@layout/twopanes</item> + <string name="has_two_panes">true</string> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values-sw600dp-port/main.xml b/samples/training/multiscreen/newsreader/res/values-sw600dp-port/main.xml new file mode 100644 index 000000000..4d032dd39 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values-sw600dp-port/main.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="main_layout" type="layout">@layout/onepane</item> + <string name="has_two_panes">false</string> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values-v11/main.xml b/samples/training/multiscreen/newsreader/res/values-v11/main.xml new file mode 100644 index 000000000..cb82bb820 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values-v11/main.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="main_layout" type="layout">@layout/onepane</item> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values-v11/style.xml b/samples/training/multiscreen/newsreader/res/values-v11/style.xml new file mode 100644 index 000000000..566a689e7 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values-v11/style.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> +<style name="CustomActionBarTabTextStyle"> + <item name="android:textColor">#017729</item> + <item name="android:textSize">20sp</item> + <item name="android:typeface">sans</item> +</style> +<style name="CustomActionBarTabStyle" parent="android:style/Widget.Holo.Light.ActionBar.TabView"> + <item name="android:background">@drawable/tab_bg</item> + <item name="android:paddingLeft">20dp</item> + <item name="android:paddingRight">20dp</item> +</style> +<style name="NewsReaderStyle" parent="android:Theme.Holo.Light"> + <item name="android:actionBarTabTextStyle">@style/CustomActionBarTabTextStyle</item> + <item name="android:actionBarTabStyle">@style/CustomActionBarTabStyle</item> +</style> + +<style name="NewsReaderStyle_NoActionBar" parent="android:Theme.Holo.Light.NoActionBar"> +</style> + +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values-xlarge-land/main.xml b/samples/training/multiscreen/newsreader/res/values-xlarge-land/main.xml new file mode 100644 index 000000000..85e596673 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values-xlarge-land/main.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="main_layout" type="layout">@layout/twopanes</item> + <string name="has_two_panes">true</string> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values-xlarge-port/main.xml b/samples/training/multiscreen/newsreader/res/values-xlarge-port/main.xml new file mode 100644 index 000000000..90e6a4a46 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values-xlarge-port/main.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="main_layout" type="layout">@layout/twopanes_narrow</item> + <string name="has_two_panes">true</string> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values/main.xml b/samples/training/multiscreen/newsreader/res/values/main.xml new file mode 100644 index 000000000..c59876243 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values/main.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="main_layout" type="layout">@layout/onepane_with_bar</item> + <string name="has_two_panes">false</string> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values/strings.xml b/samples/training/multiscreen/newsreader/res/values/strings.xml new file mode 100644 index 000000000..e4c4fe26c --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="hello">Hello World, NewsReaderActivity!</string> + <string name="app_name">NewsReader</string> +</resources> diff --git a/samples/training/multiscreen/newsreader/res/values/style.xml b/samples/training/multiscreen/newsreader/res/values/style.xml new file mode 100644 index 000000000..ddbd1c0f3 --- /dev/null +++ b/samples/training/multiscreen/newsreader/res/values/style.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> +<style name="NewsReaderStyle" parent="android:Theme.Light.NoTitleBar"> +</style> + +<style name="NewsReaderStyle_NoActionBar" parent="android:Theme.Light.NoTitleBar"> +</style> + +<style name="CategoryButtonStyle" parent="@android:style/Widget.Button"> + <item name="android:textColor">#ffffff</item> +</style> + +</resources> diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/ArticleActivity.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/ArticleActivity.java new file mode 100644 index 000000000..2aff79236 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/ArticleActivity.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; + +/** + * Activity that displays a particular news article onscreen. + * + * This activity is started only when the screen is not large enough for a two-pane layout, in + * which case this separate activity is shown in order to display the news article. This activity + * kills itself if the display is reconfigured into a shape that allows a two-pane layout, since + * in that case the news article will be displayed by the {@link NewsReaderActivity} and this + * Activity therefore becomes unnecessary. + */ +public class ArticleActivity extends FragmentActivity { + // The news category index and the article index for the article we are to display + int mCatIndex, mArtIndex; + + /** + * Sets up the activity. + * + * Setting up the activity means reading the category/article index from the Intent that + * fired this Activity and loading it onto the UI. We also detect if there has been a + * screen configuration change (in particular, a rotation) that makes this activity + * unnecessary, in which case we do the honorable thing and get out of the way. + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If we are in two-pane layout mode and the device is in landscape orientation, we are + // no longer necessary + if (getResources().getString(R.string.has_two_panes).equals("true") && + getResources().getConfiguration().orientation == + Configuration.ORIENTATION_LANDSCAPE) { + finish(); + return; + } + + // Place an ArticleFragment as our content pane + ArticleFragment f = new ArticleFragment(); + getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit(); + + // Display the correct news article on the fragment + NewsArticle article = NewsSource.getInstance().getCategory(mCatIndex).getArticle(mArtIndex); + f.displayArticle(article); + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/ArticleFragment.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/ArticleFragment.java new file mode 100644 index 000000000..075e54f36 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/ArticleFragment.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebView; + +/** + * Fragment that displays a news article. + */ +public class ArticleFragment extends Fragment { + // The webview where we display the article (our only view) + WebView mWebView; + + // The article we are to display + NewsArticle mNewsArticle = null; + + // Parameterless constructor is needed by framework + public ArticleFragment() { + super(); + } + + /** + * Sets up the UI. It consists if a single WebView. + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + mWebView = new WebView(getActivity()); + loadWebView(); + return mWebView; + } + + /** + * Displays a particular article. + * + * @param article the article to display + */ + public void displayArticle(NewsArticle article) { + mNewsArticle = article; + loadWebView(); + } + + /** + * Loads article data into the webview. + * + * This method is called internally to update the webview's contents to the appropriate + * article's text. + */ + void loadWebView() { + if (mWebView != null) { + mWebView.loadData(mNewsArticle == null ? "" : mNewsArticle.getBody(), "text/html", + "utf-8"); + } + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/CompatActionBarNavHandler.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/CompatActionBarNavHandler.java new file mode 100644 index 000000000..e9bad7e4c --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/CompatActionBarNavHandler.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +import android.app.ActionBar.OnNavigationListener; +import android.app.ActionBar.Tab; +import android.app.ActionBar.TabListener; +import android.app.FragmentTransaction; + +/** + * Adapter for action bar navigation events. + * + * This class implements an adapter that facilitates handling of action bar navigation events. + * An instance of this class must be installed as a TabListener or OnNavigationListener on an + * Action Bar, and it will relay the navigation events to a configured listener + * (a {@link CompatActionBarNavListener}). + * + * This class should only be instanced and used on Android platforms that support the Action Bar, + * that is, SDK level 11 and above. + */ +public class CompatActionBarNavHandler implements TabListener, OnNavigationListener { + // The listener that we notify of navigation events + CompatActionBarNavListener mNavListener; + + /** + * Constructs an instance with the given listener. + * + * @param listener the listener to notify when a navigation event occurs. + */ + public CompatActionBarNavHandler(CompatActionBarNavListener listener) { + mNavListener = listener; + } + + /** + * Called by framework when a tab is selected. + * + * This will cause a navigation event to be delivered to the configured listener. + */ + @Override + public void onTabSelected(Tab tab, FragmentTransaction ft) { + // TODO Auto-generated method stub + mNavListener.onCategorySelected(tab.getPosition()); + } + + /** + * Called by framework when a item on the navigation menu is selected. + * + * This will cause a navigation event to be delivered to the configured listener. + */ + @Override + public boolean onNavigationItemSelected(int itemPosition, long itemId) { + mNavListener.onCategorySelected(itemPosition); + return true; + } + + + /** + * Called by framework when a tab is re-selected. That is, it was already selected and is + * tapped on again. This is not used in our app. + */ + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + // we don't care + } + + /** + * Called by framework when a tab is unselected. Not used in our app. + */ + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + // we don't care + } + +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/CompatActionBarNavListener.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/CompatActionBarNavListener.java new file mode 100644 index 000000000..9a3f933f2 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/CompatActionBarNavListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +/** + * A listener that listens to navigation events. + * + * Represents a listener for navigation events delivered by {@link CompatActionBarNavHandler}. + */ +public interface CompatActionBarNavListener { + /** + * Signals that the given news category was selected. + * @param catIndex the selected category's index. + */ + public void onCategorySelected(int catIndex); +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/HeadlinesFragment.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/HeadlinesFragment.java new file mode 100644 index 000000000..99d02faf8 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/HeadlinesFragment.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fragment that displays the news headlines for a particular news category. + * + * This Fragment displays a list with the news headlines for a particular news category. + * When an item is selected, it notifies the configured listener that a headlines was selected. + */ +public class HeadlinesFragment extends ListFragment implements OnItemClickListener { + // The list of headlines that we are displaying + List<String> mHeadlinesList = new ArrayList<String>(); + + // The list adapter for the list we are displaying + ArrayAdapter<String> mListAdapter; + + // The listener we are to notify when a headline is selected + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /** + * Represents a listener that will be notified of headline selections. + */ + public interface OnHeadlineSelectedListener { + /** + * Called when a given headline is selected. + * @param index the index of the selected headline. + */ + public void onHeadlineSelected(int index); + } + + /** + * Default constructor required by framework. + */ + public HeadlinesFragment() { + super(); + } + + @Override + public void onStart() { + super.onStart(); + setListAdapter(mListAdapter); + getListView().setOnItemClickListener(this); + loadCategory(0); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mListAdapter = new ArrayAdapter<String>(getActivity(), R.layout.headline_item, + mHeadlinesList); + } + + /** + * Sets the listener that should be notified of headline selection events. + * @param listener the listener to notify. + */ + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } + + /** + * Load and display the headlines for the given news category. + * @param categoryIndex the index of the news category to display. + */ + public void loadCategory(int categoryIndex) { + mHeadlinesList.clear(); + int i; + NewsCategory cat = NewsSource.getInstance().getCategory(categoryIndex); + for (i = 0; i < cat.getArticleCount(); i++) { + mHeadlinesList.add(cat.getArticle(i).getHeadline()); + } + mListAdapter.notifyDataSetChanged(); + } + + /** + * Handles a click on a headline. + * + * This causes the configured listener to be notified that a headline was selected. + */ + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + + /** Sets choice mode for the list + * + * @param selectable whether list is to be selectable. + */ + public void setSelectable(boolean selectable) { + if (selectable) { + getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); + } + else { + getListView().setChoiceMode(ListView.CHOICE_MODE_NONE); + } + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsArticle.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsArticle.java new file mode 100644 index 000000000..9feaee265 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsArticle.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +/** + * A news article. + * + * An article consists of a headline and a body. In this example app, article text is dynamically + * generated nonsense. + */ +public class NewsArticle { + // How many sentences in each paragraph? + final int SENTENCES_PER_PARAGRAPH = 20; + + // How many paragraphs in each article? + final int PARAGRAPHS_PER_ARTICLE = 5; + + // Headline and body + String mHeadline, mBody; + + /** + * Create a news article with randomly generated text. + * @param ngen the nonsense generator to use. + */ + public NewsArticle(NonsenseGenerator ngen) { + mHeadline = ngen.makeHeadline(); + + StringBuilder sb = new StringBuilder(); + sb.append("<html><body>"); + sb.append("<h1>" + mHeadline + "</h1>"); + int i; + for (i = 0; i < PARAGRAPHS_PER_ARTICLE; i++) { + sb.append("<p>").append(ngen.makeText(SENTENCES_PER_PARAGRAPH)).append("</p>"); + } + + sb.append("</body></html>"); + mBody = sb.toString(); + } + + /** Returns the headline. */ + public String getHeadline() { + return mHeadline; + } + + /** Returns the article body (HTML)*/ + public String getBody() { + return mBody; + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsCategory.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsCategory.java new file mode 100644 index 000000000..75c7b223a --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsCategory.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +/** + * A news category (collection of articles). + */ +public class NewsCategory { + // how many articles? + final int ARTICLES_PER_CATEGORY = 20; + + // array of our articles + NewsArticle[] mArticles; + + /** + * Create a news category. + * + * The articles are dynamically generated with fun and random nonsense. + */ + public NewsCategory() { + NonsenseGenerator ngen = new NonsenseGenerator(); + mArticles = new NewsArticle[ARTICLES_PER_CATEGORY]; + int i; + for (i = 0; i < mArticles.length; i++) { + mArticles[i] = new NewsArticle(ngen); + } + } + + /** Returns how many articles exist in this category. */ + public int getArticleCount() { + return mArticles.length; + } + + /** Gets a particular article by index. */ + public NewsArticle getArticle(int index) { + return mArticles[index]; + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsReaderActivity.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsReaderActivity.java new file mode 100644 index 000000000..30ae0ae32 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsReaderActivity.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.SpinnerAdapter; + +/** + * Main activity: shows headlines list and articles, if layout permits. + * + * This is the main activity of the application. It can have several different layouts depending + * on the SDK version, screen size and orientation. The configurations are divided in two large + * groups: single-pane layouts and dual-pane layouts. + * + * In single-pane mode, this activity shows a list of headlines using a {@link HeadlinesFragment}. + * When the user clicks on a headline, a separate activity (a {@link ArticleActivity}) is launched + * to show the news article. + * + * In dual-pane mode, this activity shows a {@HeadlinesFragment} on the left side and an + * {@ArticleFragment} on the right side. When the user selects a headline on the left, the + * corresponding article is shown on the right. + * + * If an Action Bar is available (large enough screen and SDK version 11 or up), navigation + * controls are shown in the Action Bar (whether to show tabs or a list depends on the layout). + * If an Action Bar is not available, a regular image and button are shown in the top area of + * the screen, emulating an Action Bar. + */ +public class NewsReaderActivity extends FragmentActivity + implements HeadlinesFragment.OnHeadlineSelectedListener, + CompatActionBarNavListener, + OnClickListener { + + // Whether or not we are in dual-pane mode + boolean mIsDualPane = false; + + // The fragment where the headlines are displayed + HeadlinesFragment mHeadlinesFragment; + + // The fragment where the article is displayed (null if absent) + ArticleFragment mArticleFragment; + + // The news category and article index currently being displayed + int mCatIndex = 0; + int mArtIndex = 0; + NewsCategory mCurrentCat; + + // List of category titles + final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + // find our fragments + mHeadlinesFragment = (HeadlinesFragment) getSupportFragmentManager().findFragmentById( + R.id.headlines); + mArticleFragment = (ArticleFragment) getSupportFragmentManager().findFragmentById( + R.id.article); + + // Determine whether we are in single-pane or dual-pane mode by testing the visibility + // of the article view. + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && articleView.getVisibility() == View.VISIBLE; + + // Register ourselves as the listener for the headlines fragment events. + mHeadlinesFragment.setOnHeadlineSelectedListener(this); + + // Set up the Action Bar (or not, if one is not available) + int catIndex = savedInstanceState == null ? 0 : savedInstanceState.getInt("catIndex", 0); + setUpActionBar(mIsDualPane, catIndex); + + // Set up headlines fragment + mHeadlinesFragment.setSelectable(mIsDualPane); + restoreSelection(savedInstanceState); + + // Set up the category button (shown if an Action Bar is not available) + Button catButton = (Button) findViewById(R.id.categorybutton); + if (catButton != null) { + catButton.setOnClickListener(this); + } + } + + /** Restore category/article selection from saved state. */ + void restoreSelection(Bundle savedInstanceState) { + if (savedInstanceState != null) { + setNewsCategory(savedInstanceState.getInt("catIndex", 0)); + if (mIsDualPane) { + int artIndex = savedInstanceState.getInt("artIndex", 0); + mHeadlinesFragment.setSelection(artIndex); + onHeadlineSelected(artIndex); + } + } + } + + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + restoreSelection(savedInstanceState); + } + + /** Sets up Action Bar (if present). + * + * @param showTabs whether to show tabs (if false, will show list). + * @param selTab the selected tab or list item. + */ + public void setUpActionBar(boolean showTabs, int selTab) { + if (Build.VERSION.SDK_INT < 11) { + // No action bar for you! + // But do not despair. In this case the layout includes a bar across the + // top that looks and feels like an action bar, but is made up of regular views. + return; + } + + android.app.ActionBar actionBar = getActionBar(); + actionBar.setDisplayShowTitleEnabled(false); + + // Set up a CompatActionBarNavHandler to deliver us the Action Bar nagivation events + CompatActionBarNavHandler handler = new CompatActionBarNavHandler(this); + if (showTabs) { + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText(CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, R.layout.actionbar_list_item, + CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } + + // Show logo instead of icon+title. + actionBar.setDisplayUseLogoEnabled(true); + } + + @Override + public void onStart() { + super.onStart(); + setNewsCategory(0); + } + + /** Sets the displayed news category. + * + * This causes the headlines fragment to be repopulated with the appropriate headlines. + */ + void setNewsCategory(int categoryIndex) { + mCatIndex = categoryIndex; + mCurrentCat = NewsSource.getInstance().getCategory(categoryIndex); + mHeadlinesFragment.loadCategory(categoryIndex); + + // If we are displaying the article on the right, we have to update that too + if (mIsDualPane) { + mArticleFragment.displayArticle(mCurrentCat.getArticle(0)); + } + + // If we are displaying a "category" button (on the ActionBar-less UI), we have to update + // its text to reflect the current category. + Button catButton = (Button) findViewById(R.id.categorybutton); + if (catButton != null) { + catButton.setText(CATEGORIES[mCatIndex]); + } + } + + /** Called when a headline is selected. + * + * This is called by the HeadlinesFragment (via its listener interface) to notify us that a + * headline was selected in the Action Bar. The way we react depends on whether we are in + * single or dual-pane mode. In single-pane mode, we launch a new activity to display the + * selected article; in dual-pane mode we simply display it on the article fragment. + * + * @param index the index of the selected headline. + */ + @Override + public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + // display it on the article fragment + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } + else { + // use separate activity + Intent i = new Intent(this, ArticleActivity.class); + i.putExtra("catIndex", mCatIndex); + i.putExtra("artIndex", index); + startActivity(i); + } + } + + /** Called when a news category is selected. + * + * This is called by our CompatActionBarNavHandler in response to the user selecting a + * news category in the Action Bar. We react by loading and displaying the headlines for + * that category. + * + * @param catIndex the index of the selected news category. + */ + @Override + public void onCategorySelected(int catIndex) { + setNewsCategory(catIndex); + } + + /** Save instance state. Saves current category/article index. */ + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putInt("catIndex", mCatIndex); + outState.putInt("artIndex", mArtIndex); + super.onSaveInstanceState(outState); + } + + /** Called when news category button is clicked. + * + * This is the button that we display on UIs that don't have an action bar. This button + * calls up a list of news categories and switches to the given category. + */ + @Override + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Select a Category"); + builder.setItems(CATEGORIES, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + setNewsCategory(which); + } + }); + AlertDialog d = builder.create(); + d.show(); + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsSource.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsSource.java new file mode 100644 index 000000000..18cbe8b37 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NewsSource.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; + +/** + * Source of strange and wonderful news. + * + * This singleton functions as the repository for the news we display. + */ +public class NewsSource { + // the instance + static NewsSource instance = null; + + // the category names + final String[] CATEGORIES = { "Top Stories", "US", "Politics", "Economy" }; + + // category objects, representing each category + NewsCategory[] mCategory; + + /** Returns the singleton instance of this class. */ + public static NewsSource getInstance() { + if (instance == null) { + instance = new NewsSource(); + } + return instance; + } + + public NewsSource() { + int i; + mCategory = new NewsCategory[CATEGORIES.length]; + for (i = 0; i < CATEGORIES.length; i++) { + mCategory[i] = new NewsCategory(); + } + } + + /** Returns the list of news categories. */ + public String[] getCategories() { + return CATEGORIES; + } + + /** Returns a category by index. */ + public NewsCategory getCategory(int categoryIndex) { + return mCategory[categoryIndex]; + } +} diff --git a/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NonsenseGenerator.java b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NonsenseGenerator.java new file mode 100644 index 000000000..e38b77769 --- /dev/null +++ b/samples/training/multiscreen/newsreader/src/com/example/android/newsreader/NonsenseGenerator.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.newsreader; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** Generator of random news. More fun than "lorem ipsum", isn't it? + * + * This generator can construct headlines and news articles by randomly composing sentences. + * Any resemblance to actual events (or, actually, any resemblance to anything that makes sense) + * is merely coincidental! + */ +public class NonsenseGenerator { + Random mRandom; + + static final String[] THINGS = { "bottle", "bowl", "brick", "building", + "bunny", "cake", "car", "cat", "cup", "desk", "dog", "duck", + "elephant", "engineer", "fork", "glass", "griffon", "hat", "key", "knife", "lawyer", + "llama", "manual", "meat", "monitor", "mouse", "tangerine", "paper", "pear", "pen", + "pencil", "phone", "physicist", "planet", "potato", "road", "salad", "shoe", "slipper", + "soup", "spoon", "star", "steak", "table", "terminal", "treehouse", "truck", + "watermelon", "window" }; + + static final String[] ADJECTIVES = { "red", "green", "yellow", "gray", "solid", "fierce", + "friendly", "cowardly", "convenient", "foreign", "national", "tall", + "short", "metallic", "golden", "silver", "sweet", "nationwide", "competitive", + "stable", "municipal", "famous" }; + + static final String[] VERBS_PAST = { "accused", "threatened", "warned", "spoke to", + "has met with", + "was seen in the company of", "advanced towards", "collapsed on", + "signed a partnership with", "was converted into", "became", "was authorized to sell", + "sold", "bought", "rented", "allegedly spoke to", "leased", "is now investing on", + "is expected to buy", "is expected to sell", "was reported to have met with", + "will work together with", "plans to cease fire against", "started a war with", + "signed a truce with", "is now managing", "is investigating" }; + + static final String[] VERBS_PRESENT = { "accuses", "threatens", "warns", "speaks to", + "meets with", + "seen with", "advances towards", "collapses on", + "signs partnership with", "converts into", "becomes", "is authorized to sell", + "sells", "buys", "rents", "allegedly speaks to", "leases", "invests on", + "expected to buy", "expected to sell", "reported to have met with", + "works together with", "plans cease fire against", "starts war with", + "signs truce with", "now manages" }; + + public NonsenseGenerator() { + mRandom = new Random(); + } + + /** Produces something that reads like a headline. */ + public String makeHeadline() { + return makeSentence(true); + } + + /** Produces a sentence. + * + * @param isHeadline whether the sentence should look like a headline or not. + * @return the generated sentence. + */ + public String makeSentence(boolean isHeadline) { + List<String> words = new ArrayList<String>(); + generateSentence(words, isHeadline); + words.set(0, String.valueOf(Character.toUpperCase(words.get(0).charAt(0))) + + words.get(0).substring(1)); + return joinWords(words); + } + + /** Produces news article text. + * + * @param numSentences how many sentences the text is to contain. + * @return the generated text. + */ + public String makeText(int numSentences) { + StringBuilder sb = new StringBuilder(); + while (numSentences-- > 0) { + sb.append(makeSentence(false) + "."); + if (numSentences > 0) { + sb.append(" "); + } + } + return sb.toString(); + } + + /** Generates a sentence. + * + * @param words the list of words to which the sentence will be appended. + * @param isHeadline whether the sentence must look like a headline or not. + */ + private void generateSentence(List<String> words, boolean isHeadline) { + if (!isHeadline && mRandom.nextInt(4) == 0) + generateTimeClause(words, isHeadline); + generateAgent(words, isHeadline); + generatePredicate(words, isHeadline); + } + + private void generateTimeClause(List<String> words, boolean isHeadline) { + if (mRandom.nextInt(2) == 0) { + words.add(pickOneOf("today", "yesterday", "this afternoon", "this morning", + "last evening")); + } + else { + words.add(pickOneOf("this", "last")); + words.add(pickOneOf("Monday", "Tuesday", "Wednesday", "Thursday")); + words.add(pickOneOf("morning", "afternoon", "evening")); + } + } + + private void generateAgent(List<String> words, boolean isHeadline) { + if (!isHeadline) { + words.add(pickOneOf("a", "the")); + } + if (mRandom.nextInt(3) != 0) { + words.add(pickOneOf(ADJECTIVES)); + } + words.add(pickOneOf(THINGS)); + } + + private void generatePredicate(List<String> words, boolean isHeadline) { + words.add(pickOneOf(isHeadline ? VERBS_PRESENT : VERBS_PAST)); + if (!isHeadline) + words.add(pickOneOf("a", "the")); + if (mRandom.nextInt(3) != 0) { + words.add(pickOneOf(ADJECTIVES)); + } + words.add(pickOneOf(THINGS)); + + if (mRandom.nextInt(3) == 0) { + words.add(isHeadline ? pickOneOf(", claims", ", says") : + pickOneOf(", claimed", ", said", ", reported")); + if (!isHeadline) + words.add(pickOneOf("a", "the")); + if (mRandom.nextInt(3) != 0) { + words.add(pickOneOf(ADJECTIVES)); + } + words.add(pickOneOf(THINGS)); + } + } + + private String pickOneOf(String ... options) { + return options[mRandom.nextInt(options.length)]; + } + + private static String joinWords(List<String> words) { + int i; + if (words.size() == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(); + sb.append(words.get(0)); + for (i = 1; i < words.size(); i++) { + if (!words.get(i).startsWith(",")) { + sb.append(" "); + } + sb.append(words.get(i)); + } + return sb.toString(); + } +} |
