1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification; 18 19 import android.app.INotificationManager; 20 import android.app.NotificationManager; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.media.AudioManager; 24 import android.os.ServiceManager; 25 import android.os.Vibrator; 26 import android.util.Log; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.settings.R; 30 31 import java.util.Objects; 32 33 /** 34 * Shared functionality and interfaces for volume controllers whose state can change by ringer mode 35 */ 36 public abstract class RingerModeAffectedVolumePreferenceController extends 37 VolumeSeekBarPreferenceController { 38 39 private final String mTag; 40 41 protected int mNormalIconId; 42 protected int mVibrateIconId; 43 protected int mSilentIconId; 44 protected int mMuteIcon; 45 46 protected Vibrator mVibrator; 47 protected int mRingerMode = AudioManager.RINGER_MODE_NORMAL; 48 protected ComponentName mSuppressor; 49 protected INotificationManager mNoMan; 50 RingerModeAffectedVolumePreferenceController(Context context, String key, String tag)51 public RingerModeAffectedVolumePreferenceController(Context context, String key, String tag) { 52 super(context, key); 53 mTag = tag; 54 mVibrator = mContext.getSystemService(Vibrator.class); 55 if (mVibrator != null && !mVibrator.hasVibrator()) { 56 mVibrator = null; 57 } 58 mVolumePreferenceListener = this::updateContentDescription; 59 } 60 updateEffectsSuppressor()61 protected void updateEffectsSuppressor() { 62 final ComponentName suppressor = NotificationManager.from(mContext).getEffectsSuppressor(); 63 if (Objects.equals(suppressor, mSuppressor)) return; 64 65 if (mNoMan == null) { 66 mNoMan = INotificationManager.Stub.asInterface( 67 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 68 } 69 70 final int hints; 71 try { 72 hints = mNoMan.getHintsFromListenerNoToken(); 73 } catch (android.os.RemoteException ex) { 74 Log.w(mTag, "updateEffectsSuppressor: " + ex.getMessage()); 75 return; 76 } 77 78 if (hintsMatch(hints)) { 79 mSuppressor = suppressor; 80 if (mPreference != null) { 81 final String text = SuppressorHelper.getSuppressionText(mContext, suppressor); 82 mPreference.setSuppressionText(text); 83 } 84 } 85 } 86 87 @VisibleForTesting setPreference(VolumeSeekBarPreference volumeSeekBarPreference)88 void setPreference(VolumeSeekBarPreference volumeSeekBarPreference) { 89 mPreference = volumeSeekBarPreference; 90 } 91 92 @VisibleForTesting setVibrator(Vibrator vibrator)93 void setVibrator(Vibrator vibrator) { 94 mVibrator = vibrator; 95 } 96 97 @Override isSliceable()98 public boolean isSliceable() { 99 return true; 100 } 101 102 @Override isPublicSlice()103 public boolean isPublicSlice() { 104 return true; 105 } 106 107 @Override useDynamicSliceSummary()108 public boolean useDynamicSliceSummary() { 109 return true; 110 } 111 112 @Override getMuteIcon()113 public int getMuteIcon() { 114 return mMuteIcon; 115 } 116 117 /** 118 * Updates UI Icon in response to ringer mode changes. 119 * @return whether the ringer mode has changed. 120 */ updateRingerMode()121 protected boolean updateRingerMode() { 122 final int ringerMode = mHelper.getRingerModeInternal(); 123 if (mRingerMode == ringerMode) { 124 return false; 125 } 126 mRingerMode = ringerMode; 127 selectPreferenceIconState(); 128 updateContentDescription(); 129 return true; 130 } 131 132 /** 133 * Switching among normal/mute/vibrate 134 */ selectPreferenceIconState()135 protected void selectPreferenceIconState() { 136 if (mPreference != null) { 137 int ringerMode = getEffectiveRingerMode(); 138 if (ringerMode == AudioManager.RINGER_MODE_NORMAL) { 139 mPreference.showIcon(mNormalIconId); 140 } else { 141 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 142 mMuteIcon = mVibrateIconId; 143 } else { 144 mMuteIcon = mSilentIconId; 145 } 146 mPreference.showIcon(getMuteIcon()); 147 } 148 } 149 } 150 getEffectiveRingerMode()151 protected int getEffectiveRingerMode() { 152 if (mVibrator == null && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { 153 return AudioManager.RINGER_MODE_SILENT; 154 } 155 return mRingerMode; 156 } 157 updateContentDescription()158 protected void updateContentDescription() { 159 if (mPreference != null) { 160 int ringerMode = getEffectiveRingerMode(); 161 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 162 mPreference.updateContentDescription( 163 mContext.getString(R.string.ringer_content_description_vibrate_mode)); 164 } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) { 165 mPreference.updateContentDescription( 166 mContext.getString(R.string.ringer_content_description_silent_mode)); 167 } else { 168 mPreference.updateContentDescription(mPreference.getTitle()); 169 } 170 } 171 } 172 hintsMatch(int hints)173 protected abstract boolean hintsMatch(int hints); 174 175 } 176