Merge "Move zen-mode systemui affordance to quick settings."
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 56c1f4e..1693e01 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -58,12 +58,6 @@
             android:layout_height="@dimen/notification_panel_header_height"
             />
 
-        <com.android.systemui.statusbar.phone.ZenModeView
-            android:id="@+id/zenmode"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-
         <TextView
             android:id="@+id/emergency_calls_only"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 25c516b..9aa7cfd 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,7 +15,7 @@
 ** limitations under the License.
 -->
 
-<com.android.systemui.statusbar.phone.PanelHeaderView
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
@@ -106,4 +106,4 @@
             android:contentDescription="@string/accessibility_notifications_button"
             />
     </FrameLayout>
-</com.android.systemui.statusbar.phone.PanelHeaderView>
+</LinearLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 237b7f7..6be6d4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -20,7 +20,6 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.view.MotionEvent;
@@ -57,17 +56,6 @@
         mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
         mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
         mHandleView = findViewById(R.id.handle);
-        PanelHeaderView header = (PanelHeaderView) findViewById(R.id.header);
-        ZenModeView zenModeView = (ZenModeView) findViewById(R.id.zenmode);
-        zenModeView.setAdapter(new ZenModeViewAdapter(mContext) {
-            @Override
-            public void configure() {
-                if (mStatusBar != null) {
-                    mStatusBar.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
-                }
-            }
-        });
-        header.setZenModeView(zenModeView);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java
deleted file mode 100644
index a28324d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 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.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-
-public class PanelHeaderView extends LinearLayout {
-    private static final String TAG = "PanelHeaderView";
-    private static final boolean DEBUG = false;
-
-    private ZenModeView mZenModeView;
-
-    public PanelHeaderView(Context context) {
-        super(context);
-    }
-
-    public PanelHeaderView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void setZenModeView(ZenModeView zmv) {
-        mZenModeView = zmv;
-    }
-
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        final boolean rt = super.dispatchTouchEvent(ev);
-        if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev);
-        if (mZenModeView != null) {
-            mZenModeView.dispatchExternalTouchEvent(ev);
-        }
-        return rt;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final boolean rt = super.onInterceptTouchEvent(ev);
-        if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev);
-        return rt;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        boolean rt = super.onTouchEvent(event);
-        if (DEBUG) logTouchEvent("onTouchEvent", rt, event);
-        return true;
-    }
-
-    private void logTouchEvent(String method, boolean rt, MotionEvent ev) {
-        Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + ev);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index c1c8946..8170b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -52,13 +52,16 @@
 import android.provider.ContactsContract.Profile;
 import android.provider.Settings;
 import android.security.KeyChain;
+import android.text.TextUtils.TruncateAt;
 import android.util.Log;
 import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -586,6 +589,31 @@
         });
         parent.addView(airplaneTile);
 
+        // Zen Mode
+        final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
+        zenModeTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showZenModeDialog();
+            }
+        });
+        mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView unused, State state) {
+                zenModeTile.setImageResource(state.iconId);
+                // TODO cut new assets
+                zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
+                zenModeTile.getImageView().setScaleX(1.5f);
+                zenModeTile.getImageView().setScaleY(1.5f);
+                // for landscape version
+                zenModeTile.getTextView().setMaxLines(2);
+                zenModeTile.getTextView().setEllipsize(TruncateAt.END);
+                // TODO content description
+                zenModeTile.setText(state.label);
+            }
+        });
+        parent.addView(zenModeTile);
+
         // Bluetooth
         if (mModel.deviceSupportsBluetooth()
                 || DEBUG_GONE_TILES) {
@@ -864,6 +892,31 @@
         dialog.show();
     }
 
