OSDN Git Service

QS Animations - first pass, still not spec
authorJason Monk <jmonk@google.com>
Fri, 19 Feb 2016 13:11:55 +0000 (08:11 -0500)
committerJason Monk <jmonk@google.com>
Sat, 20 Feb 2016 13:36:40 +0000 (08:36 -0500)
Bug: 27201532

Change-Id: I9a2a16f9d769db1f40ae733ad55a07ede4780698

14 files changed:
packages/SystemUI/res/layout/qs_paged_page.xml
packages/SystemUI/res/layout/qs_paged_tile_layout.xml
packages/SystemUI/res/layout/qs_panel.xml
packages/SystemUI/res/values/dimens.xml
packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java

index eef08ba..a246e0d 100644 (file)
@@ -19,4 +19,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/tile_page"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content" />
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:clipToPadding="false" />
index c23c745..c80d31d 100644 (file)
@@ -18,7 +18,9 @@
 <com.android.systemui.qs.PagedTileLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:clipToPadding="false">
 
     <FrameLayout
         android:id="@+id/page_decor"
index 9f90af2..b8f10db 100644 (file)
@@ -26,7 +26,9 @@
             android:layout_marginTop="@dimen/status_bar_header_height"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingBottom="8dp" />
+            android:paddingBottom="8dp"
+            android:clipToPadding="false"
+            android:clipChildren="false" />
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
index b8044ba..9256fa6 100644 (file)
     <dimen name="qs_date_alarm_anim_translation">26dp</dimen>
     <dimen name="qs_date_collapsed_text_size">14sp</dimen>
     <dimen name="qs_date_text_size">16sp</dimen>
-    <dimen name="qs_header_gear_translation">120dp</dimen>
+    <dimen name="qs_header_gear_translation">150dp</dimen>
     <dimen name="qs_page_indicator_size">12dp</dimen>
     <dimen name="qs_tile_icon_size">24dp</dimen>
     <dimen name="qs_tile_text_size">12sp</dimen>
index 8e9857d..0915ee1 100644 (file)
@@ -27,6 +27,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
 
     private int mNumPages;
     private View mDecorGroup;
+    private PageListener mPageListener;
 
     public PagedTileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -36,10 +37,14 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
             public void onPageSelected(int position) {
                 if (mPageIndicator == null) return;
                 mPageIndicator.setLocation(position);
+                if (mPageListener != null) {
+                    mPageListener.onPageChanged(position);
+                }
             }
 
             @Override
-            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            public void onPageScrolled(int position, float positionOffset,
+                    int positionOffsetPixels) {
                 if (mPageIndicator == null) return;
                 mPageIndicator.setLocation(position + positionOffset);
             }
@@ -80,6 +85,10 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
         }
     }
 
+    public void setPageListener(PageListener listener) {
+        mPageListener = listener;
+    }
+
     private void postDistributeTiles() {
         removeCallbacks(mDistribute);
         post(mDistribute);
@@ -198,4 +207,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
             return view == object;
         }
     };
