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