+    private void showZenModeDialog() {
+        final Dialog d = new Dialog(mContext);
+        d.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        d.setCancelable(true);
+        d.setCanceledOnTouchOutside(true);
+        final ZenModeView v = new ZenModeView(mContext);
+        v.setAdapter(new ZenModeViewAdapter(mContext) {
+            @Override
+            public void configure() {
+                if (mStatusBarService != null) {
+                    mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
+                }
+                d.dismiss();
+            }
+            @Override
+            public void close() {
+                d.dismiss();
+            }
+        });
+        d.setContentView(v);
+        d.create();
+        d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+        d.show();
+    }
+
     private void applyBluetoothStatus() {
         mModel.onBluetoothStateChange(mBluetoothState);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 174cad8..c3c281c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -38,6 +38,7 @@
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.WindowManager;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
@@ -112,6 +113,9 @@
     public static class RotationLockState extends State {
         boolean visible = false;
     }
+    public static class ZenModeState extends State {
+        int zenMode = Settings.Global.ZEN_MODE_OFF;
+    }
 
     /** The callback to update a given tile. */
     interface RefreshCallback {
@@ -294,6 +298,25 @@
         }
     }
 
+    /** ContentObserver to watch display color space adjustment */
+    private class ZenModeObserver extends ContentObserver {
+        public ZenModeObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            onZenModeChanged();
+        }
+
+        public void startObserving() {
+            final ContentResolver cr = mContext.getContentResolver();
+            cr.unregisterContentObserver(this);
+            cr.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this);
+        }
+    }
+
     /** Callback for changes to remote display routes. */
     private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
         @Override
@@ -327,6 +350,7 @@
     private final DisplayInversionObserver mInversionObserver;
     private final DisplayContrastObserver mContrastObserver;
     private final DisplayColorSpaceObserver mColorSpaceObserver;
+    private final ZenModeObserver mZenModeObserver;
 
     private final MediaRouter mMediaRouter;
     private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
@@ -349,6 +373,10 @@
     private RefreshCallback mAirplaneModeCallback;
     private State mAirplaneModeState = new State();
 
+    private QuickSettingsTileView mZenModeTile;
+    private RefreshCallback mZenModeCallback;
+    private ZenModeState mZenModeState = new ZenModeState();
+
     private QuickSettingsTileView mWifiTile;
     private RefreshCallback mWifiCallback;
     private WifiState mWifiState = new WifiState();
@@ -445,6 +473,8 @@
         mContrastObserver.startObserving();
         mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
         mColorSpaceObserver.startObserving();
+        mZenModeObserver = new ZenModeObserver(mHandler);
+        mZenModeObserver.startObserving();
 
         mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
         rebindMediaRouterAsCurrentUser();
@@ -567,6 +597,30 @@
         mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
     }
 
+    // Zen Mode
+    void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mZenModeTile = view;
+        mZenModeCallback = cb;
+        onZenModeChanged();
+    }
+    private void onZenModeChanged() {
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+        mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF;
+        mZenModeState.zenMode = mode;
+        if (mode == Settings.Global.ZEN_MODE_FULL) {
+            mZenModeState.iconId = R.drawable.stat_sys_zen_full;
+            mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_FULL);
+        } else if (mode == Settings.Global.ZEN_MODE_LIMITED) {
+            mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
+            mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_LIMITED);
+        } else {
+            mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
+            mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_LIMITED);
+        }
+        mZenModeCallback.refreshView(mZenModeTile, mZenModeState);
+    }
+
     // Wifi
     void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
         mWifiTile = view;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index fa7f96a..d1c7a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -19,22 +19,16 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
-import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.PathShape;
-import android.os.AsyncTask;
-import android.os.Vibrator;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.TextPaint;
 import android.text.method.LinkMovementMethod;
-import android.text.style.RelativeSizeSpan;
 import android.text.style.URLSpan;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -62,7 +56,7 @@
     private static final Typeface CONDENSED =
             Typeface.create("sans-serif-condensed", Typeface.NORMAL);
     private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network
-    private static final int BACKGROUND = 0xff1d3741; //0x3333b5e5;
+    private static final int BACKGROUND = 0xff282828;
     private static final long DURATION = new ValueAnimator().getDuration();
     private static final long BOUNCE_DURATION = DURATION / 3;
     private static final float BOUNCE_SCALE = 0.8f;
@@ -73,23 +67,14 @@
 
     private final Context mContext;
     private final Paint mPathPaint;
