Merge "Move and reshape volume dialog"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index fac254a..f563794 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.systemui.HardwareUiLayout
+<com.android.systemui.volume.VolumeUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -21,18 +21,19 @@
     android:clipChildren="false" >
     <RelativeLayout
         android:id="@+id/volume_dialog"
-        android:layout_width="@dimen/volume_dialog_panel_width"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|end"
         android:paddingTop="@dimen/volume_row_padding_bottom"
-        android:layout_margin="12dp"
-        android:background="?android:attr/actionBarItemBackground"
-        android:translationZ="8dp" >
+        android:background="@drawable/rounded_full_bg_bottom"
+        android:translationZ="8dp"
+        android:clipChildren="false" >
 
         <LinearLayout
             android:id="@+id/volume_dialog_content"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:clipChildren="false"
+            android:clipToPadding="false"
             android:orientation="vertical" >
 
             <LinearLayout
@@ -42,7 +43,55 @@
                 android:orientation="vertical" >
                 <!-- volume rows added and removed here! :-) -->
             </LinearLayout>
-        </LinearLayout>
 
+            <!-- special row for ringer mode -->
+            <RelativeLayout
+                android:id="@+id/ringer_mode"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@drawable/rounded_bg_full"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:layout_margin="10dp">
+
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/ringer_icon"
+                    style="@style/VolumeButtons"
+                    android:background="?android:selectableItemBackgroundBorderless"
+                    android:layout_width="@dimen/volume_button_size"
+                    android:layout_height="@dimen/volume_button_size"
+                    android:layout_alignParentStart="true"
+                    android:layout_centerVertical="true"
+                    android:soundEffectsEnabled="false" />
+
+                <TextView
+                    android:id="@+id/ringer_title"
+                    android:text="@string/stream_ring"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:layout_alignParentStart="true"
+                    android:layout_centerVertical="true"
+                    android:layout_toEndOf="@+id/ringer_icon"
+                    android:layout_marginStart="64dp"
+                    android:textColor="?android:attr/colorControlNormal"
+                    android:textAppearance="?android:attr/textAppearanceSmall"
+                    android:paddingStart="@dimen/volume_row_header_padding_start" />
+
+                <TextView
+                    android:id="@+id/ringer_status"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:layout_alignParentEnd="true"
+                    android:layout_centerVertical="true"
+                    android:layout_marginEnd="14dp"
+                    android:maxLines="1"
+                    android:textColor="?android:attr/colorControlNormal"
+                    android:textAppearance="?android:attr/textAppearanceSmall" />
+
+            </RelativeLayout>
+        </LinearLayout>
     </RelativeLayout>
-</com.android.systemui.HardwareUiLayout>
+</com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 659c5a8..62ab74d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1248,6 +1248,10 @@
     <string name="stream_tts" translatable="false">Transmitted Through Speaker</string> <!-- STREAM_TTS -->
     <string name="stream_accessibility">Accessibility</string> <!-- STREAM_ACCESSIBILITY -->
 
+    <string name="volume_ringer_status_normal">Ring</string>
+    <string name="volume_ringer_status_vibrate">Vibrate</string>
+    <string name="volume_ringer_status_silent">Mute</string>
+
     <string name="volume_stream_muted" translatable="false">%s silent</string>
     <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
     <string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0d41e20..3e70980 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -30,7 +30,6 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.ColorStateList;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
@@ -67,8 +66,6 @@
 
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.VolumeDialog;
 import com.android.systemui.plugins.VolumeDialogController;
@@ -97,11 +94,12 @@
     private final VolumeDialogController mController;
 
     private Window mWindow;
-    private HardwareUiLayout mHardwareLayout;
     private CustomDialog mDialog;
     private ViewGroup mDialogView;
     private ViewGroup mDialogRowsView;
     private ViewGroup mDialogContentView;
+    private ImageButton mRingerIcon;
+    private TextView mRingerStatus;
     private final List<VolumeRow> mRows = new ArrayList<>();
     private ConfigurableTexts mConfigurableTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -111,6 +109,7 @@
     private final Accessibility mAccessibility = new Accessibility();
     private final ColorStateList mActiveSliderTint;
     private final ColorStateList mInactiveSliderTint;
