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

Commit 7f6c833b authored by Behnam Heydarshahi's avatar Behnam Heydarshahi Committed by Android (Google) Code Review
Browse files

Merge "Add notification volume controller in settings" into tm-qpr-dev

parents 689350d4 3ac6aaf7
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
<!--
    Copyright (C) 2022 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?android:attr/colorControlNormal">
  <path
      android:pathData="M11,7V2H13V7ZM17.6,9.85 L16.2,8.4 19.75,4.85 21.15,6.3ZM6.4,9.85 L2.85,6.3 4.25,4.85 7.8,8.4ZM12,12Q14.95,12 17.812,13.188Q20.675,14.375 22.9,16.75Q23.2,17.05 23.2,17.45Q23.2,17.85 22.9,18.15L20.6,20.4Q20.325,20.675 19.963,20.7Q19.6,20.725 19.3,20.5L16.4,18.3Q16.2,18.15 16.1,17.95Q16,17.75 16,17.5V14.65Q15.05,14.35 14.05,14.175Q13.05,14 12,14Q10.95,14 9.95,14.175Q8.95,14.35 8,14.65V17.5Q8,17.75 7.9,17.95Q7.8,18.15 7.6,18.3L4.7,20.5Q4.4,20.725 4.038,20.7Q3.675,20.675 3.4,20.4L1.1,18.15Q0.8,17.85 0.8,17.45Q0.8,17.05 1.1,16.75Q3.3,14.375 6.175,13.188Q9.05,12 12,12ZM6,15.35Q5.275,15.725 4.6,16.212Q3.925,16.7 3.2,17.3L4.2,18.3L6,16.9ZM18,15.4V16.9L19.8,18.3L20.8,17.35Q20.075,16.7 19.4,16.225Q18.725,15.75 18,15.4ZM6,15.35Q6,15.35 6,15.35Q6,15.35 6,15.35ZM18,15.4Q18,15.4 18,15.4Q18,15.4 18,15.4Z"
      android:fillColor="?android:attr/colorPrimary"/>

</vector>
 No newline at end of file
+34 −0
Original line number Diff line number Diff line
<!--
    Copyright (C) 2022 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?android:attr/colorControlNormal">
<path
      android:pathData="M0.8,4.2l8.1,8.1c-2.2,0.5 -5.2,1.6 -7.8,4.4c-0.4,0.4 -0.4,1 0,1.4l2.3,2.3c0.3,0.3 0.9,0.4 1.3,0.1l2.9,-2.2C7.8,18.1 8,17.8 8,17.5v-2.9c0.9,-0.3 1.7,-0.5 2.7,-0.6l8.5,8.5l1.4,-1.4L2.2,2.8L0.8,4.2z"
    android:fillColor="?android:attr/colorPrimary"/>
  <path
      android:pathData="M11,2h2v5h-2z"
      android:fillColor="?android:attr/colorPrimary"/>
  <path
      android:pathData="M21.2,6.3l-1.4,-1.4l-3.6,3.6l1.4,1.4C17.6,9.8 21,6.3 21.2,6.3z"
      android:fillColor="?android:attr/colorPrimary"/>
  <path
      android:pathData="M22.9,16.7c-2.8,-3 -6.2,-4.1 -8.4,-4.5l7.2,7.2l1.3,-1.3C23.3,17.7 23.3,17.1 22.9,16.7z"
      android:fillColor="?android:attr/colorPrimary"/>
</vector>
+4 −1
Original line number Diff line number Diff line
@@ -8727,9 +8727,12 @@
    <!-- Sound: Title for the option managing alarm volume. [CHAR LIMIT=30] -->
    <string name="alarm_volume_option_title">Alarm volume</string>
    <!-- Sound: Title for the option managing ring volume. [CHAR LIMIT=30] -->
    <!-- Sound: Title for the option managing ring & notification volume. [CHAR LIMIT=30] -->
    <string name="ring_volume_option_title">Ring &amp; notification volume</string>
    <!-- Sound: Title for the option managing ring volume. [CHAR LIMIT=30] -->
    <string name="separate_ring_volume_option_title">Ring volume</string>
    <!-- Sound: Title for the option managing notification volume. [CHAR LIMIT=30] -->
    <string name="notification_volume_option_title">Notification volume</string>
