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
17package com.example.android.newsreader;
18
19import android.app.AlertDialog;
20import android.content.DialogInterface;
21import android.content.Intent;
22import android.os.Build;
23import android.os.Bundle;
24import android.support.v4.app.FragmentActivity;
25import android.view.View;
26import android.view.View.OnClickListener;
27import android.widget.ArrayAdapter;
28import android.widget.Button;
29import 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 */
51public 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
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. */
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
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     */
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
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     */
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
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
223    public void onCategorySelected(int catIndex) {
224        setNewsCategory(catIndex);
225    }
226
227    /** Save instance state. Saves current category/article index. */
228    @Override
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
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