-    private final TextView mHintText;
-    private final ModeSpinner mModeSpinner;
-    private final ImageView mCloseButton;
     private final ImageView mSettingsButton;
-    private final Rect mLayoutRect = new Rect();
+    private final ModeSpinner mModeSpinner;
+    private final TextView mActionButton;
+    private final View mDivider;
     private final UntilPager mUntilPager;
     private final AlarmWarning mAlarmWarning;
-    private final int mPopDuration;
 
-    private float mDownY;
-    private int mDownBottom;
-    private boolean mPeekable = true;
-    private boolean mClosing;
-    private int mBottom;
-    private int mWidthSpec;
     private Adapter mAdapter;
-    private boolean mPopped;
 
     public ZenModeView(Context context) {
         this(context, null);
@@ -100,34 +85,22 @@
         if (DEBUG) log("new %s()", getClass().getSimpleName());
         mContext = context;
 
-        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPathPaint.setStyle(Paint.Style.STROKE);
-        mPathPaint.setColor(GRAY);
-        mPathPaint.setStrokeWidth(5);
-
         final int iconSize = mContext.getResources()
                 .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
         final int topRowSize = iconSize * 2 / 3;
+        final int p = topRowSize / 7;
 
-        mCloseButton = new ImageView(mContext);
-        mCloseButton.setAlpha(0f);
-        mCloseButton.setImageDrawable(sd(closePath(topRowSize), topRowSize, mPathPaint));
-        addView(mCloseButton, new LayoutParams(topRowSize, topRowSize));
-        mCloseButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                bounce(v, null);
-                close();
-            }
-        });
+        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPathPaint.setStyle(Paint.Style.STROKE);
+        mPathPaint.setColor(GRAY);
+        mPathPaint.setStrokeWidth(p / 2);
 
         mSettingsButton = new ImageView(mContext);
-        mSettingsButton.setAlpha(0f);
-        final int p = topRowSize / 7;
         mSettingsButton.setPadding(p, p, p, p);
         mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal);
         LayoutParams lp = new LayoutParams(topRowSize, topRowSize);
-        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+        lp.topMargin = p;
+        lp.leftMargin = p;
         addView(mSettingsButton, lp);
         mSettingsButton.setOnClickListener(new View.OnClickListener() {
             @Override
@@ -140,65 +113,65 @@
         });
 
         mModeSpinner = new ModeSpinner(mContext);
-        mModeSpinner.setAlpha(0);
-        mModeSpinner.setEnabled(false);
         mModeSpinner.setId(android.R.id.title);
         lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
-        lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
+        lp.topMargin = p;
+        lp.addRule(CENTER_HORIZONTAL);
         addView(mModeSpinner, lp);
 
-        mUntilPager = new UntilPager(mContext, mPathPaint, iconSize);
-        mUntilPager.setId(android.R.id.tabhost);
-        mUntilPager.setAlpha(0);
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        mActionButton = new TextView(mContext);
+        mActionButton.setTextColor(GRAY);
+        mActionButton.setTypeface(CONDENSED);
+        mActionButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mActionButton.getTextSize() * 1.2f);
+        mActionButton.setAllCaps(true);
+        mActionButton.setGravity(Gravity.CENTER);
+        mActionButton.setPadding(p, 0, p * 2, 0);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
+        lp.topMargin = p;
+        lp.addRule(ALIGN_PARENT_RIGHT);
+        lp.addRule(ALIGN_BASELINE, mModeSpinner.getId());
+        addView(mActionButton, lp);
+        mActionButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                bounce(v, null);
+                beginOrEnd();
+            }
+        });
+
+        mDivider = new View(mContext);
+        mDivider.setId(android.R.id.empty);
+        mDivider.setBackgroundColor(GRAY);
+        lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
         lp.addRule(BELOW, mModeSpinner.getId());
+        lp.topMargin = p;
+        lp.bottomMargin = p;
+        addView(mDivider, lp);
+
+        mUntilPager = new UntilPager(mContext, mPathPaint, iconSize * 3 / 4);
+        mUntilPager.setId(android.R.id.tabhost);
+        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        lp.addRule(BELOW, mDivider.getId());
         addView(mUntilPager, lp);
 
         mAlarmWarning = new AlarmWarning(mContext);