+10 −10
Original line number Diff line number Diff line
@@ -72,23 +72,23 @@
        android:order="-160"
        settings:controller="com.android.settings.notification.RingVolumePreferenceController"/>

    <!-- Notification volume -->
    <com.android.settings.notification.VolumeSeekBarPreference
        android:key="notification_volume"
        android:icon="@drawable/ic_notifications"
        android:title="@string/notification_volume_option_title"
        android:order="-150"
        settings:controller=
            "com.android.settings.notification.NotificationVolumePreferenceController"/>

    <!-- Alarm volume -->
    <com.android.settings.notification.VolumeSeekBarPreference
        android:key="alarm_volume"
        android:icon="@*android:drawable/ic_audio_alarm"
        android:title="@string/alarm_volume_option_title"
        android:order="-150"
        settings:controller="com.android.settings.notification.AlarmVolumePreferenceController"/>

    <!-- Notification volume -->
    <com.android.settings.notification.VolumeSeekBarPreference
        android:key="notification_volume"
        android:icon="@drawable/ic_notifications"
        android:title="@string/notification_volume_option_title"
        android:order="-140"
        settings:controller="com.android.settings.notification.NotificationVolumePreferenceController"/>

        settings:controller="com.android.settings.notification.AlarmVolumePreferenceController"/>
x
    <!-- TODO(b/174964721): make this a PrimarySwitchPreference -->
    <!-- Interruptions -->
    <com.android.settingslib.RestrictedPreference
+214 −5
Original line number Diff line number Diff line
@@ -16,26 +16,96 @@

package com.android.settings.notification;

import android.app.INotificationManager;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ServiceManager;
import android.os.Vibrator;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
import android.util.Log;

import androidx.lifecycle.OnLifecycleEvent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settingslib.core.lifecycle.Lifecycle;

import java.util.Objects;

