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