-        mAlarmWarning.setAlpha(0);
         lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         lp.addRule(CENTER_HORIZONTAL);
         lp.addRule(BELOW, mUntilPager.getId());
+        lp.bottomMargin = p;
         addView(mAlarmWarning, lp);
-
-        mHintText = new TextView(mContext);
-        mHintText.setTypeface(CONDENSED);
-        mHintText.setText("Swipe down for Limited Interruptions");
-        mHintText.setGravity(Gravity.CENTER);
-        mHintText.setTextColor(GRAY);
-        addView(mHintText, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-
-        mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
     }
 
-    private boolean isApplicable() {
-        return mAdapter != null && mAdapter.isApplicable();
-    }
-
-    private void close() {
-        mClosing = true;
-        final int startBottom = mBottom;
-        final int max = mPeekable ? getExpandedBottom() : startBottom;
-        mHintText.animate().alpha(1).setUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float f = animation.getAnimatedFraction();
-                final int hintBottom = mHintText.getBottom();
-                final boolean isDone = f == 1;
-                setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max, isDone);
-                if (isDone) {
-                    mPeekable = true;
-                    mPopped = false;
-                    mClosing = false;
-                    mModeSpinner.updateState();
-                    if (mAdapter != null) {
-                        mAdapter.cancel();
-                    }
-                }
-            }
-        }).start();
-        mUntilPager.animate().alpha(0).start();
-        mAlarmWarning.animate().alpha(0).start();
+    private void beginOrEnd() {
+        if (mAdapter == null) return;
+        if (mAdapter.getMode() == mAdapter.getCommittedMode()) {
+            // end
+            mAdapter.setCommittedMode(Adapter.MODE_OFF);
+        } else {
+            // begin
+            mAdapter.setCommittedMode(mAdapter.getMode());
+        }
+        mAdapter.close();
     }
 
     public void setAdapter(Adapter adapter) {
@@ -218,180 +191,41 @@
     }
 
     private void updateState(boolean animate) {
-        final boolean applicable = isApplicable();
-        setVisibility(applicable ? VISIBLE : GONE);
-        if (!applicable) {
-            return;
-        }
-        if (mAdapter != null && mAdapter.getMode() == Adapter.MODE_OFF && !mPeekable) {
-            close();
-        } else {
-            mModeSpinner.updateState();
-            mUntilPager.updateState();
-            mAlarmWarning.updateState(animate);
-            final float settingsAlpha = getSettingsButtonAlpha();
-            if (settingsAlpha != mSettingsButton.getAlpha()) {
-                if (animate) {
-                    mSettingsButton.animate().alpha(settingsAlpha).start();
-                } else {
-                    mSettingsButton.setAlpha(settingsAlpha);
-                }
-            }
-            if (mPeekable && mAdapter != null && mAdapter.getMode() != Adapter.MODE_OFF) {
-                if (DEBUG) log("panic expand!");
-                mPeekable = false;
-                mModeSpinner.setEnabled(true);
-                mBottom = getExpandedBottom();
-                setExpanded(1);
+        mModeSpinner.updateState();
+        mUntilPager.updateState();
+        mAlarmWarning.updateState(animate);
+        final float settingsAlpha = isFull() ? 0 : SETTINGS_ALPHA;
+        if (settingsAlpha != mSettingsButton.getAlpha()) {
+            if (animate) {
+                mSettingsButton.animate().alpha(settingsAlpha).start();
+            } else {
+                mSettingsButton.setAlpha(settingsAlpha);
             }
         }
+        final boolean committed = mAdapter != null
+                && mAdapter.getMode() == mAdapter.getCommittedMode();
+        mActionButton.setText(committed ? "End" : "Begin");
     }
 
-    private float getSettingsButtonAlpha() {
-        final boolean full = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
-        final boolean collapsed = mHintText.getAlpha() == 1;
-        return full || collapsed ? 0 : SETTINGS_ALPHA;
-    }
-
-    private static Path closePath(int size) {
-        final int pad = size / 4;
-        final Path p = new Path();
-        p.moveTo(pad, pad);
-        p.lineTo(size - pad, size - pad);
-        p.moveTo(size - pad, pad);
-        p.lineTo(pad, size - pad);
-        return p;
+    private boolean isFull() {
+        return mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (DEBUG) log("onMeasure %s %s",
                 MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec));
-        final boolean widthExact = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
-
-        if (!widthExact || (widthMeasureSpec != mWidthSpec)) {
-            if (DEBUG) log("  super.onMeasure");
-            final int hms = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            super.onMeasure(widthMeasureSpec, hms);
-            mBottom = mPeekable ? mHintText.getMeasuredHeight() : getExpandedBottom();
-            mWidthSpec = widthMeasureSpec;
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (!isFull()) {
+            final LayoutParams lp = (LayoutParams) mModeSpinner.getLayoutParams();
+            final int mh = vh(mModeSpinner) + vh(mDivider) + vh(mUntilPager) + lp.topMargin;
+            setMeasuredDimension(getMeasuredWidth(), mh);
         }
-        if (DEBUG) log("mBottom (OM) = " + mBottom);
-        setMeasuredDimension(getMeasuredWidth(), mBottom);
-        if (DEBUG) log("  mw=%s mh=%s",
-                toString(getMeasuredWidthAndState()), toString(getMeasuredHeightAndState()));
     }
 
-    private static String toString(int sizeAndState) {
-        final int size = sizeAndState & MEASURED_SIZE_MASK;
-        final boolean tooSmall = (sizeAndState & MEASURED_STATE_TOO_SMALL) != 0;
-        return size + (tooSmall ? "TOO SMALL" : "");
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        mLayoutRect.set(left, top, right, bottom);
-        if (DEBUG) log("onLayout %s %s %dx%d", changed,
-                mLayoutRect.toShortString(), mLayoutRect.width(), mLayoutRect.height());
-        super.onLayout(changed, left, top, right, bottom);
-    }
-
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        final boolean rt = super.dispatchTouchEvent(ev);
-        if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev);
-        return rt;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final boolean rt = super.onInterceptTouchEvent(ev);
-        if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev);
-        if (isApplicable()
-                && ev.getAction() == MotionEvent.ACTION_DOWN
-                && ev.getY() > mCloseButton.getBottom()
-                && mPeekable) {
-            return true;
-        }
-        return rt;
-    }
-
-    private static void logTouchEvent(String method, boolean rt, MotionEvent event) {
-        final String action = MotionEvent.actionToString(event.getAction());
-        Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + action);
-    }
-
-    private int getExpandedBottom() {
-        int b = mModeSpinner.getMeasuredHeight() + mUntilPager.getMeasuredHeight();
-        if (mAlarmWarning.getAlpha() == 1) b += mAlarmWarning.getMeasuredHeight();
-        return b;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        boolean rt = super.onTouchEvent(event);
-        if (DEBUG) logTouchEvent("onTouchEvent", rt, event);
-        if (!isApplicable() || !mPeekable) {
-            return rt;
-        }
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            mDownY = event.getY();
-            if (DEBUG) log("  mDownY=" + mDownY);
-            mDownBottom = mBottom;
-            return true;
-        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
-            final float dy = event.getY() - mDownY;
-            if (!mPopped) {
-                mPopped = true;
-                AsyncTask.execute(mPopVibration);
-            }
-            setPeeked(mDownBottom + (int)dy, getExpandedBottom(), false);
-        } else if (event.getAction() == MotionEvent.ACTION_UP
-                || event.getAction() == MotionEvent.ACTION_CANCEL) {
-            final float dy = event.getY() - mDownY;
-            setPeeked(mDownBottom + (int)dy, getExpandedBottom(), true);
-            if (mPeekable) {
-                close();
-            }
-        }
-        return rt;
-    }
-
-    private void setPeeked(int peeked, int max, boolean isDone) {
-        if (DEBUG) log("setPeeked=" + peeked);
-        final int min = mHintText.getBottom();
-        peeked = Math.max(min, Math.min(peeked, max));
-        if (!isDone && mBottom == peeked) {
-            return;
-        }
-        if (peeked == max && isDone) {
-            mPeekable = false;
-            mModeSpinner.setEnabled(true);
-            if (mAdapter != null) {
-                mAdapter.setMode(Adapter.MODE_LIMITED);
-            }
-        }
-        if (peeked == min) {
-            mPeekable = true;
-            mModeSpinner.setEnabled(false);
-        }
-        if (DEBUG) log("  mBottom=" + peeked);
-        mBottom = peeked;
-        final float f = (peeked - min) / (float)(max - min);
-        setExpanded(f);
-        requestLayout();
-    }
-
-    private void setExpanded(float f) {
-        if (DEBUG) log("setExpanded " + f);
-        final int a = (int)(Color.alpha(BACKGROUND) * f);
-        setBackgroundColor(Color.argb(a,
-                Color.red(BACKGROUND), Color.green(BACKGROUND), Color.blue(BACKGROUND)));
-        mHintText.setAlpha(1 - f);
-        mCloseButton.setAlpha(f);
-        mModeSpinner.setAlpha(f);
-        mUntilPager.setAlpha(f);
-        mSettingsButton.setAlpha(f * getSettingsButtonAlpha());
+    private int vh(View v) {
+        LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return v.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
     }
 
     private static void log(String msg, Object... args) {
@@ -406,12 +240,6 @@
         return sd;
     }
 
-    public void dispatchExternalTouchEvent(MotionEvent ev) {
-        if (isApplicable()) {
-            onTouchEvent(ev);
-        }
-    }
-
     private static void bounce(final View v, final Runnable midBounce) {
         v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3)
             .setListener(new AnimatorListenerAdapter() {
@@ -429,13 +257,18 @@
             }).start();
     }
 