+
+    public interface PageListener {
+        void onPageChanged(int page);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
new file mode 100644 (file)
index 0000000..6479b0c
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.TextView;
+import com.android.systemui.Interpolators;
+import com.android.systemui.qs.PagedTileLayout.PageListener;
+import com.android.systemui.qs.QSPanel.QSTileLayout;
+import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
+
+    private static final String TAG = "QSAnimator";
+
+    public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
+            new PathInterpolator(.1f, .3f, 1, 1);
+
+    public static final float EXPANDED_TILE_DELAY = .7f;
+
+    private final ArrayList<View> mAllViews = new ArrayList<>();
+    private final QuickQSPanel mQuickQsPanel;
+    private final QSPanel mQsPanel;
+    private final QSContainer mQsContainer;
+
+    private boolean mOnFirstPage = true;
+    private TouchAnimator mFirstPageAnimator;
+    private TouchAnimator mFirstPageDelayedAnimator;
+    private TouchAnimator mTranslationYAnimator;
+    private TouchAnimator mNonfirstPageAnimator;
+
+    public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
+        mQsContainer = container;
+        mQuickQsPanel = quickPanel;
+        mQsPanel = panel;
+        mQuickQsPanel.addOnLayoutChangeListener(this);
+        mQsPanel.addOnLayoutChangeListener(this);
+        QSTileLayout tileLayout = mQsPanel.getTileLayout();
+        if (tileLayout instanceof PagedTileLayout) {
+            ((PagedTileLayout) tileLayout).setPageListener(this);
+        } else {
+            Log.w(TAG, "QS Not using page layout");
+        }
+    }
+
+    public void setHost(QSTileHost qsh) {
+        qsh.addCallback(this);
+    }
+
+    @Override
+    public void onPageChanged(int page) {
+        mOnFirstPage = page == 0;
+        if (!mOnFirstPage) {
+            clearAnimationState();
+        }
+    }
+
+    private void updateAnimators() {
+        TouchAnimator.Builder firstPageBuilder = new Builder();
+        TouchAnimator.Builder translationYBuilder = new Builder();
+        TouchAnimator.Builder firstPageDelayedBuilder = new Builder();
+        Collection<QSTile<?>> tiles = mQsPanel.getHost().getTiles();
+        int count = 0;
+        int[] loc1 = new int[2];
+        int[] loc2 = new int[2];
+        firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
+        firstPageBuilder.setListener(this);
+        translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
+        mAllViews.clear();
+        for (QSTile<?> tile : tiles) {
+            QSTileBaseView tileView = mQsPanel.getTileView(tile);
+            final TextView label = ((QSTileView) tileView).getLabel();
+            if (count++ < 5) {
+                // Quick tiles.
+                QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
+                final View tileIcon = tileView.getIcon();
+
+                getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
+                getRelativePosition(loc2, tileIcon, mQsContainer);
+                final int xDiff = loc2[0] - loc1[0];
+                final int yDiff = loc2[1] - loc1[1];
+                // Move the quick tile right from its location to the new one.
+                firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
+                translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
+
+                // Counteract the parent translation on the tile. So we have a static base to
+                // animate off from.
+                firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+
+                // Move the real tile's icon and label from the quick tile position to its final
+                // location.
+                firstPageBuilder.addFloat(tileIcon, "translationX", -xDiff, 0);
+                translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
+                firstPageBuilder.addFloat(label, "translationX", -xDiff, 0);
+                translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+
+                // Fade in the label as we reach the final position.
+                firstPageDelayedBuilder.addFloat(label, "alpha", 0, 1);
+                mAllViews.add(quickTileView);
+            } else {
+                firstPageDelayedBuilder.addFloat(tileView, "alpha", 0, 1);
+            }
+            mAllViews.add(tileView);
+            mAllViews.add(label);
+        }
+        mFirstPageAnimator = firstPageBuilder.build();
+        mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
+        mTranslationYAnimator = translationYBuilder.build();
+        mNonfirstPageAnimator = new TouchAnimator.Builder()
+                .addFloat(mQuickQsPanel, "alpha", 1, 0)
+                .setEndDelay(.5f)
+                .build();
+    }
+
+    private void getRelativePosition(int[] loc1, View view, View parent) {
+        loc1[0] = 0 + view.getWidth() / 2;
+        loc1[1] = 0;
+        getRelativePositionInt(loc1, view, parent);
+    }
+
+    private void getRelativePositionInt(int[] loc1, View view, View parent) {
+        if(view == parent || view == null) return;
+        loc1[0] += view.getLeft();
+        loc1[1] += view.getTop();
+        getRelativePositionInt(loc1, (View) view.getParent(), parent);
+    }
+
+    public void setPosition(float position) {
+        if (mFirstPageAnimator == null) return;
+        if (mOnFirstPage) {
+            mQuickQsPanel.setAlpha(1);
+            mFirstPageAnimator.setPosition(position);
+            mFirstPageDelayedAnimator.setPosition(position);
+            mTranslationYAnimator.setPosition(position);
+        } else {
+            mNonfirstPageAnimator.setPosition(position);
+        }
+    }
+
+    @Override
+    public void onAnimationAtStart() {
+
+    }
+
+    @Override
+    public void onAnimationAtEnd() {
+        mQuickQsPanel.setVisibility(View.INVISIBLE);
+    }
+
+    @Override
+    public void onAnimationStarted() {
+        mQuickQsPanel.setVisibility(View.VISIBLE);
+    }
+
+    private void clearAnimationState() {
+        final int N = mAllViews.size();
+        mQuickQsPanel.setAlpha(0);
+        for (int i = 0; i < N; i++) {
+            View v = mAllViews.get(i);
+            v.setAlpha(1);
+            v.setTranslationX(1);
+            v.setTranslationY(1);
+        }
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        updateAnimators();
+    }
+
+    @Override
+    public void onTilesChanged() {
+        // Give the QS panels a moment to generate their new tiles, then create all new animators
+        // hooked up to the new views.
+        mQsPanel.post(mUpdateAnimators);
+    }
+
+    private Runnable mUpdateAnimators = new Runnable() {
+        @Override
+        public void run() {
+            updateAnimators();
+        }
+    };
+}
index 34dfd6c..da92143 100644 (file)
@@ -27,6 +27,7 @@ import android.widget.FrameLayout;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
@@ -49,6 +50,7 @@ public class QSContainer extends FrameLayout {
     private boolean mStackScrollerOverscrolling;
 
     private long mDelay;
+    private QSAnimator mQSAnimator;
 
     public QSContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -61,6 +63,15 @@ public class QSContainer extends FrameLayout {
         mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
         mQSDetail.setQsPanel(mQSPanel);
         mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
+        mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
+                mQSPanel);
+    }
+
+    public void setHost(QSTileHost qsh) {
+        mQSPanel.setHost(qsh);
+        mHeader.setQSPanel(mQSPanel);
+        mQSDetail.setHost(qsh);
+        mQSAnimator.setHost(qsh);
     }
 
     @Override
