Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36dd4f1f authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Move and reshape volume dialog

- Move the volume dialog back to the top
- curve some corners
- Add a ringer toggle row

Bug: 63096355
Test: manual
Change-Id: Ife8a3fa4fabf3a0f26ddca3cf05b16425b325ef3
parent af807e02
Loading
Loading
Loading
Loading
+57 −8
Original line number Diff line number Diff line
@@ -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
+4 −0
Original line number Diff line number Diff line
@@ -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>
+118 −37
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.app.KeyguardManager;
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 android.widget.TextView;

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 @@ public class VolumeDialogImpl implements VolumeDialog {
    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 @@ public class VolumeDialogImpl implements VolumeDialog {
    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 @@ public class VolumeDialogImpl implements VolumeDialog {
        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
        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 @@ public class VolumeDialogImpl implements VolumeDialog {
                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 @@ public class VolumeDialogImpl implements VolumeDialog {
            addExistingRows();
        }
        updateRowsH(getActiveRow());
        initRingerH();
    }

    private ColorStateList loadColorStateList(int colorResId) {
@@ -374,6 +393,30 @@ public class VolumeDialogImpl implements VolumeDialog {
        }
    }

    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 @@ public class VolumeDialogImpl implements VolumeDialog {
        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();
        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 @@ public class VolumeDialogImpl implements VolumeDialog {
        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 @@ public class VolumeDialogImpl implements VolumeDialog {
        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 @@ public class VolumeDialogImpl implements VolumeDialog {
        }
    }

    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 @@ public class VolumeDialogImpl implements VolumeDialog {
        for (VolumeRow row : mRows) {
            updateVolumeRowH(row);
        }
        updateRingerH();
    }

    private void updateVolumeRowH(VolumeRow row) {
+66 −0
Original line number Diff line number Diff line
/*
 * 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);
    };
}