+    private VolumeUiLayout mHardwareLayout;
 
     private boolean mShowing;
     private boolean mShowA11yStream;
@@ -160,17 +159,34 @@
         mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
                 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
-        mWindow.addFlags(
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        mWindow.setTitle(VolumeDialogImpl.class.getSimpleName());
         mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
         mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
 
         mDialog.setContentView(R.layout.volume_dialog);
-        mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
+        mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+            @Override
+            public void onShow(DialogInterface dialog) {
+                mDialogView.setTranslationY(-mDialogView.getHeight());
+                mDialogView.setAlpha(0);
+                mDialogView.animate()
+                        .alpha(1)
+                        .translationY(0)
+                        .setDuration(300)
+                        .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
+                        .withEndAction(() -> {
+                            mWindow.getDecorView().requestAccessibilityFocus();
+                        })
+                        .start();
+            }
+        });
+        mDialogView = mDialog.findViewById(R.id.volume_dialog);
         mDialogView.setOnHoverListener(new View.OnHoverListener() {
             @Override
             public boolean onHover(View v, MotionEvent event) {
@@ -181,18 +197,20 @@
                 return true;
             }
         });
-        mHardwareLayout = HardwareUiLayout.get(mDialogView);
+        mHardwareLayout = VolumeUiLayout.get(mDialogView);
         mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
 
         mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
         mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
+        mRingerIcon = mDialogContentView.findViewById(R.id.ringer_icon);
+        mRingerStatus = mDialogContentView.findViewById(R.id.ringer_status);
 
         if (mRows.isEmpty()) {
             addRow(AudioManager.STREAM_MUSIC,
                     R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
             if (!AudioSystem.isSingleVolume(mContext)) {
                 addRow(AudioManager.STREAM_RING,
-                        R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
+                        R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, false);
                 addRow(AudioManager.STREAM_ALARM,
                         R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
                 addRow(AudioManager.STREAM_VOICE_CALL,
@@ -208,6 +226,7 @@
             addExistingRows();
         }
         updateRowsH(getActiveRow());
+        initRingerH();
     }
 
     private ColorStateList loadColorStateList(int colorResId) {
@@ -374,6 +393,30 @@
         }
     }
 
+    public void initRingerH() {
+        mRingerIcon.setOnClickListener(v -> {
+            Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING,
+                    mRingerIcon.getTag());
+            final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+            final boolean hasVibrator = mController.hasVibrator();
+            if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+                if (hasVibrator) {
+                    mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+                } else {
+                    final boolean wasZero = ss.level == 0;
+                    mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
+                }
+            } else {
+                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+                if (ss.level == 0) {
+                    mController.setStreamVolume(AudioManager.STREAM_RING, 1);
+                }
+            }
+            updateRingerH();
+        });
+        updateRingerH();
+    }
+
     public void show(int reason) {
         mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
     }
@@ -389,27 +432,12 @@
         rescheduleTimeoutH();
         if (mShowing) return;
         mShowing = true;
-        mHardwareLayout.setTranslationX(getAnimTranslation());
-        mHardwareLayout.setAlpha(0);
-        mHardwareLayout.animate()
-                .alpha(1)
-                .translationX(0)
-                .setDuration(300)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .withEndAction(() -> {
-                    mDialog.show();
-                    mWindow.getDecorView().requestAccessibilityFocus();
-                })
-                .start();
+
+        mDialog.show();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
         mController.notifyVisible(true);
     }
 
-    private float getAnimTranslation() {
-        return mContext.getResources().getDimension(
-                R.dimen.volume_dialog_panel_width) / 2;
-    }
-
     protected void rescheduleTimeoutH() {
         mHandler.removeMessages(H.DISMISS);
         final int timeout = computeTimeoutH();
@@ -423,7 +451,6 @@
         if (mAccessibility.mFeedbackEnabled) return 20000;
         if (mHovering) return 16000;
         if (mSafetyWarning != null) return 5000;
-        if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
         return 3000;
     }
 
