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