@@ -163,6 +174,7 @@ public class QSContainer extends FrameLayout {
         mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
         mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
         mQSDetail.setFullyExpanded(expansion == 1);
+        mQSAnimator.setPosition(expansion);
         updateBottom();
     }
 
index 53abe37..d3e57a8 100644 (file)
@@ -25,7 +25,6 @@ import android.os.Message;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import com.android.internal.logging.MetricsLogger;
@@ -45,7 +44,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 
 /** View that represents the quick settings tile panel. **/
-public class QSPanel extends FrameLayout implements Tunable {
+public class QSPanel extends LinearLayout implements Tunable {
 
     public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
 
@@ -66,7 +65,6 @@ public class QSPanel extends FrameLayout implements Tunable {
     protected QSFooter mFooter;
     private boolean mGridContentVisible = true;
 
-    protected LinearLayout mQsContainer;
     protected QSTileLayout mTileLayout;
 
     private QSCustomizer mCustomizePanel;
@@ -80,20 +78,15 @@ public class QSPanel extends FrameLayout implements Tunable {
         super(context, attrs);
         mContext = context;
 
-
-        mQsContainer = new LinearLayout(mContext);
-        mQsContainer.setOrientation(LinearLayout.VERTICAL);
-        mQsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.WRAP_CONTENT));
-        addView(mQsContainer);
+        setOrientation(VERTICAL);
 
         mBrightnessView = LayoutInflater.from(context).inflate(
                 R.layout.quick_settings_brightness_dialog, this, false);
-        mQsContainer.addView(mBrightnessView);
+        addView(mBrightnessView);
 
         mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
-                R.layout.qs_paged_tile_layout, mQsContainer, false);
-        mQsContainer.addView((View) mTileLayout);
+                R.layout.qs_paged_tile_layout, this, false);
+        addView((View) mTileLayout);
         findViewById(android.R.id.edit).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(final View v) {
@@ -107,7 +100,7 @@ public class QSPanel extends FrameLayout implements Tunable {
         });
 
         mFooter = new QSFooter(this, context);