@@ -431,16 +458,22 @@
         mHandler.removeMessages(H.DISMISS);
         mHandler.removeMessages(H.SHOW);
         if (!mShowing) return;
+        mDialogView.animate().cancel();
         mShowing = false;
-        mHardwareLayout.setTranslationX(0);
-        mHardwareLayout.setAlpha(1);
-        mHardwareLayout.animate()
+
+        mDialogView.setTranslationY(0);
+        mDialogView.setAlpha(1);
+        mDialogView.animate()
                 .alpha(0)
-                .translationX(getAnimTranslation())
-                .setDuration(300)
-                .withEndAction(() -> mDialog.dismiss())
+                .translationY(-mDialogView.getHeight())
+                .setDuration(250)
                 .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
+                .withEndAction(() -> mHandler.postDelayed(() -> {
+                    if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
+                    mDialog.dismiss();
+                }, 50))
                 .start();
+
         if (mAccessibilityMgr.isEnabled()) {
             AccessibilityEvent event =
                     AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -493,6 +526,53 @@
         }
     }
 
+    protected void updateRingerH() {
+        if (mState != null) {
+            final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
+            switch (mState.ringerModeInternal) {
+                case AudioManager.RINGER_MODE_VIBRATE:
+                    mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
+                    mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
+                    mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
+                    break;
+                case AudioManager.RINGER_MODE_SILENT:
+                    mRingerStatus.setText(R.string.volume_ringer_status_silent);
+                    mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+                    mRingerIcon.setContentDescription(mContext.getString(
+                            R.string.volume_stream_content_description_unmute,
+                            getStreamLabelH(ss)));
+                    mRingerIcon.setTag(Events.ICON_STATE_MUTE);
+                    break;
+                case AudioManager.RINGER_MODE_NORMAL:
+                default:
+                    boolean muted = (mAutomute && ss.level == 0) || ss.muted ? true : false;
+                    if (muted) {
+                        mRingerStatus.setText(R.string.volume_ringer_status_silent);
+                        mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+                        mRingerIcon.setContentDescription(mContext.getString(
+                                R.string.volume_stream_content_description_unmute,
+                                getStreamLabelH(ss)));
+                        mRingerIcon.setTag(Events.ICON_STATE_MUTE);
+                    } else {
+                        mRingerStatus.setText(R.string.volume_ringer_status_normal);
+                        mRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
+                        if (mController.hasVibrator()) {
+                            mRingerIcon.setContentDescription(mContext.getString(
+                                    mShowA11yStream
+                                            ? R.string.volume_stream_content_description_vibrate_a11y
+                                            : R.string.volume_stream_content_description_vibrate,
+                                    getStreamLabelH(ss)));
+
+                        } else {
+                            mRingerIcon.setContentDescription(getStreamLabelH(ss));
+                        }
+                        mRingerIcon.setTag(Events.ICON_STATE_UNMUTE);
+                    }
+                    break;
+            }
+        }
+    }
+
     private void trimObsoleteH() {
         if (D.BUG) Log.d(TAG, "trimObsoleteH");
         for (int i = mRows.size() - 1; i >= 0; i--) {
@@ -529,6 +609,7 @@
         for (VolumeRow row : mRows) {
             updateVolumeRowH(row);
         }
+        updateRingerH();
     }
 
     private void updateVolumeRowH(VolumeRow row) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
new file mode 100644
index 0000000..49ac9b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.volume;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+
+public class VolumeUiLayout extends FrameLayout  {
+
+    public VolumeUiLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
+    }
+
+    @Override
+    public ViewOutlineProvider getOutlineProvider() {
+        return super.getOutlineProvider();
+    }
+
+    public void setOutsideTouchListener(OnClickListener onClickListener) {
+        requestLayout();
+        setOnClickListener(onClickListener);
+        setClickable(true);
+        setFocusable(true);
+    }
+
+    public static VolumeUiLayout get(View v) {
+        if (v instanceof VolumeUiLayout) return (VolumeUiLayout) v;
+        if (v.getParent() instanceof View) {
+            return get((View) v.getParent());
+        }
+        return null;
+    }
+
+    private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
+        inoutInfo.setTouchableInsets(
+                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+    };
+}