1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.newsreader;
18 
19 import android.app.AlertDialog;
20 import android.content.DialogInterface;
21 import android.content.Intent;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.support.v4.app.FragmentActivity;
25 import android.view.View;
26 import android.view.View.OnClickListener;
27 import android.widget.ArrayAdapter;
28 import android.widget.Button;
29 import android.widget.SpinnerAdapter;
30 
31 /**
32  * Main activity: shows headlines list and articles, if layout permits.
33  *
34  * This is the main activity of the application. It can have several different layouts depending
35  * on the SDK version, screen size and orientation. The configurations are divided in two large
36  * groups: single-pane layouts and dual-pane layouts.
37  *
38  * In single-pane mode, this activity shows a list of headlines using a {@link HeadlinesFragment}.
39  * When the user clicks on a headline, a separate activity (a {@link ArticleActivity}) is launched
40  * to show the news article.
41  *
42  * In dual-pane mode, this activity shows a {@HeadlinesFragment} on the left side and an
43  * {@ArticleFragment} on the right side. When the user selects a headline on the left, the
44  * corresponding article is shown on the right.
45  *
46  * If an Action Bar is available (large enough screen and SDK version 11 or up), navigation
47  * controls are shown in the Action Bar (whether to show tabs or a list depends on the layout).
48  * If an Action Bar is not available, a regular image and button are shown in the top area of
49  * the screen, emulating an Action Bar.
50  */
51 public class NewsReaderActivity extends FragmentActivity
52         implements HeadlinesFragment.OnHeadlineSelectedListener,
53                    CompatActionBarNavListener,
54                    OnClickListener  {
55 
56     // Whether or not we are in dual-pane mode
57     boolean mIsDualPane = false;
58 
59     // The fragment where the headlines are displayed
60     HeadlinesFragment mHeadlinesFragment;
61 
62     // The fragment where the article is displayed (null if absent)
63     ArticleFragment mArticleFragment;
64 
65     // The news category and article index currently being displayed
66     int mCatIndex = 0;
67     int mArtIndex = 0;
68     NewsCategory mCurrentCat;
69 
70     // List of category titles
71     final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" };
72 
73     @Override
onCreate(Bundle savedInstanceState)74     public void onCreate(Bundle savedInstanceState) {
75         super.onCreate(savedInstanceState);
76         setContentView(R.layout.main_layout);
77 
78         // find our fragments
79         mHeadlinesFragment = (HeadlinesFragment) getSupportFragmentManager().findFragmentById(
80                 R.id.headlines);
81         mArticleFragment = (ArticleFragment) getSupportFragmentManager().findFragmentById(
82                 R.id.article);
83 
84         // Determine whether we are in single-pane or dual-pane mode by testing the visibility
85         // of the article view.
86         View articleView = findViewById(R.id.article);
87         mIsDualPane = articleView != null && articleView.getVisibility() == View.VISIBLE;
88 
89         // Register ourselves as the listener for the headlines fragment events.
90         mHeadlinesFragment.setOnHeadlineSelectedListener(this);
91 
92         // Set up the Action Bar (or not, if one is not available)
93         int catIndex = savedInstanceState == null ? 0 : savedInstanceState.getInt("catIndex", 0);
94         setUpActionBar(mIsDualPane, catIndex);
95 
96         // Set up headlines fragment
97         mHeadlinesFragment.setSelectable(mIsDualPane);
98         restoreSelection(savedInstanceState);
99 
100         // Set up the category button (shown if an Action Bar is not available)
101         Button catButton = (Button) findViewById(R.id.categorybutton);
102         if (catButton != null) {
103             catButton.setOnClickListener(this);
104         }
105     }
106 
107     /** Restore category/article selection from saved state. */
restoreSelection(Bundle savedInstanceState)108     void restoreSelection(Bundle savedInstanceState) {
109         if (savedInstanceState != null) {
110             setNewsCategory(savedInstanceState.getInt("catIndex", 0));
111             if (mIsDualPane) {
112                 int artIndex = savedInstanceState.getInt("artIndex", 0);
113                 mHeadlinesFragment.setSelection(artIndex);
114                 onHeadlineSelected(artIndex);
115             }
116         }
117     }
118 
119     @Override
onRestoreInstanceState(Bundle savedInstanceState)120     public void onRestoreInstanceState(Bundle savedInstanceState) {
121         restoreSelection(savedInstanceState);
122     }
123 
124     /** Sets up Action Bar (if present).
125      *
126      * @param showTabs whether to show tabs (if false, will show list).
127      * @param selTab the selected tab or list item.
128      */
setUpActionBar(boolean showTabs, int selTab)129     public void setUpActionBar(boolean showTabs, int selTab) {
130         if (Build.VERSION.SDK_INT < 11) {
131             // No action bar for you!
132             // But do not despair. In this case the layout includes a bar across the
133             // top that looks and feels like an action bar, but is made up of regular views.
134             return;
135         }
136 
137         android.app.ActionBar actionBar = getActionBar();
138         actionBar.setDisplayShowTitleEnabled(false);
139 
140         // Set up a CompatActionBarNavHandler to deliver us the Action Bar nagivation events
141         CompatActionBarNavHandler handler = new CompatActionBarNavHandler(this);
142         if (showTabs) {
143             actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS);
144             int i;
145             for (i = 0; i < CATEGORIES.length; i++) {
146                 actionBar.addTab(actionBar.newTab().setText(CATEGORIES[i]).setTabListener(handler));
147             }
148             actionBar.setSelectedNavigationItem(selTab);
149         }
150         else {
151             actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST);
152             SpinnerAdapter adap = new ArrayAdapter<String>(this, R.layout.actionbar_list_item,
153                     CATEGORIES);
154             actionBar.setListNavigationCallbacks(adap, handler);
155         }
156 
157         // Show logo instead of icon+title.
158         actionBar.setDisplayUseLogoEnabled(true);
159     }
160 
161     @Override
onStart()162     public void onStart() {
163         super.onStart();
164         setNewsCategory(0);
165     }
166 
167     /** Sets the displayed news category.
168      *
169      * This causes the headlines fragment to be repopulated with the appropriate headlines.
170      */
setNewsCategory(int categoryIndex)171     void setNewsCategory(int categoryIndex) {
172         mCatIndex = categoryIndex;
173         mCurrentCat = NewsSource.getInstance().getCategory(categoryIndex);
174         mHeadlinesFragment.loadCategory(categoryIndex);
175 
176         // If we are displaying the article on the right, we have to update that too
177         if (mIsDualPane) {
178             mArticleFragment.displayArticle(mCurrentCat.getArticle(0));
179         }
180 
181         // If we are displaying a "category" button (on the ActionBar-less UI), we have to update
182         // its text to reflect the current category.
183         Button catButton = (Button) findViewById(R.id.categorybutton);
184         if (catButton != null) {
185             catButton.setText(CATEGORIES[mCatIndex]);
186         }
187     }
188 
189     /** Called when a headline is selected.
190      *
191      * This is called by the HeadlinesFragment (via its listener interface) to notify us that a
192      * headline was selected in the Action Bar. The way we react depends on whether we are in
193      * single or dual-pane mode. In single-pane mode, we launch a new activity to display the
194      * selected article; in dual-pane mode we simply display it on the article fragment.
195      *
196      * @param index the index of the selected headline.
197      */
198     @Override
onHeadlineSelected(int index)199     public void onHeadlineSelected(int index) {
200         mArtIndex = index;
201         if (mIsDualPane) {
202             // display it on the article fragment
203             mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
204         }
205         else {
206             // use separate activity
207             Intent i = new Intent(this, ArticleActivity.class);
208             i.putExtra("catIndex", mCatIndex);
209             i.putExtra("artIndex", index);
210             startActivity(i);
211         }
212     }
213 
214     /** Called when a news category is selected.
215      *
216      * This is called by our CompatActionBarNavHandler in response to the user selecting a
217      * news category in the Action Bar. We react by loading and displaying the headlines for
218      * that category.
219      *
220      * @param catIndex the index of the selected news category.
221      */
222     @Override
onCategorySelected(int catIndex)223     public void onCategorySelected(int catIndex) {
224         setNewsCategory(catIndex);
225     }
226 
227     /** Save instance state. Saves current category/article index. */
228     @Override
onSaveInstanceState(Bundle outState)229     protected void onSaveInstanceState(Bundle outState) {
230         outState.putInt("catIndex", mCatIndex);
231         outState.putInt("artIndex", mArtIndex);
232         super.onSaveInstanceState(outState);
233     }
234 
235     /** Called when news category button is clicked.
236      *
237      * This is the button that we display on UIs that don't have an action bar. This button
238      * calls up a list of news categories and switches to the given category.
239      */
240     @Override
onClick(View v)241     public void onClick(View v) {
242         AlertDialog.Builder builder = new AlertDialog.Builder(this);
243         builder.setTitle("Select a Category");
244         builder.setItems(CATEGORIES, new DialogInterface.OnClickListener() {
245             @Override
246             public void onClick(DialogInterface dialog, int which) {
247                 setNewsCategory(which);
248             }
249         });
250         AlertDialog d = builder.create();
251         d.show();
252     }
253 }
254