-    private final Runnable mPopVibration = new Runnable() {
-        @Override
-        public void run() {
-            Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
-            v.vibrate(mPopDuration);
-        }
-    };
+    public static String modeToString(int mode) {
+        if (mode == Adapter.MODE_OFF) return "MODE_OFF";
+        if (mode == Adapter.MODE_LIMITED) return "MODE_LIMITED";
+        if (mode == Adapter.MODE_FULL) return "MODE_FULL";
+        throw new IllegalArgumentException("Invalid mode: " + mode);
+    }
+
+    public static String modeToLabel(int mode) {
+        if (mode == Adapter.MODE_LIMITED) return "Limited interruptions";
+        if (mode == Adapter.MODE_FULL) return "Zero interruptions";
+        throw new UnsupportedOperationException("Unsupported mode: " + mode);
+    }
 
     private final class UntilPager extends RelativeLayout {
         private final ImageView mPrev;
@@ -448,6 +281,7 @@
         public UntilPager(Context context, Paint pathPaint, int iconSize) {
             super(context);
             mText1 = new TextView(mContext);
+            mText1.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText1.getTextSize() * 1.2f);
             mText1.setTypeface(CONDENSED);
             mText1.setTextColor(GRAY);
             mText1.setGravity(Gravity.CENTER);
@@ -456,6 +290,7 @@
             mText = mText1;
 
             mText2 = new TextView(mContext);
+            mText2.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText1.getTextSize());
             mText2.setTypeface(CONDENSED);
             mText2.setTextColor(GRAY);
             mText2.setAlpha(0);
