Merge "Add vol up + power ringer toggle gesture" into pi-dev

This commit is contained in:
Julia Reynolds
2018-03-22 22:03:48 +00:00
committed by Android (Google) Code Review
12 changed files with 206 additions and 9 deletions

View File

@@ -7761,6 +7761,21 @@ public final class Settings {
*/
public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";
/**
* What behavior should be invoked when the volume hush gesture is triggered
* One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE.
*
* @hide
*/
public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
/** @hide */ public static final int VOLUME_HUSH_OFF = 0;
/** @hide */ public static final int VOLUME_HUSH_VIBRATE = 1;
/** @hide */ public static final int VOLUME_HUSH_MUTE = 2;
private static final Validator VOLUME_HUSH_GESTURE_VALIDATOR =
NON_NEGATIVE_INTEGER_VALIDATOR;
/**
* The number of times (integer) the user has manually enabled battery saver.
* @hide
@@ -7875,6 +7890,7 @@ public final class Settings {
SCREENSAVER_ACTIVATE_ON_SLEEP,
LOCKDOWN_IN_POWER_MENU,
SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
VOLUME_HUSH_GESTURE
};
/**
@@ -8011,6 +8027,7 @@ public final class Settings {
VALIDATORS.put(LOCKDOWN_IN_POWER_MENU, LOCKDOWN_IN_POWER_MENU_VALIDATOR);
VALIDATORS.put(SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR);
VALIDATORS.put(VOLUME_HUSH_GESTURE, VOLUME_HUSH_GESTURE_VALIDATOR);
VALIDATORS.put(ENABLED_NOTIFICATION_LISTENERS,
ENABLED_NOTIFICATION_LISTENERS_VALIDATOR); //legacy restore setting
VALIDATORS.put(ENABLED_NOTIFICATION_ASSISTANT,

View File

@@ -744,9 +744,10 @@ message SecureSettingsProto {
optional SettingProto backup_manager_constants = 193;
optional SettingProto backup_local_transport_parameters = 194;
optional SettingProto bluetooth_on_while_driving = 195 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingsProto volume_hush_gesture = 196 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Please insert fields in the same order as in
// frameworks/base/core/java/android/provider/Settings.java.
// Next tag = 196
// Next tag = 197
}
message SystemSettingsProto {

View File

@@ -2911,6 +2911,10 @@
is non-interactive. -->
<bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
<!-- Allow the gesture power + volume up to change the ringer mode while the device
is interactive. -->
<bool name="config_volumeHushGestureEnabled">true</bool>
<!-- Name of the component to handle network policy notifications. If present,
disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
<string translatable="false" name="config_networkPolicyNotificationComponent"></string>

View File

@@ -4888,6 +4888,9 @@
<!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
<string name="screenshot_edit">Edit</string>
<string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string>
<string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string>
<!-- Title for the notification channel notifying user of settings system changes. [CHAR LIMIT=NONE] -->
<string name="notification_channel_system_changes">System changes</string>
<!-- Title for the notification channel notifying user of do not disturb system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->

View File

@@ -1024,6 +1024,8 @@
<java-symbol type="string" name="volume_icon_description_media" />
<java-symbol type="string" name="volume_icon_description_notification" />
<java-symbol type="string" name="volume_icon_description_ringer" />
<java-symbol type="string" name="volume_dialog_ringer_guidance_vibrate" />
<java-symbol type="string" name="volume_dialog_ringer_guidance_silent" />
<java-symbol type="string" name="wait" />
<java-symbol type="string" name="webpage_unresponsive" />
<java-symbol type="string" name="whichApplication" />
@@ -2621,6 +2623,7 @@
<java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
<java-symbol type="integer" name="config_cameraLiftTriggerSensorType" />
<java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" />
<java-symbol type="bool" name="config_volumeHushGestureEnabled" />
<java-symbol type="drawable" name="platlogo_m" />

View File

@@ -42,6 +42,8 @@ public abstract class AudioManagerInternal {
public abstract void setRingerModeInternal(int ringerMode, String caller);
public abstract void silenceRingerModeInternal(String caller);
public abstract void updateRingerModeAffectedStreamsInternal();
public abstract void setAccessibilityServiceUids(IntArray uids);

View File

@@ -1928,6 +1928,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
SecureSettingsProto.BLUETOOTH_ON_WHILE_DRIVING);
dumpSetting(s, p,
Settings.Secure.VOLUME_HUSH_GESTURE,
SecureSettingsProto.VOLUME_HUSH_GESTURE);
// Please insert new settings using the same order as in Settings.Secure.
p.end(token);

View File

@@ -2914,7 +2914,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
private static final int SETTINGS_VERSION = 161;
private static final int SETTINGS_VERSION = 162;
private final int mUserId;
@@ -3673,6 +3673,21 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 161;
}
if (currentVersion == 161) {
// Version 161: Add a gesture for silencing phones
final SettingsState secureSettings = getSecureSettingsLocked(userId);
final Setting currentSetting = secureSettings.getSettingLocked(
Secure.VOLUME_HUSH_GESTURE);
if (currentSetting.isNull()) {
secureSettings.insertSettingLocked(
Secure.VOLUME_HUSH_GESTURE,
Integer.toString(Secure.VOLUME_HUSH_VIBRATE),
null, true, SettingsState.SYSTEM_PACKAGE_NAME);
}
currentVersion = 162;
}
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {

View File

@@ -1353,8 +1353,6 @@
<string name="volume_dialog_title">%s volume controls</string>
<string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string>
<string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string>
<string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring</string>
<string name="output_title">Media output</string>

View File

@@ -451,11 +451,11 @@ public class VolumeDialogImpl implements VolumeDialog {
toastText = R.string.volume_dialog_ringer_guidance_ring;
break;
case RINGER_MODE_SILENT:
toastText = R.string.volume_dialog_ringer_guidance_silent;
toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
break;
case RINGER_MODE_VIBRATE:
default:
toastText = R.string.volume_dialog_ringer_guidance_vibrate;
toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
}
Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();

View File

@@ -24,6 +24,9 @@ import static android.media.AudioManager.STREAM_ALARM;
import static android.media.AudioManager.STREAM_MUSIC;
import static android.media.AudioManager.STREAM_SYSTEM;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
import android.Manifest;
import android.annotation.NonNull;
@@ -108,6 +111,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.System;
@@ -124,6 +128,7 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
@@ -440,6 +445,12 @@ public class AudioService extends IAudioService.Stub
// Is there a vibrator
private final boolean mHasVibrator;
// Used to play vibrations
private Vibrator mVibrator;
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
// Broadcast receiver for device connections intent broadcasts
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
@@ -697,8 +708,8 @@ public class AudioService extends IAudioService.Stub
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
// Initialize volume
int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
@@ -2423,6 +2434,54 @@ public class AudioService extends IAudioService.Stub
setRingerMode(ringerMode, caller, false /*external*/);
}
public void silenceRingerModeInternal(String reason) {
VibrationEffect effect = null;
int ringerMode = AudioManager.RINGER_MODE_SILENT;
int toastText = 0;
int silenceRingerSetting = Settings.Secure.VOLUME_HUSH_OFF;
if (mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
silenceRingerSetting = Settings.Secure.getIntForUser(mContentResolver,
Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
UserHandle.USER_CURRENT);
}
switch(silenceRingerSetting) {
case VOLUME_HUSH_MUTE:
effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
ringerMode = AudioManager.RINGER_MODE_SILENT;
toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
break;
case VOLUME_HUSH_VIBRATE:
effect = VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
ringerMode = AudioManager.RINGER_MODE_VIBRATE;
toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
break;
}
maybeVibrate(effect);
setRingerModeInternal(ringerMode, reason);
Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
}
private boolean maybeVibrate(VibrationEffect effect) {
if (!mHasVibrator) {
return false;
}
final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
if (hapticsDisabled) {
return false;
}
if (effect == null) {
return false;
}
mVibrator.vibrate(
Binder.getCallingUid(), mContext.getOpPackageName(), effect, VIBRATION_ATTRIBUTES);
return true;
}
private void setRingerMode(int ringerMode, String caller, boolean external) {
if (mUseFixedVolume || mIsSingleVolume) {
return;
@@ -7245,6 +7304,11 @@ public class AudioService extends IAudioService.Stub
AudioService.this.setRingerModeInternal(ringerMode, caller);
}
@Override
public void silenceRingerModeInternal(String caller) {
AudioService.this.silenceRingerModeInternal(caller);
}
@Override
public void updateRingerModeAffectedStreamsInternal() {
synchronized (mSettingsLock) {

View File

@@ -39,6 +39,7 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.STATE_OFF;
import static android.view.WindowManager.DOCKED_LEFT;
@@ -187,6 +188,7 @@ import android.hardware.input.InputManagerInternal;
import android.hardware.power.V1_0.PowerHint;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.session.MediaSessionLegacyHelper;
@@ -455,6 +457,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
StatusBarManagerInternal mStatusBarManagerInternal;
AudioManagerInternal mAudioManagerInternal;
boolean mPreloadedRecentApps;
final Object mServiceAquireLock = new Object();
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -772,6 +775,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
private static final long BUGREPORT_TV_GESTURE_TIMEOUT_MILLIS = 1000;
private boolean mBugreportTvKey1Pressed;
@@ -836,6 +842,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 27;
private static final int MSG_POWER_VERY_LONG_PRESS = 28;
private static final int MSG_NOTIFY_USER_ACTIVITY = 29;
private static final int MSG_RINGER_TOGGLE_CHORD = 30;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -943,6 +950,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.USER_ACTIVITY);
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
}
}
@@ -996,6 +1005,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.VOLUME_HUSH_GESTURE), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POLICY_CONTROL), false, this,
UserHandle.USER_ALL);
@@ -1117,6 +1129,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@VisibleForTesting
SystemGesturesPointerEventListener mSystemGestures;
private void handleRingerChordGesture() {
if (mRingerToggleChord == VOLUME_HUSH_OFF) {
return;
}
getAudioManagerInternal();
mAudioManagerInternal.silenceRingerModeInternal("volume_hush");
}
IStatusBarService getStatusBarService() {
synchronized (mServiceAquireLock) {
if (mStatusBarService == null) {
@@ -1137,6 +1157,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
AudioManagerInternal getAudioManagerInternal() {
synchronized (mServiceAquireLock) {
if (mAudioManagerInternal == null) {
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
}
return mAudioManagerInternal;
}
}
/*
* We always let the sensor be switched on by default except when
* the user has explicitly disabled sensor based rotation or when the
@@ -1306,6 +1335,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
interceptRingerToggleChord();
}
// Stop ringing or end call if configured to do so when power is pressed.
@@ -1701,6 +1731,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
private void interceptRingerToggleChord() {
if (mRingerToggleChord != Settings.Secure.VOLUME_HUSH_OFF
&& mScreenshotChordPowerKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered) {
final long now = SystemClock.uptimeMillis();
if (now <= mA11yShortcutChordVolumeUpKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
&& now <= mScreenshotChordPowerKeyTime
+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
mA11yShortcutChordVolumeUpKeyConsumed = true;
cancelPendingPowerKeyAction();
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RINGER_TOGGLE_CHORD),
getRingerToggleChordDelay());
}
}
}
private long getAccessibilityShortcutTimeout() {
ViewConfiguration config = ViewConfiguration.get(mContext);
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
@@ -1718,6 +1764,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
}
private long getRingerToggleChordDelay() {
// Always timeout like a tap
return ViewConfiguration.getTapTimeout();
}
private void cancelPendingScreenshotChordAction() {
mHandler.removeCallbacks(mScreenshotRunnable);
}
@@ -1726,6 +1777,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
}
private void cancelPendingRingerToggleChordAction() {
mHandler.removeMessages(MSG_RINGER_TOGGLE_CHORD);
}
private final Runnable mEndCallLongPress = new Runnable() {
@Override
public void run() {
@@ -2382,7 +2437,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mSystemNavigationKeysEnabled = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
0, UserHandle.USER_CURRENT) == 1;
mRingerToggleChord = Settings.Secure.getIntForUser(resolver,
Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
UserHandle.USER_CURRENT);
if (!mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
mRingerToggleChord = Settings.Secure.VOLUME_HUSH_OFF;
}
// Configure rotation suggestions.
int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
@@ -3531,6 +3592,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
// If a ringer toggle chord could be on the way but we're not sure, then tell the dispatcher
// to wait a little while and try again later before dispatching.
if (mRingerToggleChord != VOLUME_HUSH_OFF && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
if (mA11yShortcutChordVolumeUpKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
final long now = SystemClock.uptimeMillis();
final long timeoutTime = mA11yShortcutChordVolumeUpKeyTime
+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
if (now < timeoutTime) {
return timeoutTime - now;
}
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
if (!down) {
mA11yShortcutChordVolumeUpKeyConsumed = false;
}
return -1;
}
}
// Cancel any pending meta actions if we see any other keys being pressed between the down
// of the meta key and its corresponding up.
if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
@@ -5997,6 +6077,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
// Any activity on the vol down button stops the ringer toggle shortcut
cancelPendingRingerToggleChordAction();
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordVolumeDownKeyTriggered = true;
@@ -6020,12 +6103,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mA11yShortcutChordVolumeUpKeyConsumed = false;
cancelPendingPowerKeyAction();
cancelPendingScreenshotChordAction();
cancelPendingRingerToggleChordAction();
interceptAccessibilityShortcutChord();
interceptRingerToggleChord();
}
} else {
mA11yShortcutChordVolumeUpKeyTriggered = false;
cancelPendingScreenshotChordAction();
cancelPendingAccessibilityShortcutAction();
cancelPendingRingerToggleChordAction();
}
}
if (down) {