public class NotificationVolumePreferenceController extends
    RingVolumePreferenceController {
/**
 * Update notification volume icon in Settings in response to user adjusting volume
 */
public class NotificationVolumePreferenceController extends VolumeSeekBarPreferenceController {

    private static final String TAG = "NotificationVolumePreferenceController";
    private static final String KEY_NOTIFICATION_VOLUME = "notification_volume";

    private Vibrator mVibrator;
    private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
    private ComponentName mSuppressor;
    private final RingReceiver mReceiver = new RingReceiver();
    private final H mHandler = new H();
    private INotificationManager mNoMan;


    private int mMuteIcon;
    private final int mNormalIconId =  R.drawable.ic_notifications;
    private final int mVibrateIconId = R.drawable.ic_volume_ringer_vibrate;
    private final int mSilentIconId = R.drawable.ic_notifications_off_24dp;

    private final boolean mRingNotificationAliased;


    public NotificationVolumePreferenceController(Context context) {
        super(context, KEY_NOTIFICATION_VOLUME);
        this(context, KEY_NOTIFICATION_VOLUME);
    }

    public NotificationVolumePreferenceController(Context context, String key) {
        super(context, key);
        mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
        if (mVibrator != null && !mVibrator.hasVibrator()) {
            mVibrator = null;
        }

        mRingNotificationAliased = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_alias_ring_notif_stream_types);
        updateRingerMode();
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    @Override
    public void onResume() {
        super.onResume();
        mReceiver.register(true);
        updateEffectsSuppressor();
        updatePreferenceIconAndSliderState();
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    @Override
    public void onPause() {
        super.onPause();
        mReceiver.register(false);
    }

    @Override
    public int getAvailabilityStatus() {

        // Show separate notification slider if ring/notification are not aliased by AudioManager --
        // if they are, notification volume is controlled by RingVolumePreferenceController.
        return mContext.getResources().getBoolean(R.bool.config_show_notification_volume)
                && !Utils.isVoiceCapable(mContext) && !mHelper.isSingleVolume()
                && (!mRingNotificationAliased || !Utils.isVoiceCapable(mContext))
                && !mHelper.isSingleVolume()
                ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
    }

@@ -54,6 +124,11 @@ public class NotificationVolumePreferenceController extends
        return KEY_NOTIFICATION_VOLUME;
    }

    @Override
    public boolean useDynamicSliceSummary() {
        return true;
    }

    @Override
    public int getAudioStream() {
        return AudioManager.STREAM_NOTIFICATION;
@@ -61,7 +136,141 @@ public class NotificationVolumePreferenceController extends

    @Override
    public int getMuteIcon() {
        return R.drawable.ic_notifications_off_24dp;
        return mMuteIcon;
    }

    private void updateRingerMode() {
        final int ringerMode = mHelper.getRingerModeInternal();
        if (mRingerMode == ringerMode) return;
        mRingerMode = ringerMode;
        updatePreferenceIconAndSliderState();
    }

    private void updateEffectsSuppressor() {
        final ComponentName suppressor = NotificationManager.from(mContext).getEffectsSuppressor();
        if (Objects.equals(suppressor, mSuppressor)) return;

        if (mNoMan == null) {
            mNoMan = INotificationManager.Stub.asInterface(
                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
        }

        final int hints;
        try {
            hints = mNoMan.getHintsFromListenerNoToken();
        } catch (android.os.RemoteException exception) {
            Log.w(TAG, "updateEffectsSuppressor: " + exception.getLocalizedMessage());
            return;
        }

        if (hintsMatch(hints)) {

            mSuppressor = suppressor;
            if (mPreference != null) {
                final String text = SuppressorHelper.getSuppressionText(mContext, suppressor);
                mPreference.setSuppressionText(text);
            }
        }
    }

    @VisibleForTesting
    boolean hintsMatch(int hints) {
        boolean allEffectsDisabled =
                (hints & NotificationListenerService.HINT_HOST_DISABLE_EFFECTS) != 0;
        boolean notificationEffectsDisabled =
                (hints & NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0;

        return allEffectsDisabled || notificationEffectsDisabled;
    }

    private void updatePreferenceIconAndSliderState() {
        if (mPreference != null) {
            if (mVibrator != null && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
                mMuteIcon = mVibrateIconId;
                mPreference.showIcon(mVibrateIconId);
                mPreference.setEnabled(false);

            } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT
                    || mVibrator == null && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
                mMuteIcon = mSilentIconId;
                mPreference.showIcon(mSilentIconId);
                mPreference.setEnabled(false);
            } else { // ringmode normal: could be that we are still silent
                mPreference.setEnabled(true);
                if (mHelper.getStreamVolume(AudioManager.STREAM_NOTIFICATION) == 0) {
                    // ring is in normal, but notification is in silent
                    mMuteIcon = mSilentIconId;
                    mPreference.showIcon(mSilentIconId);
                } else {
                    mPreference.showIcon(mNormalIconId);
                }
            }
        }
    }

    private final class H extends Handler {
        private static final int UPDATE_EFFECTS_SUPPRESSOR = 1;
        private static final int UPDATE_RINGER_MODE = 2;
        private static final int NOTIFICATION_VOLUME_CHANGED = 3;

        private H() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_EFFECTS_SUPPRESSOR:
                    updateEffectsSuppressor();
                    break;
                case UPDATE_RINGER_MODE:
                    updateRingerMode();
                    break;
                case NOTIFICATION_VOLUME_CHANGED:
                    updatePreferenceIconAndSliderState();
                    break;
            }
        }
    }

    /**
     * For notification volume icon to be accurate, we need to listen to volume change as well.
     * That is because the icon can change from mute/vibrate to normal without ringer mode changing.
     */
    private class RingReceiver extends BroadcastReceiver {
        private boolean mRegistered;

        public void register(boolean register) {
            if (mRegistered == register) return;
            if (register) {
                final IntentFilter filter = new IntentFilter();
                filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
                filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
                filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
                mContext.registerReceiver(this, filter);
            } else {
                mContext.unregisterReceiver(this);
            }
            mRegistered = register;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED.equals(action)) {
                mHandler.sendEmptyMessage(H.UPDATE_EFFECTS_SUPPRESSOR);
            } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
                mHandler.sendEmptyMessage(H.UPDATE_RINGER_MODE);
            } else if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                if (streamType == AudioManager.STREAM_NOTIFICATION) {
                    int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE,
                            -1);
                    mHandler.obtainMessage(H.NOTIFICATION_VOLUME_CHANGED, streamValue, 0)
                            .sendToTarget();
                }
            }
        }
    }

}
Loading