@@ -478,7 +313,7 @@
             });
 
             lp = new LayoutParams(iconSize, iconSize);
-            lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+            lp.addRule(ALIGN_PARENT_RIGHT);
             final View v2 = new View(mContext);
             v2.setBackgroundColor(BACKGROUND);
             addView(v2, lp);
@@ -532,9 +367,7 @@
         }
 
         private void setText(final TextView textView, final ExitCondition ec) {
-            SpannableStringBuilder ss = new SpannableStringBuilder(ec.line1 + "\n" + ec.line2);
-            ss.setSpan(new RelativeSizeSpan(1.5f), (ec.line1 + "\n").length(), ss.length(),
-                    Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+            SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary);
             if (ec.action != null) {
                 ss.setSpan(new CustomLinkSpan() {
                     @Override
@@ -542,7 +375,7 @@
                         // TODO wire up links
                         Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show();
                     }
-                }, (ec.line1 + "\n").length(), ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+                }, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
                 textView.setMovementMethod(LinkMovementMethod.getInstance());
             } else {
                 textView.setMovementMethod(null);
@@ -558,7 +391,7 @@
         }
 
         private Path prevPath(int size) {
-            final int hp = size / 3;
+            final int hp = size * 3 / 8;
             final int vp = size / 4;
             final Path p = new Path();
             p.moveTo(size - hp, vp);
@@ -568,7 +401,7 @@
         }
 
         private Path nextPath(int size) {
-            final int hp = size / 3;
+            final int hp = size * 3 / 8;
             final int vp = size / 4;
             Path p = new Path();
             p.moveTo(hp, vp);
@@ -603,12 +436,14 @@
         public static final int MODE_LIMITED = 1;
         public static final int MODE_FULL = 2;
 
-        boolean isApplicable();
         void configure();
+        void close();
         int getMode();
         void setMode(int mode);
+        int getCommittedMode();
+        void setCommittedMode(int mode);
         void select(ExitCondition ec);
-        void cancel();
+        void init();
         void setCallbacks(Callbacks callbacks);
         ExitCondition getExitCondition(int d);
         int getExitConditionCount();
@@ -637,38 +472,38 @@
                 }
 
                 @Override
