cherrypick from master cl Change-Id: I45f91fd9cfe0cb89789017deec63565e4757063e
Adding the NewsReader sample. This sample demonstrates how to design a UI for multiple screens and is part of the "Designing for Multiple Screens" AndroidU lesson. Change-Id: I462261933c68b3a40f9611fcf7153c25abdfcd5d
40
samples/training/multiscreen/newsreader/AndroidManifest.xml
Normal file
@@ -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>
|
||||
40
samples/training/multiscreen/newsreader/proguard.cfg
Normal file
@@ -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 *;
|
||||
}
|
||||
11
samples/training/multiscreen/newsreader/project.properties
Normal file
@@ -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
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 246 B |
|
After Width: | Height: | Size: 598 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 137 B |
|
After Width: | Height: | Size: 377 B |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 250 B |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 429 B |
|
After Width: | Height: | Size: 389 B |
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
20
samples/training/multiscreen/newsreader/res/values/main.xml
Normal file
@@ -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>
|
||||
@@ -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>
|
||||
28
samples/training/multiscreen/newsreader/res/values/style.xml
Normal file
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||