DetailsSupportFragment.java revision 0908efd712e79f77e0cf9307bd5c32753c855561
1// CHECKSTYLE:OFF Generated code 2/* This file is auto-generated from DetailsFragment.java. DO NOT MODIFY. */ 3 4/* 5 * Copyright (C) 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 8 * in compliance with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed under the License 13 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 14 * or implied. See the License for the specific language governing permissions and limitations under 15 * the License. 16 */ 17package android.support.v17.leanback.app; 18 19import android.support.v4.app.Fragment; 20import android.support.v4.app.FragmentTransaction; 21import android.os.Bundle; 22import android.support.v17.leanback.R; 23import android.support.v17.leanback.transition.TransitionHelper; 24import android.support.v17.leanback.widget.BaseOnItemViewClickedListener; 25import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener; 26import android.support.v17.leanback.widget.BrowseFrameLayout; 27import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter; 28import android.support.v17.leanback.widget.ItemAlignmentFacet; 29import android.support.v17.leanback.widget.ItemBridgeAdapter; 30import android.support.v17.leanback.widget.ObjectAdapter; 31import android.support.v17.leanback.widget.Presenter; 32import android.support.v17.leanback.widget.PresenterSelector; 33import android.support.v17.leanback.widget.RowPresenter; 34import android.support.v17.leanback.widget.VerticalGridView; 35import android.util.Log; 36import android.view.KeyEvent; 37import android.view.LayoutInflater; 38import android.view.View; 39import android.view.ViewGroup; 40 41/** 42 * A fragment for creating Leanback details screens. 43 * 44 * <p> 45 * A DetailsSupportFragment renders the elements of its {@link ObjectAdapter} as a set 46 * of rows in a vertical list.The Adapter's {@link PresenterSelector} must maintain subclasses 47 * of {@link RowPresenter}. 48 * </p> 49 * 50 * When {@link FullWidthDetailsOverviewRowPresenter} is found in adapter, DetailsSupportFragment will 51 * setup default behavior of the DetailsOverviewRow: 52 * <li> 53 * The alignment of FullWidthDetailsOverviewRowPresenter is setup in 54 * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}. 55 * </li> 56 * <li> 57 * The view status switching of FullWidthDetailsOverviewRowPresenter is done in 58 * {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter, 59 * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)}. 60 * </li> 61 * 62 * <p> 63 * The recommended activity themes to use with a DetailsSupportFragment are 64 * <li> 65 * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details} with activity 66 * shared element transition for {@link FullWidthDetailsOverviewRowPresenter}. 67 * </li> 68 * <li> 69 * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details_NoSharedElementTransition} 70 * if shared element transition is not needed, for example if first row is not rendered by 71 * {@link FullWidthDetailsOverviewRowPresenter}. 72 * </li> 73 * </p> 74 */ 75public class DetailsSupportFragment extends BaseSupportFragment { 76 static final String TAG = "DetailsSupportFragment"; 77 static boolean DEBUG = false; 78 79 private class SetSelectionRunnable implements Runnable { 80 int mPosition; 81 boolean mSmooth = true; 82 83 SetSelectionRunnable() { 84 } 85 86 @Override 87 public void run() { 88 if (mRowsSupportFragment == null) { 89 return; 90 } 91 mRowsSupportFragment.setSelectedPosition(mPosition, mSmooth); 92 } 93 } 94 95 BrowseFrameLayout mRootView; 96 Fragment mVideoSupportFragment; 97 DetailsParallaxManager mDetailsParallaxManager; 98 RowsSupportFragment mRowsSupportFragment; 99 ObjectAdapter mAdapter; 100 int mContainerListAlignTop; 101 BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener; 102 BaseOnItemViewClickedListener mOnItemViewClickedListener; 103 104 Object mSceneAfterEntranceTransition; 105 106 final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable(); 107 108 final BaseOnItemViewSelectedListener<Object> mOnItemViewSelectedListener = 109 new BaseOnItemViewSelectedListener<Object>() { 110 @Override 111 public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, 112 RowPresenter.ViewHolder rowViewHolder, Object row) { 113 int position = mRowsSupportFragment.getVerticalGridView().getSelectedPosition(); 114 int subposition = mRowsSupportFragment.getVerticalGridView().getSelectedSubPosition(); 115 if (DEBUG) Log.v(TAG, "row selected position " + position 116 + " subposition " + subposition); 117 onRowSelected(position, subposition); 118 if (mExternalOnItemViewSelectedListener != null) { 119 mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item, 120 rowViewHolder, row); 121 } 122 } 123 }; 124 125 /** 126 * Sets the list of rows for the fragment. 127 */ 128 public void setAdapter(ObjectAdapter adapter) { 129 mAdapter = adapter; 130 Presenter[] presenters = adapter.getPresenterSelector().getPresenters(); 131 if (presenters != null) { 132 for (int i = 0; i < presenters.length; i++) { 133 setupPresenter(presenters[i]); 134 } 135 } else { 136 Log.e(TAG, "PresenterSelector.getPresenters() not implemented"); 137 } 138 if (mRowsSupportFragment != null) { 139 mRowsSupportFragment.setAdapter(adapter); 140 } 141 } 142 143 /** 144 * Returns the list of rows. 145 */ 146 public ObjectAdapter getAdapter() { 147 return mAdapter; 148 } 149 150 /** 151 * Sets an item selection listener. 152 */ 153 public void setOnItemViewSelectedListener(BaseOnItemViewSelectedListener listener) { 154 mExternalOnItemViewSelectedListener = listener; 155 } 156 157 /** 158 * Sets an item clicked listener. 159 */ 160 public void setOnItemViewClickedListener(BaseOnItemViewClickedListener listener) { 161 if (mOnItemViewClickedListener != listener) { 162 mOnItemViewClickedListener = listener; 163 if (mRowsSupportFragment != null) { 164 mRowsSupportFragment.setOnItemViewClickedListener(listener); 165 } 166 } 167 } 168 169 /** 170 * Returns the item clicked listener. 171 */ 172 public BaseOnItemViewClickedListener getOnItemViewClickedListener() { 173 return mOnItemViewClickedListener; 174 } 175 176 @Override 177 public void onCreate(Bundle savedInstanceState) { 178 super.onCreate(savedInstanceState); 179 mContainerListAlignTop = 180 getResources().getDimensionPixelSize(R.dimen.lb_details_rows_align_top); 181 } 182 183 @Override 184 public View onCreateView(LayoutInflater inflater, ViewGroup container, 185 Bundle savedInstanceState) { 186 mRootView = (BrowseFrameLayout) inflater.inflate( 187 R.layout.lb_details_fragment, container, false); 188 mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager().findFragmentById( 189 R.id.details_rows_dock); 190 if (mRowsSupportFragment == null) { 191 mRowsSupportFragment = new RowsSupportFragment(); 192 getChildFragmentManager().beginTransaction() 193 .replace(R.id.details_rows_dock, mRowsSupportFragment).commit(); 194 } 195 mRowsSupportFragment.setAdapter(mAdapter); 196 mRowsSupportFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener); 197 mRowsSupportFragment.setOnItemViewClickedListener(mOnItemViewClickedListener); 198 199 mSceneAfterEntranceTransition = TransitionHelper.createScene(mRootView, new Runnable() { 200 @Override 201 public void run() { 202 mRowsSupportFragment.setEntranceTransitionState(true); 203 } 204 }); 205 206 setupVideoPlayback(); 207 208 return mRootView; 209 } 210 211 212 /** 213 * @deprecated override {@link #onInflateTitleView(LayoutInflater,ViewGroup,Bundle)} instead. 214 */ 215 @Deprecated 216 protected View inflateTitle(LayoutInflater inflater, ViewGroup parent, 217 Bundle savedInstanceState) { 218 return super.onInflateTitleView(inflater, parent, savedInstanceState); 219 } 220 221 @Override 222 public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent, 223 Bundle savedInstanceState) { 224 return inflateTitle(inflater, parent, savedInstanceState); 225 } 226 227 void setVerticalGridViewLayout(VerticalGridView listview) { 228 // align the top edge of item to a fixed position 229 listview.setItemAlignmentOffset(-mContainerListAlignTop); 230 listview.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 231 listview.setWindowAlignmentOffset(0); 232 listview.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 233 listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 234 } 235 236 /** 237 * Called to setup each Presenter of Adapter passed in {@link #setAdapter(ObjectAdapter)}.Note 238 * that setup should only change the Presenter behavior that is meaningful in DetailsSupportFragment. 239 * For example how a row is aligned in details Fragment. The default implementation invokes 240 * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)} 241 * 242 */ 243 protected void setupPresenter(Presenter rowPresenter) { 244 if (rowPresenter instanceof FullWidthDetailsOverviewRowPresenter) { 245 setupDetailsOverviewRowPresenter((FullWidthDetailsOverviewRowPresenter) rowPresenter); 246 } 247 } 248 249 /** 250 * Called to setup {@link FullWidthDetailsOverviewRowPresenter}. The default implementation 251 * adds two alignment positions({@link ItemAlignmentFacet}) for ViewHolder of 252 * FullWidthDetailsOverviewRowPresenter to align in fragment. 253 */ 254 protected void setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter presenter) { 255 ItemAlignmentFacet facet = new ItemAlignmentFacet(); 256 // by default align details_frame to half window height 257 ItemAlignmentFacet.ItemAlignmentDef alignDef1 = new ItemAlignmentFacet.ItemAlignmentDef(); 258 alignDef1.setItemAlignmentViewId(R.id.details_frame); 259 alignDef1.setItemAlignmentOffset(- getResources() 260 .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions)); 261 alignDef1.setItemAlignmentOffsetPercent(0); 262 // when description is selected, align details_frame to top edge 263 ItemAlignmentFacet.ItemAlignmentDef alignDef2 = new ItemAlignmentFacet.ItemAlignmentDef(); 264 alignDef2.setItemAlignmentViewId(R.id.details_frame); 265 alignDef2.setItemAlignmentFocusViewId(R.id.details_overview_description); 266 alignDef2.setItemAlignmentOffset(- getResources() 267 .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description)); 268 alignDef2.setItemAlignmentOffsetPercent(0); 269 ItemAlignmentFacet.ItemAlignmentDef[] defs = 270 new ItemAlignmentFacet.ItemAlignmentDef[] {alignDef1, alignDef2}; 271 facet.setAlignmentDefs(defs); 272 presenter.setFacet(ItemAlignmentFacet.class, facet); 273 } 274 275 VerticalGridView getVerticalGridView() { 276 return mRowsSupportFragment == null ? null : mRowsSupportFragment.getVerticalGridView(); 277 } 278 279 /** 280 * Gets embedded RowsSupportFragment showing multiple rows for DetailsSupportFragment. If view of 281 * DetailsSupportFragment is not created, the method returns null. 282 * @return Embedded RowsSupportFragment showing multiple rows for DetailsSupportFragment. 283 */ 284 public RowsSupportFragment getRowsSupportFragment() { 285 return mRowsSupportFragment; 286 } 287 288 /** 289 * Setup dimensions that are only meaningful when the child Fragments are inside 290 * DetailsSupportFragment. 291 */ 292 private void setupChildFragmentLayout() { 293 setVerticalGridViewLayout(mRowsSupportFragment.getVerticalGridView()); 294 } 295 296 /** 297 * Sets the selected row position with smooth animation. 298 */ 299 public void setSelectedPosition(int position) { 300 setSelectedPosition(position, true); 301 } 302 303 /** 304 * Sets the selected row position. 305 */ 306 public void setSelectedPosition(int position, boolean smooth) { 307 mSetSelectionRunnable.mPosition = position; 308 mSetSelectionRunnable.mSmooth = smooth; 309 if (getView() != null && getView().getHandler() != null) { 310 getView().getHandler().post(mSetSelectionRunnable); 311 } 312 } 313 314 /** 315 * Creates an instance of {@link VideoSupportFragment}. Subclasses can override this method 316 * and provide their own instance of a {@link Fragment}. When you provide your own instance of 317 * video fragment, you MUST also provide a custom 318 * {@link android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost}. 319 */ 320 public Fragment onCreateVideoSupportFragment() { 321 return new VideoSupportFragment(); 322 } 323 324 /** 325 * Creates an instance of 326 * {@link android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost}. The implementation 327 * of this host depends on the instance of video fragment {@link #onCreateVideoSupportFragment()}. 328 */ 329 public PlaybackGlue.PlaybackGlueHost onCreateVideoSupportFragmentHost(Fragment fragment) { 330 return new VideoSupportFragmentGlueHost((VideoSupportFragment) fragment); 331 } 332 333 /** 334 * This method adds a fragment for rendering video to the layout. In case the 335 * fragment is being restored, it will return the video fragment in there. 336 * 337 * @return Fragment the added or restored fragment responsible for rendering video. 338 */ 339 public final Fragment findOrCreateVideoSupportFragment() { 340 Fragment fragment = getFragmentManager().findFragmentById(R.id.video_surface_container); 341 if (fragment == null) { 342 FragmentTransaction ft2 = getFragmentManager().beginTransaction(); 343 ft2.add(android.support.v17.leanback.R.id.video_surface_container, 344 fragment = onCreateVideoSupportFragment()); 345 ft2.commit(); 346 } 347 mVideoSupportFragment = fragment; 348 return mVideoSupportFragment; 349 } 350 351 /** 352 * This method initializes a video fragment, create an instance of 353 * {@link android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost} using that fragment 354 * and return it. 355 */ 356 public final PlaybackGlue.PlaybackGlueHost createPlaybackGlueHost() { 357 Fragment fragment = findOrCreateVideoSupportFragment(); 358 return onCreateVideoSupportFragmentHost(fragment); 359 } 360 361 void onRowSelected(int selectedPosition, int selectedSubPosition) { 362 ObjectAdapter adapter = getAdapter(); 363 if (adapter == null || adapter.size() == 0 364 || (selectedPosition == 0 && selectedSubPosition == 0)) { 365 showTitle(true); 366 } else { 367 showTitle(false); 368 } 369 if (adapter != null && adapter.size() > selectedPosition) { 370 final VerticalGridView gridView = getVerticalGridView(); 371 final int count = gridView.getChildCount(); 372 for (int i = 0; i < count; i++) { 373 ItemBridgeAdapter.ViewHolder bridgeViewHolder = (ItemBridgeAdapter.ViewHolder) 374 gridView.getChildViewHolder(gridView.getChildAt(i)); 375 RowPresenter rowPresenter = (RowPresenter) bridgeViewHolder.getPresenter(); 376 onSetRowStatus(rowPresenter, 377 rowPresenter.getRowViewHolder(bridgeViewHolder.getViewHolder()), 378 bridgeViewHolder.getAdapterPosition(), 379 selectedPosition, selectedSubPosition); 380 } 381 } 382 } 383 384 /** 385 * Called on every visible row to change view status when current selected row position 386 * or selected sub position changed. Subclass may override. The default 387 * implementation calls {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter, 388 * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)} if presenter is 389 * instance of {@link FullWidthDetailsOverviewRowPresenter}. 390 * 391 * @param presenter The presenter used to create row ViewHolder. 392 * @param viewHolder The visible (attached) row ViewHolder, note that it may or may not 393 * be selected. 394 * @param adapterPosition The adapter position of viewHolder inside adapter. 395 * @param selectedPosition The adapter position of currently selected row. 396 * @param selectedSubPosition The sub position within currently selected row. This is used 397 * When a row has multiple alignment positions. 398 */ 399 protected void onSetRowStatus(RowPresenter presenter, RowPresenter.ViewHolder viewHolder, int 400 adapterPosition, int selectedPosition, int selectedSubPosition) { 401 if (presenter instanceof FullWidthDetailsOverviewRowPresenter) { 402 onSetDetailsOverviewRowStatus((FullWidthDetailsOverviewRowPresenter) presenter, 403 (FullWidthDetailsOverviewRowPresenter.ViewHolder) viewHolder, 404 adapterPosition, selectedPosition, selectedSubPosition); 405 } 406 } 407 408 /** 409 * Called to change DetailsOverviewRow view status when current selected row position 410 * or selected sub position changed. Subclass may override. The default 411 * implementation switches between three states based on the positions: 412 * {@link FullWidthDetailsOverviewRowPresenter#STATE_HALF}, 413 * {@link FullWidthDetailsOverviewRowPresenter#STATE_FULL} and 414 * {@link FullWidthDetailsOverviewRowPresenter#STATE_SMALL}. 415 * 416 * @param presenter The presenter used to create row ViewHolder. 417 * @param viewHolder The visible (attached) row ViewHolder, note that it may or may not 418 * be selected. 419 * @param adapterPosition The adapter position of viewHolder inside adapter. 420 * @param selectedPosition The adapter position of currently selected row. 421 * @param selectedSubPosition The sub position within currently selected row. This is used 422 * When a row has multiple alignment positions. 423 */ 424 protected void onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter presenter, 425 FullWidthDetailsOverviewRowPresenter.ViewHolder viewHolder, int adapterPosition, 426 int selectedPosition, int selectedSubPosition) { 427 if (selectedPosition > adapterPosition) { 428 presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF); 429 } else if (selectedPosition == adapterPosition && selectedSubPosition == 1) { 430 presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF); 431 } else if (selectedPosition == adapterPosition && selectedSubPosition == 0){ 432 presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_FULL); 433 } else { 434 presenter.setState(viewHolder, 435 FullWidthDetailsOverviewRowPresenter.STATE_SMALL); 436 } 437 } 438 439 @Override 440 public void onStart() { 441 super.onStart(); 442 setupChildFragmentLayout(); 443 if (isEntranceTransitionEnabled()) { 444 mRowsSupportFragment.setEntranceTransitionState(false); 445 } 446 if (mDetailsParallaxManager != null) { 447 mDetailsParallaxManager.setRecyclerView(mRowsSupportFragment.getVerticalGridView()); 448 } 449 mRowsSupportFragment.getVerticalGridView().requestFocus(); 450 } 451 452 @Override 453 protected Object createEntranceTransition() { 454 return TransitionHelper.loadTransition(getActivity(), 455 R.transition.lb_details_enter_transition); 456 } 457 458 @Override 459 protected void runEntranceTransition(Object entranceTransition) { 460 TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition); 461 } 462 463 @Override 464 protected void onEntranceTransitionEnd() { 465 mRowsSupportFragment.onTransitionEnd(); 466 } 467 468 @Override 469 protected void onEntranceTransitionPrepare() { 470 mRowsSupportFragment.onTransitionPrepare(); 471 } 472 473 @Override 474 protected void onEntranceTransitionStart() { 475 mRowsSupportFragment.onTransitionStart(); 476 } 477 478 /** 479 * Create a DetailsParallaxManager that will be used to configure parallax effect of background 480 * and start/stop Video playback. Subclass may override. 481 * 482 * @return The new created DetailsParallaxManager. 483 * @see #getParallaxManager() 484 */ 485 public DetailsParallaxManager onCreateParallaxManager() { 486 return new DetailsParallaxManager(); 487 } 488 489 /** 490 * Returns the {@link DetailsParallaxManager} instance used to configure parallax effect of 491 * background. 492 * 493 * @return The DetailsParallaxManager instance attached to the DetailsSupportFragment. 494 * @see #onCreateParallaxManager() 495 */ 496 public DetailsParallaxManager getParallaxManager() { 497 if (mDetailsParallaxManager == null) { 498 mDetailsParallaxManager = onCreateParallaxManager(); 499 if (mRowsSupportFragment != null) { 500 mDetailsParallaxManager.setRecyclerView(mRowsSupportFragment.getVerticalGridView()); 501 } 502 } 503 return mDetailsParallaxManager; 504 } 505 506 /** 507 * Returns background View that above VideoSupportFragment. App can set a background drawable to this 508 * view to hide the VideoSupportFragment before it is ready to play. 509 * 510 * @see #findOrCreateVideoSupportFragment() 511 */ 512 public View getBackgroundView() { 513 return mRootView == null ? null : mRootView.findViewById(R.id.details_background_view); 514 } 515 516 /** 517 * This method does the following 518 * <ul> 519 * <li>sets up focus search handling logic in the root view to enable transitioning between 520 * half screen/full screen/no video mode.</li> 521 * 522 * <li>Sets up the key listener in the root view to intercept events like UP/DOWN and 523 * transition to appropriate mode like half/full screen video.</li> 524 * </ul> 525 */ 526 void setupVideoPlayback() { 527 mRootView.setOnFocusSearchListener(new BrowseFrameLayout.OnFocusSearchListener() { 528 @Override 529 public View onFocusSearch(View focused, int direction) { 530 if (mVideoSupportFragment == null) { 531 return null; 532 } 533 if (mRowsSupportFragment.getVerticalGridView() != null 534 && mRowsSupportFragment.getVerticalGridView().hasFocus()) { 535 if (direction == View.FOCUS_UP) { 536 slideOutGridView(); 537 return mVideoSupportFragment.getView(); 538 } 539 } else if (mVideoSupportFragment.getView() != null 540 && mVideoSupportFragment.getView().hasFocus()) { 541 if (direction == View.FOCUS_DOWN) { 542 slideInGridView(); 543 return mRowsSupportFragment.getVerticalGridView(); 544 } 545 } 546 return focused; 547 } 548 }); 549 550 // If we press BACK or DOWN on remote while in full screen video mode, we should 551 // transition back to half screen video playback mode. 552 mRootView.setOnDispatchKeyListener(new View.OnKeyListener() { 553 @Override 554 public boolean onKey(View v, int keyCode, KeyEvent event) { 555 // This is used to check if we are in full screen video mode. This is somewhat 556 // hacky and relies on the behavior of the video helper class to update the 557 // focusability of the video surface view. 558 if (mVideoSupportFragment != null && mVideoSupportFragment.getView() != null 559 && mVideoSupportFragment.getView().hasFocus()) { 560 if (keyCode == KeyEvent.KEYCODE_BACK) { 561 slideInGridView(); 562 getVerticalGridView().requestFocus(); 563 return true; 564 } 565 } 566 567 return false; 568 } 569 }); 570 } 571 572 /** 573 * Slides vertical grid view (displaying media item details) out of the screen from below. 574 */ 575 void slideOutGridView() { 576 getVerticalGridView().animateOut(); 577 } 578 579 /** 580 * Slides in vertical grid view (displaying media item details) from below. 581 */ 582 void slideInGridView() { 583 getVerticalGridView().animateIn(); 584 } 585} 586