Implement new volume UI design.

- Add segmented zen-mode picker to the rocker UI.
- Add a new "no interruptions" value to the zen setting.
- Implement expandable condition subpanel on the rocker UI.
- Remove the old circle&slash icons.
- Suppress alarm sounds if in "no interruptions" mode.
- Add warning re: alarms to the condition UI.
- Allow rocker UI to display over the keyguard.
- Remove Notifications QS tile.
- Realign volume rocker to the top of the screen.
- Add support for new "days" sleepMode.
- New icon policy rules for "volume" slot.
- New important icon (star).

Associated Settings change:
  I6ed56791784968adfbd684f490dbbebed285a2dd

Bug:15831713
Change-Id: I35afe38646f04d2ba0dbac11c2c6356120a33694
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 53daaae..b6d6767 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.volume;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
@@ -38,24 +36,21 @@
 import android.media.session.MediaController;
 import android.media.session.MediaController.VolumeInfo;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Vibrator;
+import android.provider.Settings.Global;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -71,7 +66,8 @@
  * @hide
  */
 public class VolumePanel extends Handler {
-    private static boolean LOGD = false;
+    private static final String TAG = "VolumePanel";
+    private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
 
@@ -89,7 +85,6 @@
     private static final int FREE_DELAY = 10000;
     private static final int TIMEOUT_DELAY = 3000;
     private static final int TIMEOUT_DELAY_EXPANDED = 10000;
-    private static final float ICON_PULSE_SCALE = 1.3f;
 
     private static final int MSG_VOLUME_CHANGED = 0;
     private static final int MSG_FREE_RESOURCES = 1;
@@ -105,6 +100,7 @@
     private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
     private static final int MSG_LAYOUT_DIRECTION = 12;
     private static final int MSG_ZEN_MODE_CHANGED = 13;
+    private static final int MSG_USER_ACTIVITY = 14;
 
     // Pseudo stream type for master volume
     private static final int STREAM_MASTER = -100;
@@ -114,7 +110,6 @@
     protected final Context mContext;
     private final AudioManager mAudioManager;
     private final ZenModeController mZenController;
-    private final Interpolator mFastOutSlowInInterpolator;
     private boolean mRingIsSilent;
     private boolean mVoiceCapable;
     private boolean mZenModeCapable;
@@ -135,18 +130,12 @@
     private final ViewGroup mPanel;
     /** Contains the slider and its touchable icons */
     private final ViewGroup mSliderPanel;
-    /** The button that expands the dialog to show the zen panel */
-    private final ImageView mExpandButton;
-    /** Dummy divider icon that needs to vanish with the expand button */
-    private final View mExpandDivider;
     /** The zen mode configuration panel view stub */
     private final ViewStub mZenPanelStub;
     /** The zen mode configuration panel view, once inflated */
     private ZenModePanel mZenPanel;
-    /** Dummy divider icon that needs to vanish with the zen panel */
-    private final View mZenPanelDivider;
 
-    private ZenModePanel.Callback mZenPanelCallback;
+    private Callback mCallback;
 
     /** Currently active stream that shows up at the top of the list of sliders */
     private int mActiveStreamType = -1;
@@ -231,7 +220,6 @@
         ViewGroup group;
         ImageView icon;
         SeekBar seekbarView;
-        View seekbarContainer;
         int iconRes;
         int iconMuteRes;
     }
@@ -280,13 +268,11 @@
 
 
     public VolumePanel(Context context, ViewGroup parent, ZenModeController zenController) {
-        mTag = String.format("VolumePanel%s.%08x", parent == null ? "Dialog" : "", hashCode());
+        mTag = String.format("%s.%s.%08x", TAG, parent == null ? "Dialog" : "Embed", hashCode());
         mContext = context;
         mParent = parent;
         mZenController = zenController;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_slow_in);
 
         // For now, only show master volume if master volume is supported
         final Resources res = context.getResources();
