PlaybackOverlaySupportFragment.java revision 61905b0b52c50018dcaebcd79699c39b8f28d622
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.app; 15 16import android.graphics.Color; 17import android.graphics.drawable.ColorDrawable; 18import android.animation.Animator; 19import android.animation.AnimatorInflater; 20import android.animation.TimeInterpolator; 21import android.animation.ValueAnimator; 22import android.view.animation.AccelerateInterpolator; 23import android.animation.ValueAnimator.AnimatorUpdateListener; 24import android.content.Context; 25import android.os.Bundle; 26import android.os.Handler; 27import android.os.Message; 28import android.support.v7.widget.RecyclerView; 29import android.support.v17.leanback.R; 30import android.support.v17.leanback.animation.LogAccelerateInterpolator; 31import android.support.v17.leanback.animation.LogDecelerateInterpolator; 32import android.support.v17.leanback.widget.Presenter; 33import android.support.v17.leanback.widget.ItemBridgeAdapter; 34import android.support.v17.leanback.widget.ObjectAdapter; 35import android.support.v17.leanback.widget.ObjectAdapter.DataObserver; 36import android.support.v17.leanback.widget.VerticalGridView; 37import android.support.v17.leanback.widget.PlaybackControlsRowPresenter; 38import android.util.Log; 39import android.view.KeyEvent; 40import android.view.LayoutInflater; 41import android.view.MotionEvent; 42import android.view.View; 43import android.view.ViewGroup; 44import android.view.ViewGroup.MarginLayoutParams; 45import android.view.animation.Interpolator; 46import android.view.animation.LinearInterpolator; 47 48import java.util.ArrayList; 49 50/** 51 * A fragment for displaying playback controls and related content. 52 * The {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be 53 * at position 0 in the adapter. 54 */ 55public class PlaybackOverlaySupportFragment extends DetailsSupportFragment { 56 57 /** 58 * No background. 59 */ 60 public static final int BG_NONE = 0; 61 62 /** 63 * A dark translucent background. 64 */ 65 public static final int BG_DARK = 1; 66 67 /** 68 * A light translucent background. 69 */ 70 public static final int BG_LIGHT = 2; 71 72 public static class OnFadeCompleteListener { 73 public void onFadeInComplete() { 74 } 75 public void onFadeOutComplete() { 76 } 77 } 78 79 private static final String TAG = "PlaybackOverlaySupportFragment"; 80 private static final boolean DEBUG = false; 81 private static final int ANIMATION_MULTIPLIER = 1; 82 83 private static int START_FADE_OUT = 1; 84 85 // Fading status 86 private static final int IDLE = 0; 87 private static final int IN = 1; 88 private static final int OUT = 2; 89 90 private int mAlignPosition; 91 private int mPaddingBottom; 92 private View mRootView; 93 private int mBackgroundType = BG_DARK; 94 private int mBgDarkColor; 95 private int mBgLightColor; 96 private int mShowTimeMs; 97 private int mMajorFadeTranslateY, mMinorFadeTranslateY; 98 private int mAnimationTranslateY; 99 private OnFadeCompleteListener mFadeCompleteListener; 100 private boolean mFadingEnabled = true; 101 private int mFadingStatus = IDLE; 102 private int mBgAlpha; 103 private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator; 104 private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator; 105 private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator; 106 private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator; 107 private boolean mTranslateAnimationEnabled; 108 private boolean mResetControlsToPrimaryActionsPending; 109 private RecyclerView.ItemAnimator mItemAnimator; 110 111 private final Animator.AnimatorListener mFadeListener = 112 new Animator.AnimatorListener() { 113 @Override 114 public void onAnimationStart(Animator animation) { 115 enableVerticalGridAnimations(false); 116 } 117 @Override 118 public void onAnimationRepeat(Animator animation) { 119 } 120 @Override 121 public void onAnimationCancel(Animator animation) { 122 } 123 @Override 124 public void onAnimationEnd(Animator animation) { 125 if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha); 126 if (mBgAlpha > 0) { 127 enableVerticalGridAnimations(true); 128 startFadeTimer(); 129 if (mFadeCompleteListener != null) { 130 mFadeCompleteListener.onFadeInComplete(); 131 } 132 } else { 133 if (getVerticalGridView() != null) { 134 // Reset focus to the controls row 135 getVerticalGridView().setSelectedPosition(0); 136 resetControlsToPrimaryActions(null); 137 } 138 if (mFadeCompleteListener != null) { 139 mFadeCompleteListener.onFadeOutComplete(); 140 } 141 } 142 mFadingStatus = IDLE; 143 } 144 }; 145 146 private final Handler mHandler = new Handler() { 147 @Override 148 public void handleMessage(Message message) { 149 if (message.what == START_FADE_OUT && mFadingEnabled) { 150 fade(false); 151 } 152 } 153 }; 154 155 private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener = 156 new VerticalGridView.OnTouchInterceptListener() { 157 public boolean onInterceptTouchEvent(MotionEvent event) { 158 return onInterceptInputEvent(); 159 } 160 }; 161 162 private final VerticalGridView.OnMotionInterceptListener mOnMotionInterceptListener = 163 new VerticalGridView.OnMotionInterceptListener() { 164 public boolean onInterceptMotionEvent(MotionEvent event) { 165 return onInterceptInputEvent(); 166 } 167 }; 168 169 private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener = 170 new VerticalGridView.OnKeyInterceptListener() { 171 public boolean onInterceptKeyEvent(KeyEvent event) { 172 return onInterceptInputEvent(); 173 } 174 }; 175 176 private void setBgAlpha(int alpha) { 177 mBgAlpha = alpha; 178 if (mRootView != null) { 179 mRootView.getBackground().setAlpha(alpha); 180 } 181 } 182 183 private void enableVerticalGridAnimations(boolean enable) { 184 if (getVerticalGridView() != null) { 185 getVerticalGridView().setAnimateChildLayout(enable); 186 } 187 } 188 189 private void resetControlsToPrimaryActions(ItemBridgeAdapter.ViewHolder vh) { 190 if (vh == null && getVerticalGridView() != null) { 191 vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().findViewHolderForPosition(0); 192 } 193 if (vh == null) { 194 mResetControlsToPrimaryActionsPending = true; 195 } else if (vh.getPresenter() instanceof PlaybackControlsRowPresenter) { 196 mResetControlsToPrimaryActionsPending = false; 197 ((PlaybackControlsRowPresenter) vh.getPresenter()).showPrimaryActions( 198 (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder()); 199 } 200 } 201 202 /** 203 * Enables or disables view fading. If enabled, 204 * the view will be faded in when the fragment starts, 205 * and will fade out after a time period. The timeout 206 * period is reset each time {@link #tickle} is called. 207 * 208 */ 209 public void setFadingEnabled(boolean enabled) { 210 if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled); 211 if (enabled != mFadingEnabled) { 212 mFadingEnabled = enabled; 213 if (isResumed()) { 214 if (mFadingEnabled) { 215 if (mFadingStatus == IDLE && !mHandler.hasMessages(START_FADE_OUT)) { 216 startFadeTimer(); 217 } 218 } else { 219 // Ensure fully opaque 220 mHandler.removeMessages(START_FADE_OUT); 221 fade(true); 222 } 223 } 224 } 225 } 226 227 /** 228 * Returns true if view fading is enabled. 229 */ 230 public boolean isFadingEnabled() { 231 return mFadingEnabled; 232 } 233 234 /** 235 * Sets the listener to be called when fade in or out has completed. 236 */ 237 public void setFadeCompleteListener(OnFadeCompleteListener listener) { 238 mFadeCompleteListener = listener; 239 } 240 241 /** 242 * Returns the listener to be called when fade in or out has completed. 243 */ 244 public OnFadeCompleteListener getFadeCompleteListener() { 245 return mFadeCompleteListener; 246 } 247 248 /** 249 * Tickles the playback controls. Fades in the view if it was faded out, 250 * otherwise resets the fade out timer. Tickling on input events is handled 251 * by the fragment. 252 */ 253 public void tickle() { 254 if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed()); 255 if (!mFadingEnabled || !isResumed()) { 256 return; 257 } 258 if (mHandler.hasMessages(START_FADE_OUT)) { 259 // Restart the timer 260 startFadeTimer(); 261 } else { 262 fade(true); 263 } 264 } 265 266 private boolean onInterceptInputEvent() { 267 if (DEBUG) Log.v(TAG, "onInterceptInputEvent status " + mFadingStatus); 268 boolean consumeEvent = (mFadingStatus == IDLE && mBgAlpha == 0); 269 tickle(); 270 return consumeEvent; 271 } 272 273 @Override 274 public void onResume() { 275 super.onResume(); 276 if (mFadingEnabled) { 277 setBgAlpha(0); 278 fade(true); 279 } 280 getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener); 281 getVerticalGridView().setOnMotionInterceptListener(mOnMotionInterceptListener); 282 getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener); 283 } 284 285 private void startFadeTimer() { 286 if (mHandler != null) { 287 mHandler.removeMessages(START_FADE_OUT); 288 mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs); 289 } 290 } 291 292 private static ValueAnimator loadAnimator(Context context, int resId) { 293 ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId); 294 animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER); 295 return animator; 296 } 297 298 private void loadBgAnimator() { 299 AnimatorUpdateListener listener = new AnimatorUpdateListener() { 300 @Override 301 public void onAnimationUpdate(ValueAnimator arg0) { 302 setBgAlpha((Integer) arg0.getAnimatedValue()); 303 } 304 }; 305 306 mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in); 307 mBgFadeInAnimator.addUpdateListener(listener); 308 mBgFadeInAnimator.addListener(mFadeListener); 309 310 mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out); 311 mBgFadeOutAnimator.addUpdateListener(listener); 312 mBgFadeOutAnimator.addListener(mFadeListener); 313 } 314 315 private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0); 316 private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0); 317 318 private View getControlRowView() { 319 if (getVerticalGridView() == null) { 320 return null; 321 } 322 RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0); 323 if (vh == null) { 324 return null; 325 } 326 return vh.itemView; 327 } 328 329 private void loadControlRowAnimator() { 330 final AnimatorListener listener = new AnimatorListener() { 331 @Override 332 void getViews(ArrayList<View> views) { 333 View view = getControlRowView(); 334 if (view != null) { 335 views.add(view); 336 } 337 } 338 }; 339 final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { 340 @Override 341 public void onAnimationUpdate(ValueAnimator arg0) { 342 View view = getControlRowView(); 343 if (view != null) { 344 final float fraction = (Float) arg0.getAnimatedValue(); 345 if (DEBUG) Log.v(TAG, "fraction " + fraction); 346 view.setAlpha(fraction); 347 view.setTranslationY((float) mAnimationTranslateY * (1f - fraction)); 348 } 349 } 350 }; 351 352 mControlRowFadeInAnimator = loadAnimator( 353 getActivity(), R.animator.lb_playback_controls_fade_in); 354 mControlRowFadeInAnimator.addUpdateListener(updateListener); 355 mControlRowFadeInAnimator.addListener(listener); 356 mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 357 358 mControlRowFadeOutAnimator = loadAnimator( 359 getActivity(), R.animator.lb_playback_controls_fade_out); 360 mControlRowFadeOutAnimator.addUpdateListener(updateListener); 361 mControlRowFadeOutAnimator.addListener(listener); 362 mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator); 363 } 364 365 private void loadOtherRowAnimator() { 366 final AnimatorListener listener = new AnimatorListener() { 367 @Override 368 void getViews(ArrayList<View> views) { 369 if (getVerticalGridView() == null) { 370 return; 371 } 372 final int count = getVerticalGridView().getChildCount(); 373 for (int i = 0; i < count; i++) { 374 View view = getVerticalGridView().getChildAt(i); 375 if (view != null) { 376 views.add(view); 377 } 378 } 379 } 380 }; 381 final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { 382 @Override 383 public void onAnimationUpdate(ValueAnimator arg0) { 384 final float fraction = (Float) arg0.getAnimatedValue(); 385 for (View view : listener.mViews) { 386 if (getVerticalGridView().getChildPosition(view) > 0) { 387 view.setAlpha(fraction); 388 view.setTranslationY((float) mAnimationTranslateY * (1f - fraction)); 389 } 390 } 391 } 392 }; 393 394 mOtherRowFadeInAnimator = loadAnimator( 395 getActivity(), R.animator.lb_playback_controls_fade_in); 396 mOtherRowFadeInAnimator.addListener(listener); 397 mOtherRowFadeInAnimator.addUpdateListener(updateListener); 398 mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 399 400 mOtherRowFadeOutAnimator = loadAnimator( 401 getActivity(), R.animator.lb_playback_controls_fade_out); 402 mOtherRowFadeOutAnimator.addListener(listener); 403 mOtherRowFadeOutAnimator.addUpdateListener(updateListener); 404 mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator()); 405 } 406 407 private void loadDescriptionAnimator() { 408 AnimatorUpdateListener listener = new AnimatorUpdateListener() { 409 @Override 410 public void onAnimationUpdate(ValueAnimator arg0) { 411 if (getVerticalGridView() == null) { 412 return; 413 } 414 ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder) 415 getVerticalGridView().findViewHolderForPosition(0); 416 if (adapterVh != null && adapterVh.getViewHolder() 417 instanceof PlaybackControlsRowPresenter.ViewHolder) { 418 final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder) 419 adapterVh.getViewHolder()).mDescriptionViewHolder; 420 if (vh != null) { 421 vh.view.setAlpha((Float) arg0.getAnimatedValue()); 422 } 423 } 424 } 425 }; 426 427 mDescriptionFadeInAnimator = loadAnimator( 428 getActivity(), R.animator.lb_playback_description_fade_in); 429 mDescriptionFadeInAnimator.addUpdateListener(listener); 430 mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 431 432 mDescriptionFadeOutAnimator = loadAnimator( 433 getActivity(), R.animator.lb_playback_description_fade_out); 434 mDescriptionFadeOutAnimator.addUpdateListener(listener); 435 } 436 437 private void fade(boolean fadeIn) { 438 if (DEBUG) Log.v(TAG, "fade " + fadeIn); 439 if (getView() == null) { 440 return; 441 } 442 if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) { 443 if (DEBUG) Log.v(TAG, "requested fade in progress"); 444 return; 445 } 446 if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) { 447 if (DEBUG) Log.v(TAG, "fade is no-op"); 448 return; 449 } 450 451 mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ? 452 mMajorFadeTranslateY : mMinorFadeTranslateY; 453 454 if (mFadingStatus == IDLE) { 455 if (fadeIn) { 456 mBgFadeInAnimator.start(); 457 mControlRowFadeInAnimator.start(); 458 mOtherRowFadeInAnimator.start(); 459 mDescriptionFadeInAnimator.start(); 460 } else { 461 mBgFadeOutAnimator.start(); 462 mControlRowFadeOutAnimator.start(); 463 mOtherRowFadeOutAnimator.start(); 464 mDescriptionFadeOutAnimator.start(); 465 } 466 } else { 467 if (fadeIn) { 468 mBgFadeOutAnimator.reverse(); 469 mControlRowFadeOutAnimator.reverse(); 470 mOtherRowFadeOutAnimator.reverse(); 471 mDescriptionFadeOutAnimator.reverse(); 472 } else { 473 mBgFadeInAnimator.reverse(); 474 mControlRowFadeInAnimator.reverse(); 475 mOtherRowFadeInAnimator.reverse(); 476 mDescriptionFadeInAnimator.reverse(); 477 } 478 } 479 480 // If fading in while control row is focused, set initial translationY so 481 // views slide in from below. 482 if (fadeIn && mFadingStatus == IDLE) { 483 final int count = getVerticalGridView().getChildCount(); 484 for (int i = 0; i < count; i++) { 485 getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY); 486 } 487 } 488 489 mFadingStatus = fadeIn ? IN : OUT; 490 } 491 492 /** 493 * Sets the list of rows for the fragment. 494 */ 495 @Override 496 public void setAdapter(ObjectAdapter adapter) { 497 if (getAdapter() != null) { 498 getAdapter().unregisterObserver(mObserver); 499 } 500 super.setAdapter(adapter); 501 if (adapter != null) { 502 adapter.registerObserver(mObserver); 503 } 504 } 505 506 @Override 507 void setVerticalGridViewLayout(VerticalGridView listview) { 508 if (listview == null) { 509 return; 510 } 511 // Padding affects alignment when last row is focused 512 // (last is first when there's only one row). 513 setBottomPadding(listview, mPaddingBottom); 514 515 // Item alignment affects focused row that isn't the last. 516 listview.setItemAlignmentOffset(mAlignPosition); 517 listview.setItemAlignmentOffsetPercent(100); 518 519 // Push rows to the bottom. 520 listview.setWindowAlignmentOffset(0); 521 listview.setWindowAlignmentOffsetPercent(100); 522 listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE); 523 } 524 525 private static void setBottomPadding(View view, int padding) { 526 view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), 527 view.getPaddingRight(), padding); 528 } 529 530 @Override 531 public void onCreate(Bundle savedInstanceState) { 532 super.onCreate(savedInstanceState); 533 534 mAlignPosition = 535 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_align_bottom); 536 mPaddingBottom = 537 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom); 538 mBgDarkColor = 539 getResources().getColor(R.color.lb_playback_controls_background_dark); 540 mBgLightColor = 541 getResources().getColor(R.color.lb_playback_controls_background_light); 542 mShowTimeMs = 543 getResources().getInteger(R.integer.lb_playback_controls_show_time_ms); 544 mMajorFadeTranslateY = 545 getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y); 546 mMinorFadeTranslateY = 547 getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y); 548 549 loadBgAnimator(); 550 loadControlRowAnimator(); 551 loadOtherRowAnimator(); 552 loadDescriptionAnimator(); 553 } 554 555 /** 556 * Sets the background type. 557 * 558 * @param type One of BG_LIGHT, BG_DARK, or BG_NONE. 559 */ 560 public void setBackgroundType(int type) { 561 switch (type) { 562 case BG_LIGHT: 563 case BG_DARK: 564 case BG_NONE: 565 if (type != mBackgroundType) { 566 mBackgroundType = type; 567 updateBackground(); 568 } 569 break; 570 default: 571 throw new IllegalArgumentException("Invalid background type"); 572 } 573 } 574 575 /** 576 * Returns the background type. 577 */ 578 public int getBackgroundType() { 579 return mBackgroundType; 580 } 581 582 private void updateBackground() { 583 if (mRootView != null) { 584 int color = mBgDarkColor; 585 switch (mBackgroundType) { 586 case BG_DARK: break; 587 case BG_LIGHT: color = mBgLightColor; break; 588 case BG_NONE: color = Color.TRANSPARENT; break; 589 } 590 mRootView.setBackground(new ColorDrawable(color)); 591 } 592 } 593 594 private void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) { 595 // Add extra space between rows 0 and 1 596 if (vh == null && getVerticalGridView() != null) { 597 vh = (ItemBridgeAdapter.ViewHolder) 598 getVerticalGridView().findViewHolderForPosition(0); 599 } 600 if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) { 601 final int adapterSize = getAdapter() == null ? 0 : getAdapter().size(); 602 ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace( 603 (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(), 604 adapterSize > 1); 605 } 606 } 607 608 private final ItemBridgeAdapter.AdapterListener mAdapterListener = 609 new ItemBridgeAdapter.AdapterListener() { 610 @Override 611 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) { 612 if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view); 613 if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) { 614 if (DEBUG) Log.v(TAG, "setting alpha to 0"); 615 vh.getViewHolder().view.setAlpha(0); 616 } 617 if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) { 618 resetControlsToPrimaryActions(vh); 619 } 620 } 621 @Override 622 public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) { 623 if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view); 624 // Reset animation state 625 vh.getViewHolder().view.setAlpha(1f); 626 vh.getViewHolder().view.setTranslationY(0); 627 if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) { 628 Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder) 629 vh.getViewHolder()).mDescriptionViewHolder; 630 if (descriptionVh != null) { 631 descriptionVh.view.setAlpha(1f); 632 } 633 } 634 } 635 @Override 636 public void onBind(ItemBridgeAdapter.ViewHolder vh) { 637 if (vh.getPosition() == 0) { 638 updateControlsBottomSpace(vh); 639 } 640 } 641 }; 642 643 @Override 644 public View onCreateView(LayoutInflater inflater, ViewGroup container, 645 Bundle savedInstanceState) { 646 mRootView = super.onCreateView(inflater, container, savedInstanceState); 647 mBgAlpha = 255; 648 updateBackground(); 649 getRowsSupportFragment().setExternalAdapterListener(mAdapterListener); 650 return mRootView; 651 } 652 653 @Override 654 public void onDestroyView() { 655 mRootView = null; 656 super.onDestroyView(); 657 } 658 659 private final DataObserver mObserver = new DataObserver() { 660 public void onChanged() { 661 updateControlsBottomSpace(null); 662 } 663 }; 664 665 static abstract class AnimatorListener implements Animator.AnimatorListener { 666 ArrayList<View> mViews = new ArrayList<View>(); 667 ArrayList<Integer> mLayerType = new ArrayList<Integer>(); 668 669 public void onAnimationCancel(Animator animation) { 670 } 671 public void onAnimationRepeat(Animator animation) { 672 } 673 public void onAnimationStart(Animator animation) { 674 getViews(mViews); 675 for (View view : mViews) { 676 mLayerType.add(view.getLayerType()); 677 view.setLayerType(View.LAYER_TYPE_HARDWARE, null); 678 } 679 } 680 public void onAnimationEnd(Animator animation) { 681 for (int i = 0; i < mViews.size(); i++) { 682 mViews.get(i).setLayerType(mLayerType.get(i), null); 683 } 684 mLayerType.clear(); 685 mViews.clear(); 686 } 687 abstract void getViews(ArrayList<View> views); 688 }; 689} 690