Loading packages/SystemUI/src/com/android/systemui/ExpandHelper.java +2 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ public class ExpandHelper implements Gefingerpoken { void setUserExpandedChild(View v, boolean userExpanded); void setUserLockedChild(View v, boolean userLocked); void expansionStateChanged(boolean isExpanding); int getMaxExpandHeight(ExpandableView view); } private static final String TAG = "ExpandHelper"; Loading Loading @@ -144,7 +145,7 @@ public class ExpandHelper implements Gefingerpoken { return mView.getActualHeight(); } public int getNaturalHeight() { return mView.getMaxContentHeight(); return mCallback.getMaxExpandHeight(mView); } } Loading packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +16 −1 Original line number Diff line number Diff line Loading @@ -156,6 +156,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } } }; private boolean mForceUnlocked; private boolean mDismissed; private boolean mKeepInParent; private boolean mRemoved; Loading Loading @@ -454,7 +455,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * @param pinned whether it is pinned */ public void setPinned(boolean pinned) { int intrinsicHeight = getIntrinsicHeight(); mIsPinned = pinned; if (intrinsicHeight != getIntrinsicHeight()) { notifyHeightChanged(false); } if (pinned) { setIconAnimationRunning(true); mExpandedWhenPinned = false; Loading Loading @@ -645,6 +650,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { onChildrenCountChanged(); } public void setForceUnlocked(boolean forceUnlocked) { mForceUnlocked = forceUnlocked; if (mIsSummaryWithChildren) { List<ExpandableNotificationRow> notificationChildren = getNotificationChildren(); for (ExpandableNotificationRow child : notificationChildren) { child.setForceUnlocked(forceUnlocked); } } } public void setDismissed(boolean dismissed) { mDismissed = dismissed; } Loading Loading @@ -1017,7 +1032,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } public boolean isUserLocked() { return mUserLocked; return mUserLocked && !mForceUnlocked; } public void setUserLocked(boolean userLocked) { Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +3 −1 Original line number Diff line number Diff line Loading @@ -103,10 +103,12 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mInitialTouchX = x; mInitialTouchY = y; int expandedHeight = mPickedChild.getActualHeight(); mHeadsUpManager.unpinAll(); mPanel.setPanelScrimMinFraction((float) expandedHeight / mPanel.getMaxPanelHeight()); mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight); // This call needs to be after the expansion start otherwise we will get a // flicker of one frame as it's not expanded yet. mHeadsUpManager.unpinAll(); mPanel.clearNotificationEffects(); return true; } Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +1 −0 Original line number Diff line number Diff line Loading @@ -362,6 +362,7 @@ public abstract class PanelView extends FrameLayout { mInitialTouchX = newX; if (startTracking) { mTouchSlopExceeded = true; setExpandedHeight(mInitialOffsetOnTouch); onTrackingStarted(); } } Loading packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +106 −16 Original line number Diff line number Diff line Loading @@ -36,8 +36,10 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; import android.util.Pair; import android.util.Property; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; Loading Loading @@ -331,6 +333,20 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mPulsing; private boolean mDrawBackgroundAsSrc; private boolean mFadedOut; private boolean mGroupExpandedForMeasure; private float mBackgroundFadeAmount = 1.0f; private static final Property<NotificationStackScrollLayout, Float> BACKGROUND_FADE = new FloatProperty<NotificationStackScrollLayout>("backgroundFade") { @Override public void setValue(NotificationStackScrollLayout object, float value) { object.setBackgroundFadeAmount(value); } @Override public Float get(NotificationStackScrollLayout object) { return object.getBackgroundFadeAmount(); } }; public NotificationStackScrollLayout(Context context) { this(context, null); Loading Loading @@ -406,14 +422,18 @@ public class NotificationStackScrollLayout extends ViewGroup private void updateBackgroundDimming() { float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount); alpha *= mBackgroundFadeAmount; // We need to manually blend in the background color int scrimColor = mScrimController.getScrimBehindColor(); // SRC_OVER blending Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc float alphaInv = 1 - alpha; int color = Color.argb((int) (alpha * 255 + alphaInv * Color.alpha(scrimColor)), (int) (Color.red(mBgColor) + alphaInv * Color.red(scrimColor)), (int) (Color.green(mBgColor) + alphaInv * Color.green(scrimColor)), (int) (Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor))); (int) (mBackgroundFadeAmount * Color.red(mBgColor) + alphaInv * Color.red(scrimColor)), (int) (mBackgroundFadeAmount * Color.green(mBgColor) + alphaInv * Color.green(scrimColor)), (int) (mBackgroundFadeAmount * Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor))); mBackgroundPaint.setColor(color); invalidate(); } Loading Loading @@ -930,6 +950,30 @@ public class NotificationStackScrollLayout extends ViewGroup } } @Override public int getMaxExpandHeight(ExpandableView view) { int maxContentHeight = view.getMaxContentHeight(); if (view.isSummaryWithChildren()) { // Faking a measure with the group expanded to simulate how the group would look if // it was. Doing a calculation here would be highly non-trivial because of the // algorithm mGroupExpandedForMeasure = true; ExpandableNotificationRow row = (ExpandableNotificationRow) view; mGroupManager.toggleGroupExpansion(row.getStatusBarNotification()); row.setForceUnlocked(true); mAmbientState.setLayoutHeight(mMaxLayoutHeight); mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState); mAmbientState.setLayoutHeight(getLayoutHeight()); mGroupManager.toggleGroupExpansion( row.getStatusBarNotification()); mGroupExpandedForMeasure = false; row.setForceUnlocked(false); int height = mCurrentStackScrollState.getViewStateForView(view).height; return Math.min(height, maxContentHeight); } return maxContentHeight; } public void setScrollingEnabled(boolean enable) { mScrollingEnabled = enable; } Loading Loading @@ -1555,6 +1599,24 @@ public class NotificationStackScrollLayout extends ViewGroup return null; } /** * @return the child before the given view which has visibility unequal to GONE */ public ExpandableView getViewBeforeView(ExpandableView view) { ExpandableView previousView = null; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child == view) { return previousView; } if (child.getVisibility() != View.GONE) { previousView = (ExpandableView) child; } } return null; } /** * @return The first child which has visibility unequal to GONE which is currently below the * given translationY or equal to it. Loading Loading @@ -1599,14 +1661,6 @@ public class NotificationStackScrollLayout extends ViewGroup return count; } private int getMaxExpandHeight(View view) { if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; return row.getIntrinsicHeight(); } return view.getHeight(); } public int getContentHeight() { return mContentHeight; } Loading Loading @@ -2577,6 +2631,7 @@ public class NotificationStackScrollLayout extends ViewGroup AnimationEvent ev = new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DARK); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); startBackgroundFadeIn(); } mDarkNeedsAnimation = false; } Loading Loading @@ -2886,8 +2941,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (row.isChildInGroup()) { endPosition += row.getNotificationParent().getTranslationY(); } int stackEnd = mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight + (int) mStackTranslation; int stackEnd = getStackEndPosition(); if (endPosition > stackEnd) { mOwnScrollY += endPosition - stackEnd; mDisallowScrollingInThisMotion = true; Loading @@ -2896,6 +2950,11 @@ public class NotificationStackScrollLayout extends ViewGroup } } private int getStackEndPosition() { return mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight + mPaddingBetweenElements + (int) mStackTranslation; } public void setOnHeightChangedListener( ExpandableView.OnHeightChangedListener mOnHeightChangedListener) { this.mOnHeightChangedListener = mOnHeightChangedListener; Loading Loading @@ -3081,6 +3140,9 @@ public class NotificationStackScrollLayout extends ViewGroup mDarkNeedsAnimation = true; mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); mNeedsAnimation = true; setBackgroundFadeAmount(0.0f); } else if (!dark) { setBackgroundFadeAmount(1.0f); } requestChildrenUpdate(); if (dark) { Loading @@ -3089,10 +3151,35 @@ public class NotificationStackScrollLayout extends ViewGroup } else { updateBackground(); setWillNotDraw(false); // TODO: fade in background } } private void setBackgroundFadeAmount(float fadeAmount) { mBackgroundFadeAmount = fadeAmount; updateBackgroundDimming(); } public float getBackgroundFadeAmount() { return mBackgroundFadeAmount; } private void startBackgroundFadeIn() { ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(this, BACKGROUND_FADE, 0f, 1f); int maxLength; if (mDarkAnimationOriginIndex == AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE || mDarkAnimationOriginIndex == AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW) { maxLength = getNotGoneChildCount() - 1; } else { maxLength = Math.max(mDarkAnimationOriginIndex, getNotGoneChildCount() - mDarkAnimationOriginIndex - 1); } long delay = maxLength * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_DARK; fadeAnimator.setStartDelay(delay); fadeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); fadeAnimator.setInterpolator(Interpolators.ALPHA_IN); fadeAnimator.start(); } private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) { return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE; Loading Loading @@ -3376,14 +3463,17 @@ public class NotificationStackScrollLayout extends ViewGroup @Override public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) { boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned()); boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled && (mIsExpanded || changedRow.isPinned()); if (animated) { mExpandedGroupView = changedRow; mNeedsAnimation = true; } changedRow.setChildrenExpanded(expanded, animated); if (!mGroupExpandedForMeasure) { onHeightChanged(changedRow, false /* needsAnimation */); } } @Override public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) { Loading Loading
packages/SystemUI/src/com/android/systemui/ExpandHelper.java +2 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ public class ExpandHelper implements Gefingerpoken { void setUserExpandedChild(View v, boolean userExpanded); void setUserLockedChild(View v, boolean userLocked); void expansionStateChanged(boolean isExpanding); int getMaxExpandHeight(ExpandableView view); } private static final String TAG = "ExpandHelper"; Loading Loading @@ -144,7 +145,7 @@ public class ExpandHelper implements Gefingerpoken { return mView.getActualHeight(); } public int getNaturalHeight() { return mView.getMaxContentHeight(); return mCallback.getMaxExpandHeight(mView); } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +16 −1 Original line number Diff line number Diff line Loading @@ -156,6 +156,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } } }; private boolean mForceUnlocked; private boolean mDismissed; private boolean mKeepInParent; private boolean mRemoved; Loading Loading @@ -454,7 +455,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * @param pinned whether it is pinned */ public void setPinned(boolean pinned) { int intrinsicHeight = getIntrinsicHeight(); mIsPinned = pinned; if (intrinsicHeight != getIntrinsicHeight()) { notifyHeightChanged(false); } if (pinned) { setIconAnimationRunning(true); mExpandedWhenPinned = false; Loading Loading @@ -645,6 +650,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { onChildrenCountChanged(); } public void setForceUnlocked(boolean forceUnlocked) { mForceUnlocked = forceUnlocked; if (mIsSummaryWithChildren) { List<ExpandableNotificationRow> notificationChildren = getNotificationChildren(); for (ExpandableNotificationRow child : notificationChildren) { child.setForceUnlocked(forceUnlocked); } } } public void setDismissed(boolean dismissed) { mDismissed = dismissed; } Loading Loading @@ -1017,7 +1032,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } public boolean isUserLocked() { return mUserLocked; return mUserLocked && !mForceUnlocked; } public void setUserLocked(boolean userLocked) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +3 −1 Original line number Diff line number Diff line Loading @@ -103,10 +103,12 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mInitialTouchX = x; mInitialTouchY = y; int expandedHeight = mPickedChild.getActualHeight(); mHeadsUpManager.unpinAll(); mPanel.setPanelScrimMinFraction((float) expandedHeight / mPanel.getMaxPanelHeight()); mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight); // This call needs to be after the expansion start otherwise we will get a // flicker of one frame as it's not expanded yet. mHeadsUpManager.unpinAll(); mPanel.clearNotificationEffects(); return true; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +1 −0 Original line number Diff line number Diff line Loading @@ -362,6 +362,7 @@ public abstract class PanelView extends FrameLayout { mInitialTouchX = newX; if (startTracking) { mTouchSlopExceeded = true; setExpandedHeight(mInitialOffsetOnTouch); onTrackingStarted(); } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +106 −16 Original line number Diff line number Diff line Loading @@ -36,8 +36,10 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; import android.util.Pair; import android.util.Property; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; Loading Loading @@ -331,6 +333,20 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mPulsing; private boolean mDrawBackgroundAsSrc; private boolean mFadedOut; private boolean mGroupExpandedForMeasure; private float mBackgroundFadeAmount = 1.0f; private static final Property<NotificationStackScrollLayout, Float> BACKGROUND_FADE = new FloatProperty<NotificationStackScrollLayout>("backgroundFade") { @Override public void setValue(NotificationStackScrollLayout object, float value) { object.setBackgroundFadeAmount(value); } @Override public Float get(NotificationStackScrollLayout object) { return object.getBackgroundFadeAmount(); } }; public NotificationStackScrollLayout(Context context) { this(context, null); Loading Loading @@ -406,14 +422,18 @@ public class NotificationStackScrollLayout extends ViewGroup private void updateBackgroundDimming() { float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount); alpha *= mBackgroundFadeAmount; // We need to manually blend in the background color int scrimColor = mScrimController.getScrimBehindColor(); // SRC_OVER blending Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc float alphaInv = 1 - alpha; int color = Color.argb((int) (alpha * 255 + alphaInv * Color.alpha(scrimColor)), (int) (Color.red(mBgColor) + alphaInv * Color.red(scrimColor)), (int) (Color.green(mBgColor) + alphaInv * Color.green(scrimColor)), (int) (Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor))); (int) (mBackgroundFadeAmount * Color.red(mBgColor) + alphaInv * Color.red(scrimColor)), (int) (mBackgroundFadeAmount * Color.green(mBgColor) + alphaInv * Color.green(scrimColor)), (int) (mBackgroundFadeAmount * Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor))); mBackgroundPaint.setColor(color); invalidate(); } Loading Loading @@ -930,6 +950,30 @@ public class NotificationStackScrollLayout extends ViewGroup } } @Override public int getMaxExpandHeight(ExpandableView view) { int maxContentHeight = view.getMaxContentHeight(); if (view.isSummaryWithChildren()) { // Faking a measure with the group expanded to simulate how the group would look if // it was. Doing a calculation here would be highly non-trivial because of the // algorithm mGroupExpandedForMeasure = true; ExpandableNotificationRow row = (ExpandableNotificationRow) view; mGroupManager.toggleGroupExpansion(row.getStatusBarNotification()); row.setForceUnlocked(true); mAmbientState.setLayoutHeight(mMaxLayoutHeight); mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState); mAmbientState.setLayoutHeight(getLayoutHeight()); mGroupManager.toggleGroupExpansion( row.getStatusBarNotification()); mGroupExpandedForMeasure = false; row.setForceUnlocked(false); int height = mCurrentStackScrollState.getViewStateForView(view).height; return Math.min(height, maxContentHeight); } return maxContentHeight; } public void setScrollingEnabled(boolean enable) { mScrollingEnabled = enable; } Loading Loading @@ -1555,6 +1599,24 @@ public class NotificationStackScrollLayout extends ViewGroup return null; } /** * @return the child before the given view which has visibility unequal to GONE */ public ExpandableView getViewBeforeView(ExpandableView view) { ExpandableView previousView = null; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child == view) { return previousView; } if (child.getVisibility() != View.GONE) { previousView = (ExpandableView) child; } } return null; } /** * @return The first child which has visibility unequal to GONE which is currently below the * given translationY or equal to it. Loading Loading @@ -1599,14 +1661,6 @@ public class NotificationStackScrollLayout extends ViewGroup return count; } private int getMaxExpandHeight(View view) { if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; return row.getIntrinsicHeight(); } return view.getHeight(); } public int getContentHeight() { return mContentHeight; } Loading Loading @@ -2577,6 +2631,7 @@ public class NotificationStackScrollLayout extends ViewGroup AnimationEvent ev = new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DARK); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); startBackgroundFadeIn(); } mDarkNeedsAnimation = false; } Loading Loading @@ -2886,8 +2941,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (row.isChildInGroup()) { endPosition += row.getNotificationParent().getTranslationY(); } int stackEnd = mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight + (int) mStackTranslation; int stackEnd = getStackEndPosition(); if (endPosition > stackEnd) { mOwnScrollY += endPosition - stackEnd; mDisallowScrollingInThisMotion = true; Loading @@ -2896,6 +2950,11 @@ public class NotificationStackScrollLayout extends ViewGroup } } private int getStackEndPosition() { return mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight + mPaddingBetweenElements + (int) mStackTranslation; } public void setOnHeightChangedListener( ExpandableView.OnHeightChangedListener mOnHeightChangedListener) { this.mOnHeightChangedListener = mOnHeightChangedListener; Loading Loading @@ -3081,6 +3140,9 @@ public class NotificationStackScrollLayout extends ViewGroup mDarkNeedsAnimation = true; mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); mNeedsAnimation = true; setBackgroundFadeAmount(0.0f); } else if (!dark) { setBackgroundFadeAmount(1.0f); } requestChildrenUpdate(); if (dark) { Loading @@ -3089,10 +3151,35 @@ public class NotificationStackScrollLayout extends ViewGroup } else { updateBackground(); setWillNotDraw(false); // TODO: fade in background } } private void setBackgroundFadeAmount(float fadeAmount) { mBackgroundFadeAmount = fadeAmount; updateBackgroundDimming(); } public float getBackgroundFadeAmount() { return mBackgroundFadeAmount; } private void startBackgroundFadeIn() { ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(this, BACKGROUND_FADE, 0f, 1f); int maxLength; if (mDarkAnimationOriginIndex == AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE || mDarkAnimationOriginIndex == AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW) { maxLength = getNotGoneChildCount() - 1; } else { maxLength = Math.max(mDarkAnimationOriginIndex, getNotGoneChildCount() - mDarkAnimationOriginIndex - 1); } long delay = maxLength * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_DARK; fadeAnimator.setStartDelay(delay); fadeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); fadeAnimator.setInterpolator(Interpolators.ALPHA_IN); fadeAnimator.start(); } private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) { return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE; Loading Loading @@ -3376,14 +3463,17 @@ public class NotificationStackScrollLayout extends ViewGroup @Override public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) { boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned()); boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled && (mIsExpanded || changedRow.isPinned()); if (animated) { mExpandedGroupView = changedRow; mNeedsAnimation = true; } changedRow.setChildrenExpanded(expanded, animated); if (!mGroupExpandedForMeasure) { onHeightChanged(changedRow, false /* needsAnimation */); } } @Override public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) { Loading