-                public View getDropDownView(int position, View convertView, ViewGroup parent) {
+                public View getDropDownView(final int position, View convertView, ViewGroup parent) {
                     if (DEBUG) log("getDropDownView %s cv=%s parent=%s",
                             position, convertView, parent);
                     final TextView tv = convertView != null ? (TextView) convertView
                             : new TextView(context);
                     final int mode = getItem(position);
-                    tv.setText(modeToString(mode));
+                    tv.setText(modeToLabel(mode));
+                    final boolean inDropdown = parent instanceof ListView;
                     if (convertView == null) {
                         if (DEBUG) log(" setting up view");
                         tv.setTextColor(GRAY);
                         tv.setTypeface(CONDENSED);
                         tv.setAllCaps(true);
-                        tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f);
+                        tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.2f);
                         final int p = (int) tv.getTextSize() / 2;
-                        if (parent instanceof ListView) {
-                            tv.setPadding(p, p, p, p);
+                        if (inDropdown) {
+                            tv.setPadding(p, p, 0, p);
                         } else {
                             tv.setGravity(Gravity.CENTER_HORIZONTAL);
-                            tv.setPadding(p, 0, p, 0);
+                            tv.setPadding(p, 0, 0, 0);
                         }
                     }
                     tv.setOnTouchListener(new OnTouchListener(){
                         @Override
                         public boolean onTouch(View v, MotionEvent event) {
-                            if (DEBUG) log("onTouch %s %s", tv.getText(),
-                                    MotionEvent.actionToString(event.getAction()));
-                            if (mAdapter != null) {
+                            if (DEBUG) log("onTouch %s %s inDropdown=%s", tv.getText(),
+                                    MotionEvent.actionToString(event.getAction()), inDropdown);
+                            if (inDropdown && mAdapter != null) {
                                 mAdapter.setMode(mode);
                             }
                             return false;
                         }
-
                     });
                     return tv;
                 }
@@ -688,16 +523,10 @@
                 if (getAdapter().getItem(i).equals(mode)) {
                     if (DEBUG) log("  setting selection = " + i);
                     setSelection(i, true);
-                    return;
+                    onDetachedFromWindow();
                 }
             }
         }
