ActionBarActivity.java revision c4b9e0cb716a4caff218b27d86f37ef8117d257b
1/* 2 * Copyright (C) 2012 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 android.support.v7.app; 18 19import android.app.Activity; 20import android.content.Intent; 21import android.content.res.Configuration; 22import android.os.Bundle; 23import android.support.annotation.LayoutRes; 24import android.support.annotation.Nullable; 25import android.support.v4.app.ActionBarDrawerToggle; 26import android.support.v4.app.ActivityCompat; 27import android.support.v4.app.FragmentActivity; 28import android.support.v4.app.NavUtils; 29import android.support.v4.app.TaskStackBuilder; 30import android.support.v4.view.WindowCompat; 31import android.support.v7.view.ActionMode; 32import android.support.v7.widget.Toolbar; 33import android.view.KeyEvent; 34import android.view.Menu; 35import android.view.MenuInflater; 36import android.view.View; 37import android.view.ViewGroup; 38import android.view.Window; 39 40/** 41 * Base class for activities that use the <a 42 * href="{@docRoot}tools/extras/support-library.html">support library</a> action bar features. 43 * 44 * <p>You can add an {@link ActionBar} to your activity when running on API level 7 or higher 45 * by extending this class for your activity and setting the activity theme to 46 * {@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} or a similar theme. 47 * 48 * <div class="special reference"> 49 * <h3>Developer Guides</h3> 50 * 51 * <p>For information about how to use the action bar, including how to add action items, navigation 52 * modes and more, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action 53 * Bar</a> API guide.</p> 54 * </div> 55 */ 56public class ActionBarActivity extends FragmentActivity implements ActionBar.Callback, 57 TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider, 58 android.support.v7.app.ActionBarDrawerToggle.TmpDelegateProvider { 59 60 private ActionBarActivityDelegate mDelegate; 61 62 /** 63 * Support library version of {@link Activity#getActionBar}. 64 * 65 * <p>Retrieve a reference to this activity's ActionBar. 66 * 67 * @return The Activity's ActionBar, or null if it does not have one. 68 */ 69 public ActionBar getSupportActionBar() { 70 return getDelegate().getSupportActionBar(); 71 } 72 73 /** 74 * Set a {@link android.widget.Toolbar Toolbar} to act as the {@link ActionBar} for this 75 * Activity window. 76 * 77 * <p>When set to a non-null value the {@link #getActionBar()} method will return 78 * an {@link ActionBar} object that can be used to control the given toolbar as if it were 79 * a traditional window decor action bar. The toolbar's menu will be populated with the 80 * Activity's options menu and the navigation button will be wired through the standard 81 * {@link android.R.id#home home} menu select action.</p> 82 * 83 * <p>In order to use a Toolbar within the Activity's window content the application 84 * must not request the window feature {@link Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p> 85 * 86 * @param toolbar Toolbar to set as the Activity's action bar 87 */ 88 public void setSupportActionBar(@Nullable Toolbar toolbar) { 89 getDelegate().setSupportActionBar(toolbar); 90 } 91 92 @Override 93 public MenuInflater getMenuInflater() { 94 return getDelegate().getMenuInflater(); 95 } 96 97 @Override 98 public void setContentView(@LayoutRes int layoutResID) { 99 getDelegate().setContentView(layoutResID); 100 } 101 102 @Override 103 public void setContentView(View view) { 104 getDelegate().setContentView(view); 105 } 106 107 @Override 108 public void setContentView(View view, ViewGroup.LayoutParams params) { 109 getDelegate().setContentView(view, params); 110 } 111 112 @Override 113 public void addContentView(View view, ViewGroup.LayoutParams params) { 114 getDelegate().addContentView(view, params); 115 } 116 117 @Override 118 protected void onCreate(Bundle savedInstanceState) { 119 super.onCreate(savedInstanceState); 120 getDelegate().onCreate(savedInstanceState); 121 } 122 123 @Override 124 public void onConfigurationChanged(Configuration newConfig) { 125 super.onConfigurationChanged(newConfig); 126 getDelegate().onConfigurationChanged(newConfig); 127 } 128 129 @Override 130 protected void onStop() { 131 super.onStop(); 132 getDelegate().onStop(); 133 } 134 135 @Override 136 protected void onPostResume() { 137 super.onPostResume(); 138 getDelegate().onPostResume(); 139 } 140 141 @Override 142 public View onCreatePanelView(int featureId) { 143 if (featureId == Window.FEATURE_OPTIONS_PANEL) { 144 return getDelegate().onCreatePanelView(featureId); 145 } else { 146 return super.onCreatePanelView(featureId); 147 } 148 } 149 150 @Override 151 public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) { 152 if (super.onMenuItemSelected(featureId, item)) { 153 return true; 154 } 155 156 final ActionBar ab = getSupportActionBar(); 157 if (item.getItemId() == android.R.id.home && ab != null && 158 (ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) { 159 return onSupportNavigateUp(); 160 } 161 return false; 162 } 163 164 @Override 165 protected void onTitleChanged(CharSequence title, int color) { 166 super.onTitleChanged(title, color); 167 getDelegate().onTitleChanged(title); 168 } 169 170 /** 171 * Enable extended support library window features. 172 * <p> 173 * This is a convenience for calling 174 * {@link android.view.Window#requestFeature getWindow().requestFeature()}. 175 * </p> 176 * 177 * @param featureId The desired feature as defined in 178 * {@link android.view.Window} or {@link WindowCompat}. 179 * @return Returns true if the requested feature is supported and now enabled. 180 * 181 * @see android.app.Activity#requestWindowFeature 182 * @see android.view.Window#requestFeature 183 */ 184 public boolean supportRequestWindowFeature(int featureId) { 185 return getDelegate().supportRequestWindowFeature(featureId); 186 } 187 188 @Override 189 public void supportInvalidateOptionsMenu() { 190 getDelegate().supportInvalidateOptionsMenu(); 191 } 192 193 /** 194 * @hide 195 */ 196 public void invalidateOptionsMenu() { 197 getDelegate().supportInvalidateOptionsMenu(); 198 } 199 200 /** 201 * Notifies the Activity that a support action mode has been started. 202 * Activity subclasses overriding this method should call the superclass implementation. 203 * 204 * @param mode The new action mode. 205 */ 206 public void onSupportActionModeStarted(ActionMode mode) { 207 } 208 209 /** 210 * Notifies the activity that a support action mode has finished. 211 * Activity subclasses overriding this method should call the superclass implementation. 212 * 213 * @param mode The action mode that just finished. 214 */ 215 public void onSupportActionModeFinished(ActionMode mode) { 216 } 217 218 public ActionMode startSupportActionMode(ActionMode.Callback callback) { 219 return getDelegate().startSupportActionMode(callback); 220 } 221 222 @Override 223 public boolean onCreatePanelMenu(int featureId, Menu menu) { 224 return getDelegate().onCreatePanelMenu(featureId, menu); 225 } 226 227 @Override 228 public boolean onPreparePanel(int featureId, View view, Menu menu) { 229 return getDelegate().onPreparePanel(featureId, view, menu); 230 } 231 232 @Override 233 public void onPanelClosed(int featureId, Menu menu) { 234 getDelegate().onPanelClosed(featureId, menu); 235 } 236 237 @Override 238 public boolean onMenuOpened(int featureId, Menu menu) { 239 return getDelegate().onMenuOpened(featureId, menu); 240 } 241 242 /** 243 * @hide 244 */ 245 @Override 246 protected boolean onPrepareOptionsPanel(View view, Menu menu) { 247 return getDelegate().onPrepareOptionsPanel(view, menu); 248 } 249 250 void superSetContentView(int resId) { 251 super.setContentView(resId); 252 } 253 254 void superSetContentView(View v) { 255 super.setContentView(v); 256 } 257 258 void superSetContentView(View v, ViewGroup.LayoutParams lp) { 259 super.setContentView(v, lp); 260 } 261 262 void superAddContentView(View v, ViewGroup.LayoutParams lp) { 263 super.addContentView(v, lp); 264 } 265 266 boolean superOnCreatePanelMenu(int featureId, android.view.Menu frameworkMenu) { 267 return super.onCreatePanelMenu(featureId, frameworkMenu); 268 } 269 270 boolean superOnPreparePanel(int featureId, View view, android.view.Menu menu) { 271 return super.onPreparePanel(featureId, view, menu); 272 } 273 274 boolean superOnPrepareOptionsPanel(View view, Menu menu) { 275 return super.onPrepareOptionsPanel(view, menu); 276 } 277 278 void superOnPanelClosed(int featureId, Menu menu) { 279 super.onPanelClosed(featureId, menu); 280 } 281 282 boolean superOnMenuOpened(int featureId, Menu menu) { 283 return super.onMenuOpened(featureId, menu); 284 } 285 286 @Override 287 public void onBackPressed() { 288 if (!getDelegate().onBackPressed()) { 289 super.onBackPressed(); 290 } 291 } 292 293 /** 294 * Support library version of {@link Activity#setProgressBarVisibility(boolean)} 295 * <p> 296 * Sets the visibility of the progress bar in the title. 297 * <p> 298 * In order for the progress bar to be shown, the feature must be requested 299 * via {@link #supportRequestWindowFeature(int)}. 300 * 301 * @param visible Whether to show the progress bars in the title. 302 */ 303 public void setSupportProgressBarVisibility(boolean visible) { 304 getDelegate().setSupportProgressBarVisibility(visible); 305 } 306 307 /** 308 * Support library version of {@link Activity#setProgressBarIndeterminateVisibility(boolean)} 309 * <p> 310 * Sets the visibility of the indeterminate progress bar in the title. 311 * <p> 312 * In order for the progress bar to be shown, the feature must be requested 313 * via {@link #supportRequestWindowFeature(int)}. 314 * 315 * @param visible Whether to show the progress bars in the title. 316 */ 317 public void setSupportProgressBarIndeterminateVisibility(boolean visible) { 318 getDelegate().setSupportProgressBarIndeterminateVisibility(visible); 319 } 320 321 /** 322 * Support library version of {@link Activity#setProgressBarIndeterminate(boolean)} 323 * <p> 324 * Sets whether the horizontal progress bar in the title should be indeterminate (the 325 * circular is always indeterminate). 326 * <p> 327 * In order for the progress bar to be shown, the feature must be requested 328 * via {@link #supportRequestWindowFeature(int)}. 329 * 330 * @param indeterminate Whether the horizontal progress bar should be indeterminate. 331 */ 332 public void setSupportProgressBarIndeterminate(boolean indeterminate) { 333 getDelegate().setSupportProgressBarIndeterminate(indeterminate); 334 } 335 336 /** 337 * Support library version of {@link Activity#setProgress(int)}. 338 * <p> 339 * Sets the progress for the progress bars in the title. 340 * <p> 341 * In order for the progress bar to be shown, the feature must be requested 342 * via {@link #supportRequestWindowFeature(int)}. 343 * 344 * @param progress The progress for the progress bar. Valid ranges are from 345 * 0 to 10000 (both inclusive). If 10000 is given, the progress 346 * bar will be completely filled and will fade out. 347 */ 348 public void setSupportProgress(int progress) { 349 getDelegate().setSupportProgress(progress); 350 } 351 352 /** 353 * Support version of {@link #onCreateNavigateUpTaskStack(android.app.TaskStackBuilder)}. 354 * This method will be called on all platform versions. 355 * 356 * Define the synthetic task stack that will be generated during Up navigation from 357 * a different task. 358 * 359 * <p>The default implementation of this method adds the parent chain of this activity 360 * as specified in the manifest to the supplied {@link TaskStackBuilder}. Applications 361 * may choose to override this method to construct the desired task stack in a different 362 * way.</p> 363 * 364 * <p>This method will be invoked by the default implementation of {@link #onNavigateUp()} 365 * if {@link #shouldUpRecreateTask(Intent)} returns true when supplied with the intent 366 * returned by {@link #getParentActivityIntent()}.</p> 367 * 368 * <p>Applications that wish to supply extra Intent parameters to the parent stack defined 369 * by the manifest should override 370 * {@link #onPrepareSupportNavigateUpTaskStack(TaskStackBuilder)}.</p> 371 * 372 * @param builder An empty TaskStackBuilder - the application should add intents representing 373 * the desired task stack 374 */ 375 public void onCreateSupportNavigateUpTaskStack(TaskStackBuilder builder) { 376 builder.addParentStack(this); 377 } 378 379 /** 380 * Support version of {@link #onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder)}. 381 * This method will be called on all platform versions. 382 * 383 * Prepare the synthetic task stack that will be generated during Up navigation 384 * from a different task. 385 * 386 * <p>This method receives the {@link TaskStackBuilder} with the constructed series of 387 * Intents as generated by {@link #onCreateSupportNavigateUpTaskStack(TaskStackBuilder)}. 388 * If any extra data should be added to these intents before launching the new task, 389 * the application should override this method and add that data here.</p> 390 * 391 * @param builder A TaskStackBuilder that has been populated with Intents by 392 * onCreateNavigateUpTaskStack. 393 */ 394 public void onPrepareSupportNavigateUpTaskStack(TaskStackBuilder builder) { 395 } 396 397 /** 398 * This method is called whenever the user chooses to navigate Up within your application's 399 * activity hierarchy from the action bar. 400 * 401 * <p>If a parent was specified in the manifest for this activity or an activity-alias to it, 402 * default Up navigation will be handled automatically. See 403 * {@link #getSupportParentActivityIntent()} for how to specify the parent. If any activity 404 * along the parent chain requires extra Intent arguments, the Activity subclass 405 * should override the method {@link #onPrepareSupportNavigateUpTaskStack(TaskStackBuilder)} 406 * to supply those arguments.</p> 407 * 408 * <p>See <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and 409 * Back Stack</a> from the developer guide and 410 * <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> from the design guide 411 * for more information about navigating within your app.</p> 412 * 413 * <p>See the {@link TaskStackBuilder} class and the Activity methods 414 * {@link #getSupportParentActivityIntent()}, {@link #supportShouldUpRecreateTask(Intent)}, and 415 * {@link #supportNavigateUpTo(Intent)} for help implementing custom Up navigation.</p> 416 * 417 * @return true if Up navigation completed successfully and this Activity was finished, 418 * false otherwise. 419 */ 420 public boolean onSupportNavigateUp() { 421 Intent upIntent = getSupportParentActivityIntent(); 422 423 if (upIntent != null) { 424 if (supportShouldUpRecreateTask(upIntent)) { 425 TaskStackBuilder b = TaskStackBuilder.create(this); 426 onCreateSupportNavigateUpTaskStack(b); 427 onPrepareSupportNavigateUpTaskStack(b); 428 b.startActivities(); 429 430 try { 431 ActivityCompat.finishAffinity(this); 432 } catch (IllegalStateException e) { 433 // This can only happen on 4.1+, when we don't have a parent or a result set. 434 // In that case we should just finish(). 435 finish(); 436 } 437 } else { 438 // This activity is part of the application's task, so simply 439 // navigate up to the hierarchical parent activity. 440 supportNavigateUpTo(upIntent); 441 } 442 return true; 443 } 444 return false; 445 } 446 447 /** 448 * Obtain an {@link Intent} that will launch an explicit target activity 449 * specified by sourceActivity's {@link NavUtils#PARENT_ACTIVITY} <meta-data> 450 * element in the application's manifest. If the device is running 451 * Jellybean or newer, the android:parentActivityName attribute will be preferred 452 * if it is present. 453 * 454 * @return a new Intent targeting the defined parent activity of sourceActivity 455 */ 456 public Intent getSupportParentActivityIntent() { 457 return NavUtils.getParentActivityIntent(this); 458 } 459 460 /** 461 * Returns true if sourceActivity should recreate the task when navigating 'up' 462 * by using targetIntent. 463 * 464 * <p>If this method returns false the app can trivially call 465 * {@link #supportNavigateUpTo(Intent)} using the same parameters to correctly perform 466 * up navigation. If this method returns false, the app should synthesize a new task stack 467 * by using {@link TaskStackBuilder} or another similar mechanism to perform up navigation.</p> 468 * 469 * @param targetIntent An intent representing the target destination for up navigation 470 * @return true if navigating up should recreate a new task stack, false if the same task 471 * should be used for the destination 472 */ 473 public boolean supportShouldUpRecreateTask(Intent targetIntent) { 474 return NavUtils.shouldUpRecreateTask(this, targetIntent); 475 } 476 477 /** 478 * Navigate from sourceActivity to the activity specified by upIntent, finishing sourceActivity 479 * in the process. upIntent will have the flag {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} set 480 * by this method, along with any others required for proper up navigation as outlined 481 * in the Android Design Guide. 482 * 483 * <p>This method should be used when performing up navigation from within the same task 484 * as the destination. If up navigation should cross tasks in some cases, see 485 * {@link #supportShouldUpRecreateTask(Intent)}.</p> 486 * 487 * @param upIntent An intent representing the target destination for up navigation 488 */ 489 public void supportNavigateUpTo(Intent upIntent) { 490 NavUtils.navigateUpTo(this, upIntent); 491 } 492 493 @Override 494 public final ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() { 495 return getDelegate().getDrawerToggleDelegate(); 496 } 497 498 @Nullable 499 @Override 500 /** 501 * Temporary method until ActionBarDrawerToggle transition from v4 to v7 is complete. 502 */ 503 public android.support.v7.app.ActionBarDrawerToggle.Delegate getV7DrawerToggleDelegate() { 504 return getDelegate().getV7DrawerToggleDelegate(); 505 } 506 507 @Override 508 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 509 return getDelegate().onKeyShortcut(keyCode, event); 510 } 511 512 @Override 513 public boolean onKeyDown(int keyCode, KeyEvent event) { 514 // First let the Activity try and handle it (for back, etc) 515 if (super.onKeyDown(keyCode, event)) { 516 return true; 517 } 518 return getDelegate().onKeyDown(keyCode, event); 519 } 520 521 /** 522 * Use {@link #onSupportContentChanged()} instead. 523 */ 524 public final void onContentChanged() { 525 getDelegate().onContentChanged(); 526 } 527 528 /** 529 * This hook is called whenever the content view of the screen changes. 530 * @see android.app.Activity#onContentChanged() 531 */ 532 public void onSupportContentChanged() { 533 } 534 535 private ActionBarActivityDelegate getDelegate() { 536 if (mDelegate == null) { 537 mDelegate = ActionBarActivityDelegate.createDelegate(this); 538 } 539 return mDelegate; 540 } 541} 542