-        mQsContainer.addView(mFooter.getView());
+        addView(mFooter.getView());
 
         updateResources();
 
@@ -187,7 +180,7 @@ public class QSPanel extends FrameLayout implements Tunable {
         final Resources res = mContext.getResources();
         mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
         mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
-        mQsContainer.setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
+        setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
         for (TileRecord r : mRecords) {
             r.tile.clearState();
         }
@@ -214,6 +207,9 @@ public class QSPanel extends FrameLayout implements Tunable {
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
+        if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
+            ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+        }
         MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded);
         if (!mExpanded) {
             closeDetail();
@@ -376,7 +372,7 @@ public class QSPanel extends FrameLayout implements Tunable {
     }
 
     public int getGridHeight() {
-        return mQsContainer.getMeasuredHeight();
+        return getMeasuredHeight();
     }
 
     protected void handleShowDetail(Record r, boolean show) {
@@ -425,7 +421,7 @@ public class QSPanel extends FrameLayout implements Tunable {
 
     void setGridContentVisibility(boolean visible) {
         int newVis = visible ? VISIBLE : INVISIBLE;
-        mQsContainer.setVisibility(newVis);
+        setVisibility(newVis);
         if (mGridContentVisible != visible) {
             MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, newVis);
         }
@@ -468,6 +464,19 @@ public class QSPanel extends FrameLayout implements Tunable {
         }
     }
 
+    QSTileLayout getTileLayout() {
+        return mTileLayout;
+    }
+
+    QSTileBaseView getTileView(QSTile<?> tile) {
+        for (TileRecord r : mRecords) {
+            if (r.tile == tile) {
+                return r.tileView;
+            }
+        }
+        return null;
+    }
+
     private class H extends Handler {
         private static final int SHOW_DETAIL = 1;
         private static final int SET_TILE_VISIBILITY = 2;
index 1a854c2..1601d81 100644 (file)
@@ -49,6 +49,8 @@ public class QSTileBaseView extends LinearLayout {
         // Default to Quick Tile padding, and QSTileView will specify its own padding.
         int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
         setPadding(padding, padding, padding, padding);
+        setClipChildren(false);
+        setClipToPadding(false);
     }
 
     private Drawable newTileBackground() {
@@ -110,6 +112,10 @@ public class QSTileBaseView extends LinearLayout {
         setContentDescription(state.contentDescription);
     }
 
+    View getIcon() {
+        return mIcon;
+    }
+
     private class H extends Handler {
         private static final int STATE_CHANGED = 1;
         public H() {
index 0d5d115..dcff620 100644 (file)
@@ -57,6 +57,10 @@ public class QSTileView extends QSTileBaseView {
         setGravity(Gravity.CENTER);
     }
 
+    TextView getLabel() {
+        return mLabel;
+    }
+
     private void updateTopPadding() {
         Resources res = getResources();
         int padding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
index d0f7e6e..abe4c77 100644 (file)
@@ -43,10 +43,10 @@ public class QuickQSPanel extends QSPanel {
             for (int i = 0; i < mRecords.size(); i++) {
                 mTileLayout.removeTile(mRecords.get(i));
             }
-            mQsContainer.removeView((View) mTileLayout);
+            removeView((View) mTileLayout);
         }
         mTileLayout = new HeaderTileLayout(context);
-        mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
+        addView((View) mTileLayout, 1 /* Between brightness and footer */);
     }
 
     @Override
index 5e6b52b..52b7059 100644 (file)
@@ -213,7 +213,7 @@ public class TouchAnimator {
         }
     }
 
-    public static class FloatKeyframeSet extends KeyframeSet {
+    private static class FloatKeyframeSet extends KeyframeSet {
         public FloatKeyframeSet(Keyframe[] keyframes) {
             super(keyframes);
         }
@@ -226,7 +226,7 @@ public class TouchAnimator {
         }
     }
 
-    public static class IntKeyframeSet extends KeyframeSet {
+    private static class IntKeyframeSet extends KeyframeSet {
         public IntKeyframeSet(Keyframe[] keyframes) {
             super(keyframes);
         }
index 47d3093..c6d325e 100644 (file)
@@ -116,7 +116,7 @@ import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.qs.QSDetail;
+import com.android.systemui.qs.QSContainer;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.recents.events.EventBus;
@@ -871,13 +871,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
                     mCastController, mFlashlightController,
                     mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
                     mSecurityController, mBatteryController, mIconController);
-            mQSPanel.setHost(qsh);
             mQSPanel.setTiles(qsh.getTiles());
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
             mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
-            mHeader.setQSPanel(mQSPanel);
-            QSDetail qsDetail = (QSDetail) mStatusBarWindow.findViewById(R.id.qs_detail);
-            qsDetail.setHost(qsh);
+            QSContainer qsContainer = (QSContainer) mStatusBarWindow.findViewById(
+                    R.id.quick_settings_container);
+            qsContainer.setHost(qsh);
             qsh.addCallback(new QSTileHost.Callback() {
                 @Override
                 public void onTilesChanged() {
index bd5bac2..ab8067d 100644 (file)
@@ -34,6 +34,7 @@ import android.widget.Toast;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSAnimator;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QuickQSPanel;
@@ -50,7 +51,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
 
     private static final String TAG = "QuickStatusBarHeader";
 
-    private static final float EXPAND_INDICATOR_THRESHOLD = .8f;
+    private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
 
     private ActivityStarter mActivityStarter;
     private NextAlarmController mNextAlarmController;
@@ -89,6 +90,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     private TouchAnimator mFirstHalfAnimator;
     private TouchAnimator mDateSizeAnimator;
     private TouchAnimator mAlarmTranslation;
+    private TouchAnimator mSettingsAlpha;
     private float mExpansionAmount;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
@@ -164,18 +166,16 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
         mAnimator = new TouchAnimator.Builder()
                 .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
                 .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
-                .addFloat(mSettingsButton, "rotation", -90, 0)
                 .setListener(this)
                 .build();
         mSecondHalfAnimator = new TouchAnimator.Builder()
-                .addFloat(mSettingsButton, "rotation", -90, 0)
+                .addFloat(mSettingsButton, "rotation", -180, 0)
                 .addFloat(mAlarmStatus, "alpha", 0, 1)
                 .addFloat(mEmergencyOnly, "alpha", 0, 1)
                 .setStartDelay(.5f)
                 .build();
         mFirstHalfAnimator = new TouchAnimator.Builder()
                 .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0)
-                .addFloat(mHeaderQsPanel, "alpha", 1, 0)
                 .setEndDelay(.5f)
                 .build();
         mDateSizeAnimator = new TouchAnimator.Builder()
@@ -183,6 +183,11 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
                 .addFloat(mDateTimeGroup, "scaleY", 1, mDateScaleFactor)
                 .setStartDelay(.36f)
                 .build();
+        mSettingsAlpha = new TouchAnimator.Builder()
+                .addFloat(mSettingsContainer, "alpha", 0, 1)
+                .addFloat(mMultiUserSwitch, "alpha", 0, 1)
+                .setStartDelay(QSAnimator.EXPANDED_TILE_DELAY)
+                .build();
     }
 
     @Override
@@ -221,6 +226,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
         mFirstHalfAnimator.setPosition(headerExpansionFraction);
         mDateSizeAnimator.setPosition(headerExpansionFraction);
         mAlarmTranslation.setPosition(headerExpansionFraction);
+        mSettingsAlpha.setPosition(headerExpansionFraction);
 
         updateAlarmVisibilities();