@@ -318,12 +304,11 @@
             lp.token = null;
             // Offset from the top
             lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
-            lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.volume_panel_width);
-            lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+            lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
             lp.format = PixelFormat.TRANSLUCENT;
-            lp.windowAnimations = R.style.Animation_VolumePanel;
+            lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+            lp.gravity = Gravity.TOP;
             window.setAttributes(lp);
-            window.setGravity(Gravity.TOP);
             window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
             window.requestFeature(Window.FEATURE_NO_TITLE);
             window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
@@ -337,7 +322,7 @@
                 public void onDismiss(DialogInterface dialog) {
                     mActiveStreamType = -1;
                     mAudioManager.forceVolumeControlStream(mActiveStreamType);
-                    collapse();
+                    setZenPanelVisible(false);
                 }
             });
 
@@ -362,19 +347,14 @@
         }
         mPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.visible_panel);
         mSliderPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.slider_panel);
-        mExpandButton = (ImageView) mView.findViewById(com.android.systemui.R.id.expand_button);
-        mExpandDivider = mView.findViewById(com.android.systemui.R.id.expand_button_divider);
         mZenPanelStub = (ViewStub)mView.findViewById(com.android.systemui.R.id.zen_panel_stub);
-        mZenPanelDivider = mView.findViewById(com.android.systemui.R.id.zen_panel_divider);
 
         mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
 
         mZenModeCapable = !useMasterVolume && mZenController != null;
-        mZenPanelDivider.setVisibility(View.GONE);
-        mExpandButton.setOnClickListener(mClickListener);
-        updateZenMode(mZenController == null ? false : mZenController.isZen());
+        updateZenMode(mZenController != null ? mZenController.getZen() : Global.ZEN_MODE_OFF);
         mZenController.addCallback(mZenCallback);
 
         final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
@@ -502,17 +482,7 @@
                         toggle(sc);
                     }
                 });
-                sc.icon.setOnLongClickListener(new OnLongClickListener() {
-                    @Override
-                    public boolean onLongClick(View v) {
-                        resetTimeout();
-                        longToggle(sc);
-                        return true;
-                    }
-                });
             }
-            sc.seekbarContainer =
-                    sc.group.findViewById(com.android.systemui.R.id.seekbar_container);
             sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar);
             final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
@@ -533,29 +503,19 @@
         }
     }
 
-    private void longToggle(StreamControl sc) {
-        if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
-            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-            postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND);
-        } else {
-            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
-            postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI); // disable the slider
-        }
-    }
-
     private void reorderSliders(int activeStreamType) {
         mSliderPanel.removeAllViews();
 
         final StreamControl active = mStreamControls.get(activeStreamType);
         if (active == null) {
-            Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
+            Log.e(TAG, "Missing stream type! - " + activeStreamType);
             mActiveStreamType = -1;
         } else {
             mSliderPanel.addView(active.group);
             mActiveStreamType = activeStreamType;
             active.group.setVisibility(View.VISIBLE);
             updateSlider(active);
-            updateZenMode(mZenController == null ? false : mZenController.isZen());
+            setZenPanelVisible(isNotificationOrRing(mActiveStreamType));
         }
     }
 
@@ -575,6 +535,7 @@
 
     private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) {
         final boolean wasEnabled = sc.seekbarView.isEnabled();
+        final boolean isRinger = isNotificationOrRing(sc.streamType);
         if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
             // never disable touch interactions for remote playback, the muting is not tied to
             // the state of the phone.
@@ -583,40 +544,37 @@
                         (sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
                         (sConfirmSafeVolumeDialog != null)) {
             sc.seekbarView.setEnabled(false);
-        } else if (isNotificationOrRing(sc.streamType)
-                && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
+        } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
             sc.seekbarView.setEnabled(false);
+            sc.icon.setEnabled(false);
+            sc.icon.setClickable(false);
         } else {
             sc.seekbarView.setEnabled(true);
+            sc.icon.setEnabled(true);
         }
