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
This commit is contained in:
Bruno Oliveira
2011-10-26 13:38:47 -04:00
committed by Scott Main
parent 6c8a38a780
commit 4ea24bff40
53 changed files with 1486 additions and 0 deletions

View 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>

View 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 *;
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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/twopanes</item>
<string name="has_two_panes">true</string>
</resources>

View 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</item>
<string name="has_two_panes">false</string>
</resources>

View File

@@ -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>

View File

@@ -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>

View 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/twopanes</item>
<string name="has_two_panes">true</string>
</resources>

View 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/twopanes_narrow</item>
<string name="has_two_panes">true</string>
</resources>

View 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>

View 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>
<string name="hello">Hello World, NewsReaderActivity!</string>
<string name="app_name">NewsReader</string>
</resources>

View 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>

View File

@@ -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);
}
}

View File

@@ -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");
}
}
}

View File

@@ -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
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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];
}
}

View File

@@ -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();
}
}

View File

@@ -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];
}
}

View File

@@ -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();
}
}