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

Commit 661f2cf4 authored by John Spurlock's avatar John Spurlock
Browse files

VolumeZen: Introduce internal vs external ringer mode.

Stabilize mapping between ringer-mode=silent and zen=priority
by keeping track of two ringer modes:
 - Internal ringer mode: Used for underlying stream muting
 - External ringer mode: Reported to clients

The mapping between external ringer mode + zen is:
 - normal = all
 - vibrate = all
 - silent = priority (read-write) or none (read)

Changes include:
 - Remove "zen check" from audio service, back to audio
   service having no knowledge of zen.
 - Maintain a new external ringer mode in audio service,
   this is the ringer mode reported through AudioManager
   to callers, also mapped to the change intent.
 - Introduce a "ringer mode delegate" to the local
   audio manager interface, responsible for observing
   external / internal mode changes, and making changes
   if necessary.
 - Internal ringer mode changes are still interesting
   to the volume dialog, wire up a callback through
   the existing IVolumeController interface.
 - On devices without vibration, the mapping is the same
   but since no ringer mode change is possible, disable
   the icon toggle and remove the mute icon when volume=0.
 - On devices with vibration, volume down presses should
   pulse the vibrate icon (and vibrate) as a hint that this
   is as low as the device can go using the keys.  Since
   the mechanics are similar to the existing zen=none hint,
   pull into shared helper.
 - Log ringer mode changes to the zen log, include calling
   package information for issue diagnosis.
 - Include whether vibration is supported in the audio service
   dump.
 - Update the status bar icon policy to use the internal ringer
   mode, not the external mode (for vibrate icon).
 - Update the "Muted by <x>" logic, include current suppressor
   in dumpsys, ensure suppression icon is enabled & !clickable,
   regardless of zen mode.