-        // pulse the ringer icon when the disabled slider is touched in silent mode
-        if (sc.icon.isClickable() && wasEnabled != sc.seekbarView.isEnabled()) {
+        // show the silent hint when the disabled slider is touched in silent mode
+        if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) {
             if (sc.seekbarView.isEnabled()) {
-                sc.seekbarContainer.setOnTouchListener(null);
+                sc.group.setOnTouchListener(null);
+                sc.icon.setClickable(true);
             } else {
-                sc.seekbarContainer.setOnTouchListener(new View.OnTouchListener() {
+                final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() {
                     @Override
                     public boolean onTouch(View v, MotionEvent event) {
                         resetTimeout();
-                        pulseIcon(sc.icon);
+                        showSilentHint();
                         return false;
                     }
-                });
+                };
+                sc.group.setOnTouchListener(showHintOnTouch);
             }
         }
     }
 
-    private void pulseIcon(final ImageView icon) {
-        if (icon.getScaleX() != 1) return;  // already running
-        icon.animate().cancel();
-        icon.animate().scaleX(ICON_PULSE_SCALE).scaleY(ICON_PULSE_SCALE)
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        icon.animate().scaleX(1).scaleY(1).setListener(null);
-                    }
-                });
+    private void showSilentHint() {
+        if (mZenPanel != null) {
+            mZenPanel.showSilentHint();
+        }
     }
 
     private static boolean isNotificationOrRing(int streamType) {
@@ -624,47 +582,45 @@
                 || streamType == AudioManager.STREAM_NOTIFICATION;
     }
 