-
-        private String modeToString(int mode) {
-            if (mode == Adapter.MODE_LIMITED) return "Limited interruptions";
-            if (mode == Adapter.MODE_FULL) return "Zero interruptions";
-            throw new UnsupportedOperationException("Unsupported mode: " + mode);
-        }
     }
 
     private final class AlarmWarning extends LinearLayout {
@@ -724,29 +553,12 @@
         }
 
         public void updateState(boolean animate) {
-            final boolean visible = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
-            final float alpha = visible ? 1 : 0;
+            final float alpha = isFull() ? 1 : 0;
             if (alpha == getAlpha()) {
                 return;
             }
             if (animate) {
-                final boolean in = alpha == 1;
-                animate().alpha(alpha).setUpdateListener(new AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        if (mPeekable || mClosing) {
-                            return;
-                        }
-                        float f = animation.getAnimatedFraction();
-                        if (!in) {
-                            f = 1 - f;
-                        }
-                        ZenModeView.this.mBottom = mUntilPager.getBottom()
-                                + (int)(mAlarmWarning.getMeasuredHeight() * f);
-                        if (DEBUG) log("mBottom (AW) = " + mBottom);
-                        requestLayout();
-                    }
-                }).start();
+                animate().alpha(alpha).start();
             } else {
                 setAlpha(alpha);
                 requestLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
index 39c4faa..d2067a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
@@ -35,23 +35,19 @@
     private final Handler mHandler = new Handler();
     private final SettingsObserver mObserver;
     private final List<ExitCondition> mExits = Arrays.asList(
-            newExit("Until you delete this", "Until", "You delete this"));
+            newExit("Until you turn this off", "Until", "You turn this off"));
 
     private Callbacks mCallbacks;
     private int mExitIndex;
-    private boolean mDeviceProvisioned;
     private int mMode;
+    private int mCommittedMode;
 
     public ZenModeViewAdapter(Context context) {
         mContext = context;
         mResolver = mContext.getContentResolver();
         mObserver = new SettingsObserver(mHandler);
         mObserver.init();
-    }
-
-    @Override
-    public boolean isApplicable() {
-        return mDeviceProvisioned;
+        init();
     }
 
     @Override
@@ -61,6 +57,18 @@
 
     @Override
     public void setMode(int mode) {
+        if (mode == mMode) return;
+        mMode = mode;
+        dispatchChanged();
+    }
+
+    @Override
+    public int getCommittedMode() {
+        return mCommittedMode;
+    }
+
+    @Override
+    public void setCommittedMode(int mode) {
         final int v = mode == MODE_LIMITED ? Settings.Global.ZEN_MODE_LIMITED
                     : mode == MODE_FULL ? Settings.Global.ZEN_MODE_FULL
                     : Settings.Global.ZEN_MODE_OFF;
@@ -74,12 +82,21 @@
     }
 
     @Override
-    public void cancel() {
+    public void init() {
         if (mExitIndex != 0) {
             mExitIndex = 0;
-            mHandler.post(mChange);
+            dispatchChanged();
         }
-        setMode(MODE_OFF);
+        final int mode = mCommittedMode == MODE_FULL ? MODE_FULL : MODE_LIMITED;
+        if (mode != mMode) {
+            mMode = mode;
+            dispatchChanged();
+        }
+    }
+
+    private void dispatchChanged() {
+        mHandler.removeCallbacks(mChanged);
+        mHandler.post(mChanged);
     }
 
     @Override
@@ -111,7 +128,7 @@
             return;
         }
         mExitIndex = i;
-        mHandler.post(mChange);
+        dispatchChanged();
     }
 
     private static ExitCondition newExit(String summary, String line1, String line2) {
@@ -122,7 +139,7 @@
         return rt;
     }
 
-    private final Runnable mChange = new Runnable() {
+    private final Runnable mChanged = new Runnable() {
         public void run() {
             if (mCallbacks == null) {
                 return;
@@ -145,24 +162,19 @@
             mResolver.registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
                     false, this);
-            mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
-                    false, this);
         }
 
         @Override
         public void onChange(boolean selfChange) {
             loadSettings();
-            mChange.run();  // already on handler
+            mChanged.run();  // already on handler
         }
 
         private void loadSettings() {
-            mDeviceProvisioned = Settings.Global.getInt(mResolver,
-                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-            mMode = getMode();
+            mCommittedMode = getModeFromSetting();
         }
 
-        private int getMode() {
+        private int getModeFromSetting() {
             final int v = Settings.Global.getInt(mResolver,
                     Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
             if (v == Settings.Global.ZEN_MODE_LIMITED) return MODE_LIMITED;