Bug: 17884168
Bug: 15471679
Bug: 16824970
Change-Id: Ia7d3bb23ce6d1e37b24fb6521d1c1ab9bb8f60c0
parent fb6121e0
Loading
Loading
Loading
Loading
+70 −11
Original line number Diff line number Diff line
@@ -469,6 +469,49 @@ public class AudioManager {
     */
    public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;

    /**
     * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
     * @hide
     */
    public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;

    private static final String[] FLAG_NAMES = {
        "FLAG_SHOW_UI",
        "FLAG_ALLOW_RINGER_MODES",
        "FLAG_PLAY_SOUND",
        "FLAG_REMOVE_SOUND_AND_VIBRATE",
        "FLAG_VIBRATE",
        "FLAG_FIXED_VOLUME",
        "FLAG_BLUETOOTH_ABS_VOLUME",
        "FLAG_SHOW_SILENT_HINT",
        "FLAG_HDMI_SYSTEM_AUDIO_VOLUME",
        "FLAG_ACTIVE_MEDIA_ONLY",
        "FLAG_SHOW_UI_WARNINGS",
        "FLAG_SHOW_VIBRATE_HINT",
    };

    /** @hide */
    public static String flagsToString(int flags) {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < FLAG_NAMES.length; i++) {
            final int flag = 1 << i;
            if ((flags & flag) != 0) {
                if (sb.length() > 0) {
                    sb.append(',');
                }
                sb.append(FLAG_NAMES[i]);
                flags &= ~flag;
            }
        }
        if (flags != 0) {
            if (sb.length() > 0) {
                sb.append(',');
            }
            sb.append(flags);
        }
        return sb.toString();
    }

    /**
     * Ringer mode that will be silent and will not vibrate. (This overrides the
     * vibrate setting.)
@@ -857,7 +900,7 @@ public class AudioManager {
    public int getRingerMode() {
        IAudioService service = getService();
        try {
            return service.getRingerMode();
            return service.getRingerModeExternal();
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in getRingerMode", e);
            return RINGER_MODE_NORMAL;
@@ -977,21 +1020,12 @@ public class AudioManager {
     * @see #isVolumeFixed()
     */
    public void setRingerMode(int ringerMode) {
        setRingerMode(ringerMode, true /*checkZen*/);
    }

    /**
     * @see #setRingerMode(int)
     * @param checkZen  Update zen mode if necessary to compensate.
     * @hide
     */
    public void setRingerMode(int ringerMode, boolean checkZen) {
        if (!isValidRingerMode(ringerMode)) {
            return;
        }
        IAudioService service = getService();
        try {
            service.setRingerMode(ringerMode, checkZen);
            service.setRingerModeExternal(ringerMode, mContext.getOpPackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in setRingerMode", e);
        }
@@ -3307,6 +3341,31 @@ public class AudioManager {
        }
    }

    /**
     * Only useful for volume controllers.
     * @hide
     */
    public void setRingerModeInternal(int ringerMode) {
        try {
            getService().setRingerModeInternal(ringerMode, mContext.getOpPackageName());
        } catch (RemoteException e) {
            Log.w(TAG, "Error calling setRingerModeInternal", e);
        }
    }

    /**
     * Only useful for volume controllers.
     * @hide
     */
    public int getRingerModeInternal() {
        try {
            return getService().getRingerModeInternal();
        } catch (RemoteException e) {
            Log.w(TAG, "Error calling getRingerModeInternal", e);
            return RINGER_MODE_NORMAL;
        }
    }

    /**
     * Set Hdmi Cec system audio mode.
     *
+16 −0
Original line number Diff line number Diff line
@@ -38,4 +38,20 @@ public abstract class AudioManagerInternal {

    public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
            int uid);

    public abstract void setRingerModeDelegate(RingerModeDelegate delegate);

    public abstract int getRingerModeInternal();

    public abstract void setRingerModeInternal(int ringerMode, String caller);

    public interface RingerModeDelegate {
        /** Called when external ringer mode is evaluated, returns the new internal ringer mode */
        int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
                int ringerModeInternal);

        /** Called when internal ringer mode is evaluated, returns the new external ringer mode */
        int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
                int ringerModeExternal);
    }
}
+129 −59
Original line number Diff line number Diff line
@@ -66,7 +66,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.System;
import android.telecom.TelecomManager;
import android.text.TextUtils;
@@ -375,7 +374,8 @@ public class AudioService extends IAudioService.Stub {
     * {@link AudioManager#RINGER_MODE_VIBRATE}.
     */
    // protected by mSettingsLock
    private int mRingerMode;
    private int mRingerMode;  // internal ringer mode, affects muting of underlying streams
    private int mRingerModeExternal = -1;  // reported ringer mode to outside clients (AudioManager)

    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
    private int mRingerModeAffectedStreams = 0;
@@ -532,6 +532,8 @@ public class AudioService extends IAudioService.Stub {

    private static Long mLastDeviceConnectMsgTime = new Long(0);

    private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;

    ///////////////////////////////////////////////////////////////////////////
    // Construction
    ///////////////////////////////////////////////////////////////////////////
@@ -619,7 +621,7 @@ public class AudioService extends IAudioService.Stub {
        // Call setRingerModeInt() to apply correct mute
        // state on streams affected by ringer mode.
        mRingerModeMutedStreams = 0;
        setRingerModeInt(getRingerMode(), false);
        setRingerModeInt(getRingerModeInternal(), false);

        // Register for device connection intent broadcasts.
        IntentFilter intentFilter =
@@ -829,7 +831,7 @@ public class AudioService extends IAudioService.Stub {
        if (updateVolumes) {
            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
            // apply stream mute states according to new value of mRingerModeAffectedStreams
            setRingerModeInt(getRingerMode(), false);
            setRingerModeInt(getRingerModeInternal(), false);
            sendMsg(mAudioHandler,
                    MSG_SET_ALL_VOLUMES,
                    SENDMSG_QUEUE,
@@ -883,6 +885,9 @@ public class AudioService extends IAudioService.Stub {
        }
        synchronized(mSettingsLock) {
            mRingerMode = ringerMode;
            if (mRingerModeExternal == -1) {
                mRingerModeExternal = mRingerMode;
            }

            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
            // are still needed while setVibrateSetting() and getVibrateSetting() are being
@@ -1067,7 +1072,7 @@ public class AudioService extends IAudioService.Stub {
        // or the stream type is one that is affected by ringer modes
        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                (streamTypeAlias == getMasterStreamType())) {
            int ringerMode = getRingerMode();
            int ringerMode = getRingerModeInternal();
            // do not vibrate if already in vibrate mode
            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
                flags &= ~AudioManager.FLAG_VIBRATE;
@@ -1080,6 +1085,10 @@ public class AudioService extends IAudioService.Stub {
            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
            }
            // If suppressing a volume down adjustment in vibrate mode, display the UI hint
            if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
                flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
            }
        }

        int oldIndex = mStreamStates[streamType].getIndex(device);
@@ -1206,7 +1215,7 @@ public class AudioService extends IAudioService.Stub {
            } else {
                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
            }
            setRingerMode(newRingerMode, false /*checkZen*/);
            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
        }
    }

@@ -1769,8 +1778,15 @@ public class AudioService extends IAudioService.Stub {
                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
    }

    /** @see AudioManager#getRingerMode() */
    public int getRingerMode() {
    @Override
    public int getRingerModeExternal() {
        synchronized(mSettingsLock) {
            return mRingerModeExternal;
        }
    }

    @Override
    public int getRingerModeInternal() {
        synchronized(mSettingsLock) {
            return mRingerMode;
        }
@@ -1787,36 +1803,57 @@ public class AudioService extends IAudioService.Stub {
        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
    }

    /** @see AudioManager#setRingerMode(int) */
    public void setRingerMode(int ringerMode, boolean checkZen) {
    public void setRingerModeExternal(int ringerMode, String caller) {
        setRingerMode(ringerMode, caller, true /*external*/);
    }

    public void setRingerModeInternal(int ringerMode, String caller) {
        enforceSelfOrSystemUI("setRingerModeInternal");
        setRingerMode(ringerMode, caller, false /*external*/);
    }

    private void setRingerMode(int ringerMode, String caller, boolean external) {
        if (mUseFixedVolume || isPlatformTelevision()) {
            return;
        }
        if (caller == null || caller.length() == 0) {
            throw new IllegalArgumentException("Bad caller: " + caller);
        }
        ensureValidRingerMode(ringerMode);
        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
            ringerMode = AudioManager.RINGER_MODE_SILENT;
        }
        if (checkZen) {
            checkZen(ringerMode);
        final int ringerModeInternal = getRingerModeInternal();
        final int ringerModeExternal = getRingerModeExternal();
        if (external) {
            setRingerModeExt(ringerMode);
            if (mRingerModeDelegate != null) {
                ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
                        ringerMode, caller, ringerModeInternal);
            }
        if (ringerMode != getRingerMode()) {
            setRingerModeInt(ringerMode, true);
            // Send sticky broadcast
            broadcastRingerMode(ringerMode);
            if (ringerMode != ringerModeInternal) {
                setRingerModeInt(ringerMode, true /*persist*/);
            }
        } else /*internal*/ {
            if (ringerMode != ringerModeInternal) {
                setRingerModeInt(ringerMode, true /*persist*/);
                mVolumeController.postInternalRingerModeChanged(ringerMode);
            }
            if (mRingerModeDelegate != null) {
                ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
                        ringerMode, caller, ringerModeExternal);
            }
            setRingerModeExt(ringerMode);
        }

    private void checkZen(int ringerMode) {
        // leave zen when callers set ringer-mode = normal or vibrate
        final int zen = Global.getInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF);
        if (ringerMode != AudioManager.RINGER_MODE_SILENT && zen != Global.ZEN_MODE_OFF) {
            final long ident = Binder.clearCallingIdentity();
            try {
                Global.putInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF);
            } finally {
                Binder.restoreCallingIdentity(ident);
    }

    private void setRingerModeExt(int ringerMode) {
        synchronized(mSettingsLock) {
            if (ringerMode == mRingerModeExternal) return;
            mRingerModeExternal = ringerMode;
        }
        // Send sticky broadcast
        broadcastRingerMode(ringerMode);
    }

    private void setRingerModeInt(int ringerMode, boolean persist) {
@@ -1829,10 +1866,14 @@ public class AudioService extends IAudioService.Stub {
        // Unmute stream if previously muted by ringer mode and ringer mode
        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
        int numStreamTypes = AudioSystem.getNumStreamTypes();
        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
                || ringerMode == AudioManager.RINGER_MODE_SILENT;
        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
            if (isStreamMutedByRingerMode(streamType)) {
                if (!isStreamAffectedByRingerMode(streamType) ||
                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
            final boolean isMuted = isStreamMutedByRingerMode(streamType);
            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
            if (isMuted == shouldMute) continue;
            if (!shouldMute) {
                // unmute
                // ring and notifications volume should never be 0 when not silenced
                // on voice capable devices or devices that support vibration
                if ((isPlatformVoice() || mHasVibrator) &&
@@ -1850,15 +1891,12 @@ public class AudioService extends IAudioService.Stub {
                }
                mStreamStates[streamType].mute(null, false);
                mRingerModeMutedStreams &= ~(1 << streamType);
                }
            } else {
                if (isStreamAffectedByRingerMode(streamType) &&
                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
                // mute
                mStreamStates[streamType].mute(null, true);
                mRingerModeMutedStreams |= (1 << streamType);
            }
        }
        }

        // Post a persist ringer mode msg
        if (persist) {
@@ -1888,10 +1926,10 @@ public class AudioService extends IAudioService.Stub {
        switch (getVibrateSetting(vibrateType)) {

            case AudioManager.VIBRATE_SETTING_ON:
                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
                return getRingerModeInternal() != AudioManager.RINGER_MODE_SILENT;

            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
                return getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE;

            case AudioManager.VIBRATE_SETTING_OFF:
                // return false, even for incoming calls
@@ -2352,7 +2390,7 @@ public class AudioService extends IAudioService.Stub {

        // apply new ringer mode before checking volume for alias streams so that streams
        // muted by ringer mode have the correct volume
        setRingerModeInt(getRingerMode(), false);
        setRingerModeInt(getRingerModeInternal(), false);

        checkAllFixedVolumeDevices();
        checkAllAliasStreamVolumes();
@@ -3003,7 +3041,7 @@ public class AudioService extends IAudioService.Stub {
     */
    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
        int result = FLAG_ADJUST_VOLUME;
        int ringerMode = getRingerMode();
        int ringerMode = getRingerModeInternal();

        switch (ringerMode) {
        case RINGER_MODE_NORMAL:
@@ -3037,6 +3075,8 @@ public class AudioService extends IAudioService.Stub {
                if (VOLUME_SETS_RINGER_MODE_SILENT
                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                    ringerMode = RINGER_MODE_SILENT;
                } else {
                    result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
                }
            } else if (direction == AudioManager.ADJUST_RAISE) {
                ringerMode = RINGER_MODE_NORMAL;
@@ -3062,7 +3102,7 @@ public class AudioService extends IAudioService.Stub {
            break;
        }

        setRingerMode(ringerMode, false /*checkZen*/);
        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);

        mPrevVolDirection = direction;

@@ -4136,7 +4176,7 @@ public class AudioService extends IAudioService.Stub {
                case MSG_PERSIST_RINGER_MODE:
                    // note that the value persisted is the current ringer mode, not the
                    // value of ringer mode as of the time the request was made to persist
                    persistRingerMode(getRingerMode());
                    persistRingerMode(getRingerModeInternal());
                    break;

                case MSG_MEDIA_SERVER_DIED:
@@ -4188,7 +4228,7 @@ public class AudioService extends IAudioService.Stub {
                    }

                    // Restore ringer mode
                    setRingerModeInt(getRingerMode(), false);
                    setRingerModeInt(getRingerModeInternal(), false);

                    // Restore master volume
                    restoreMasterVolume();
@@ -4358,7 +4398,7 @@ public class AudioService extends IAudioService.Stub {
                     * Ensure all stream types that should be affected by ringer mode
                     * are in the proper state.
                     */
                    setRingerModeInt(getRingerMode(), false);
                    setRingerModeInt(getRingerModeInternal(), false);
                }
                readDockAudioSettings(mContentResolver);
            }
@@ -5110,7 +5150,7 @@ public class AudioService extends IAudioService.Stub {
                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
                        }
                        // take new state into account for streams muted by ringer mode
                        setRingerModeInt(getRingerMode(), false);
                        setRingerModeInt(getRingerModeInternal(), false);
                    }

                    sendMsg(mAudioHandler,
@@ -5451,11 +5491,13 @@ public class AudioService extends IAudioService.Stub {

    private void dumpRingerMode(PrintWriter pw) {
        pw.println("\nRinger mode: ");
        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
        pw.print("- ringer mode affected streams = 0x");
        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
        pw.print("- ringer mode muted streams = 0x");
        pw.println(Integer.toHexString(mRingerModeMutedStreams));
        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
    }

    @Override
@@ -5477,6 +5519,7 @@ public class AudioService extends IAudioService.Stub {
        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
        pw.print("  mMcc="); pw.println(mMcc);
        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
    }

    private static String safeMediaVolumeStateToString(Integer state) {
@@ -5668,6 +5711,16 @@ public class AudioService extends IAudioService.Stub {
                Log.w(TAG, "Error calling dismiss", e);
            }
        }

        public void postInternalRingerModeChanged(int mode) {
            if (mController == null)
                return;
            try {
                mController.internalRingerModeChanged(mode);
            } catch (RemoteException e) {
                Log.w(TAG, "Error calling internalRingerModeChanged", e);
            }
        }
    }

    /**
@@ -5675,6 +5728,13 @@ public class AudioService extends IAudioService.Stub {
     * LocalServices.
     */
    final class AudioServiceInternal extends AudioManagerInternal {
        @Override
        public void setRingerModeDelegate(RingerModeDelegate delegate) {
            mRingerModeDelegate = delegate;
            if (mRingerModeDelegate != null) {
                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
            }
        }

        @Override
        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
@@ -5701,6 +5761,16 @@ public class AudioService extends IAudioService.Stub {
                int uid) {
            adjustMasterVolume(steps, flags, callingPackage, uid);
        }

        @Override
        public int getRingerModeInternal() {
            return AudioService.this.getRingerModeInternal();
        }

        @Override
        public void setRingerModeInternal(int ringerMode, String caller) {
            AudioService.this.setRingerModeInternal(ringerMode, caller);
        }
    }

    //==========================================================================================
+6 −2
Original line number Diff line number Diff line
@@ -77,9 +77,13 @@ interface IAudioService {

    void setMicrophoneMute(boolean on, String callingPackage);

    void setRingerMode(int ringerMode, boolean checkZen);
    void setRingerModeExternal(int ringerMode, String caller);

    int getRingerMode();
    void setRingerModeInternal(int ringerMode, String caller);

    int getRingerModeExternal();

    int getRingerModeInternal();

    boolean isValidRingerMode(int ringerMode);

+2 −0
Original line number Diff line number Diff line
@@ -34,4 +34,6 @@ oneway interface IVolumeController {
    void setLayoutDirection(int layoutDirection);

    void dismiss();

    void internalRingerModeChanged(int mode);
}
Loading