-    public void setZenModePanelCallback(ZenModePanel.Callback callback) {
-        mZenPanelCallback = callback;
+    public void setCallback(Callback callback) {
+        mCallback = callback;
     }
 
-    private void expand() {
-        if (LOGD) Log.d(mTag, "expand mZenPanel=" + mZenPanel);
-        if (mZenPanel == null) {
-            mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
-            final boolean isDialog = mDialog != null;
-            mZenPanel.init(mZenController, isDialog ? 'D' : 'E', isDialog);
-            mZenPanel.setCallback(new ZenModePanel.Callback() {
-                @Override
-                public void onMoreSettings() {
-                    if (mZenPanelCallback != null) {
-                        mZenPanelCallback.onMoreSettings();
+    private void setZenPanelVisible(boolean visible) {
+        if (LOGD) Log.d(mTag, "setZenPanelVisible " + visible + " mZenPanel=" + mZenPanel);
+        if (visible) {
+            if (mZenPanel == null) {
+                mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
+                mZenPanel.init(mZenController, mDialog != null ? 'D' : 'E');
+                mZenPanel.setCallback(new ZenModePanel.Callback() {
+                    @Override
+                    public void onMoreSettings() {
+                        if (mCallback != null) {
+                            mCallback.onZenSettings();
+                        }
                     }
-                }
 
-                @Override
-                public void onInteraction() {
-                    resetTimeout();
-                    if (mZenPanelCallback != null) {
-                        mZenPanelCallback.onInteraction();
+                    @Override
+                    public void onInteraction() {
+                        resetTimeout();
                     }
-                }
-            });
-        }
-        mZenPanel.setVisibility(View.VISIBLE);
-        mZenPanelDivider.setVisibility(View.VISIBLE);
-        mTimeoutDelay = TIMEOUT_DELAY_EXPANDED;
-        resetTimeout();
-    }
 
-    private void collapse() {
-        if (LOGD) Log.d(mTag, "collapse mZenPanel=" + mZenPanel);
-        if (mZenPanel != null) {
-            mZenPanel.setVisibility(View.GONE);
+                    @Override
+                    public void onExpanded(boolean expanded) {
+                        mTimeoutDelay = expanded ? TIMEOUT_DELAY_EXPANDED : TIMEOUT_DELAY;
+                        resetTimeout();
+                    }
+                });
+            }
+            mZenPanel.setVisibility(View.VISIBLE);
+            resetTimeout();
+        } else {
+            if (mZenPanel != null) {
+                mZenPanel.setVisibility(View.GONE);
+            }
+            mTimeoutDelay = TIMEOUT_DELAY;
+            resetTimeout();
         }
-        mZenPanelDivider.setVisibility(View.GONE);
-        mTimeoutDelay = TIMEOUT_DELAY;
-        resetTimeout();
     }
 
     public void updateStates() {
@@ -675,25 +631,14 @@
         }
     }
 
-    private void updateZenMode(boolean zen) {
-        if (mZenModeCapable) {
-            final boolean show = isNotificationOrRing(mActiveStreamType);
-            mExpandButton.setVisibility(show ? View.VISIBLE : View.GONE);
-            mExpandDivider.setVisibility(show ? View.VISIBLE : View.GONE);
-            mExpandButton.setImageResource(zen ? com.android.systemui.R.drawable.ic_vol_zen_on
-                    : com.android.systemui.R.drawable.ic_vol_zen_off);
-            if (show && !zen) {
-                collapse();
-            }
-        } else {
-            mExpandButton.setVisibility(View.GONE);
-            mExpandDivider.setVisibility(View.GONE);
-        }
+    private void updateZenMode(int zen) {
+        final boolean show = mZenModeCapable && isNotificationOrRing(mActiveStreamType);
+        setZenPanelVisible(show);
     }
 
-    public void postZenModeChanged(boolean zen) {
+    public void postZenModeChanged(int zen) {
         removeMessages(MSG_ZEN_MODE_CHANGED);
-        obtainMessage(MSG_ZEN_MODE_CHANGED, zen ? 1 : 0, 0).sendToTarget();
+        obtainMessage(MSG_ZEN_MODE_CHANGED, zen).sendToTarget();
     }
 
     public void postVolumeChanged(int streamType, int flags) {
@@ -955,8 +900,8 @@
         }
 
         // Pulse the slider icon if an adjustment was suppressed due to silent mode.
-        if (sc != null && (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
-            pulseIcon(sc.icon);
+        if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
+            showSilentHint();
         }
     }
 
@@ -1233,15 +1178,23 @@
                 break;
 
             case MSG_ZEN_MODE_CHANGED:
-                updateZenMode(msg.arg1 != 0);
+                updateZenMode(msg.arg1);
+                break;
+
+            case MSG_USER_ACTIVITY:
+                if (mCallback != null) {
+                    mCallback.onInteraction();
+                }
                 break;
         }
     }
 
-    public void resetTimeout() {
+    private void resetTimeout() {
         if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis());
         removeMessages(MSG_TIMEOUT);
         sendEmptyMessageDelayed(MSG_TIMEOUT, mTimeoutDelay);
+        removeMessages(MSG_USER_ACTIVITY);
+        sendEmptyMessage(MSG_USER_ACTIVITY);
     }
 
     private void forceTimeout() {
@@ -1273,29 +1226,8 @@
         }
     };
 
-    private final View.OnClickListener mClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (v == mExpandButton && mZenController != null) {
-                final boolean newZen = !mZenController.isZen();
-                AsyncTask.execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        mZenController.setZen(newZen);
-                    }
-                });
-                if (newZen) {
-                    expand();
-                } else {
-                    collapse();
-                }
-            }
-            resetTimeout();
-        }
-    };
-
     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
-        public void onZenChanged(boolean zen) {
+        public void onZenChanged(int zen) {
             postZenModeChanged(zen);
         }
     };
@@ -1305,4 +1237,9 @@
             onRemoteVolumeUpdateIfShown();
         }
     };
+
+    public interface Callback {
+        void onZenSettings();
+        void onInteraction();
+    }
 }