InCallUI: SmartMute
Mute the incoming call by flipping the phone
AICP: Brought to N by combining into one commit
3a4c1f7b7b319a3bfd560423ae19e4da3f52eda1
9063092dfc3eac9bc30f73fdca40ec6fe1aa1f44
AICP: brought up to O
@eyosen: brought up to P
Change-Id: I3ff27450eecbf501fafb2d75317a0d7dd844e7b2
Signed-off-by: linuxxxxx <joey@cyanogenmoditalia.it>
Signed-off-by: blinoff82 <blinov@gmail.com>
Signed-off-by: DennySPB <dennyspb@gmail.com>
diff --git a/java/com/android/dialer/app/res/values/bliss_strings.xml b/java/com/android/dialer/app/res/values/bliss_strings.xml
index 2425df2..5532bce 100644
--- a/java/com/android/dialer/app/res/values/bliss_strings.xml
+++ b/java/com/android/dialer/app/res/values/bliss_strings.xml
@@ -41,4 +41,9 @@
<string name="auto_answer_delay_title">Autoanswer delay</string>
<string name="auto_answer_dialog_title">Autoanswer delay in (ms)</string>
<string name="auto_answer_delay_summary">Autoanswer will be activated in <xliff:g id="number">%d</xliff:g> ms</string>
+
+ <!-- Smart Options -->
+ <string name="smart_category_title">Gestures</string>
+ <string name="smart_mute_title">Smart mute</string>
+ <string name="smart_mute_summary">Mute the incoming call by flipping the device</string>
</resources>
diff --git a/java/com/android/dialer/app/res/xml/sound_settings.xml b/java/com/android/dialer/app/res/xml/sound_settings.xml
index 673ec56..3062d40 100644
--- a/java/com/android/dialer/app/res/xml/sound_settings.xml
+++ b/java/com/android/dialer/app/res/xml/sound_settings.xml
@@ -90,4 +90,17 @@
</PreferenceCategory>
+ <PreferenceCategory
+ android:key="dialer_general_smart_category_key"
+ android:title="@string/smart_category_title"
+ android:persistent="false">
+
+ <SwitchPreference
+ android:key="button_smart_mute"
+ android:title="@string/smart_mute_title"
+ android:summary="@string/smart_mute_summary"
+ android:defaultValue="false" />
+
+ </PreferenceCategory>
+
</PreferenceScreen>
diff --git a/java/com/android/dialer/app/settings/SoundSettingsFragment.java b/java/com/android/dialer/app/settings/SoundSettingsFragment.java
index ce03322..c8e5a60 100644
--- a/java/com/android/dialer/app/settings/SoundSettingsFragment.java
+++ b/java/com/android/dialer/app/settings/SoundSettingsFragment.java
@@ -53,6 +53,8 @@
private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1;
+ public static final String BUTTON_SMART_MUTE_KEY = "button_smart_mute";
+
private Preference ringtonePreference;
private final Handler ringtoneLookupComplete =
new Handler() {
diff --git a/java/com/android/incallui/AccelerometerListener.java b/java/com/android/incallui/AccelerometerListener.java
index 92e62b0..35a05b4 100644
--- a/java/com/android/incallui/AccelerometerListener.java
+++ b/java/com/android/incallui/AccelerometerListener.java
@@ -39,6 +39,7 @@
private static final boolean DEBUG = true;
private static final boolean VDEBUG = false;
private static final int ORIENTATION_CHANGED = 1234;
+ private static final int FACE_UP_CHANGED = 1235;
private static final int VERTICAL_DEBOUNCE = 100;
private static final int HORIZONTAL_DEBOUNCE = 500;
private static final double VERTICAL_ANGLE = 50.0;
@@ -50,7 +51,7 @@
// This is sent to the client after a rebounce delay, at which point it is copied to
// mOrientation.
private int pendingOrientation;
- private OrientationListener listener;
+ private ChangeListener listener;
Handler handler =
new Handler() {
@Override
@@ -68,10 +69,13 @@
: (orientation == ORIENTATION_VERTICAL ? "vertical" : "unknown")));
}
if (listener != null) {
- listener.orientationChanged(orientation);
+ listener.onOrientationChanged(orientation);
}
}
break;
+ case FACE_UP_CHANGED:
+ listener.onDeviceFlipped(msg.arg1 == 0);
+ break;
}
}
};
@@ -88,12 +92,33 @@
}
};
+ // Flip detection
+ private static final int FACE_UP_GRAVITY_THRESHOLD = 7;
+ private static final int FACE_DOWN_GRAVITY_THRESHOLD = -7;
+ private static final int SENSOR_SAMPLES = 3;
+ private static final int MIN_ACCEPT_COUNT = SENSOR_SAMPLES - 1;
+
+ private boolean mWasFaceUp;
+ private boolean[] mSamples = new boolean[SENSOR_SAMPLES];
+ private int mSampleIndex;
+
+ public interface ChangeListener {
+ void onOrientationChanged(int orientation);
+ void onDeviceFlipped(boolean faceDown);
+ }
+
public AccelerometerListener(Context context) {
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
- public void setListener(OrientationListener listener) {
+ public AccelerometerListener(Context context, ChangeListener listener) {
+ setListener(listener);
+ sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+ sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ }
+
+ public void setListener(ChangeListener listener) {
this.listener = listener;
}
@@ -105,6 +130,8 @@
if (enable) {
orientation = ORIENTATION_UNKNOWN;
pendingOrientation = ORIENTATION_UNKNOWN;
+ mWasFaceUp = false;
+ resetFlipSamples();
sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
} else {
sensorManager.unregisterListener(sensorListener);
@@ -113,6 +140,22 @@
}
}
+ private void resetFlipSamples() {
+ for (int i = 0; i < SENSOR_SAMPLES; i++) {
+ mSamples[i] = false;
+ }
+ }
+
+ private boolean filterFlipSamples() {
+ int trues = 0;
+ for (int i = 0; i < mSamples.length; i++) {
+ if (mSamples[i]) {
+ ++trues;
+ }
+ }
+ return trues >= MIN_ACCEPT_COUNT;
+ }
+
private void setOrientation(int orientation) {
synchronized (this) {
if (pendingOrientation == orientation) {
@@ -140,6 +183,17 @@
}
}
+ private void setIsFaceUp(boolean faceUp) {
+ synchronized (this) {
+ if (mWasFaceUp != faceUp) {
+ handler.removeMessages(FACE_UP_CHANGED);
+ handler.obtainMessage(FACE_UP_CHANGED, faceUp ? 1 : 0, 0).sendToTarget();
+ mWasFaceUp = faceUp;
+ resetFlipSamples();
+ }
+ }
+ }
+
private void onSensorEvent(double x, double y, double z) {
if (VDEBUG) {
LogUtil.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
@@ -163,10 +217,24 @@
LogUtil.d(TAG, "angle: " + angle + " orientation: " + orientation);
}
setOrientation(orientation);
- }
- public interface OrientationListener {
+ boolean nowFaceUp, wasFaceUp;
+ synchronized (this) {
+ nowFaceUp = wasFaceUp = mWasFaceUp;
+ }
- void orientationChanged(int orientation);
+ if (!wasFaceUp) {
+ // Check if its face up enough.
+ mSamples[mSampleIndex] = z > FACE_UP_GRAVITY_THRESHOLD;
+ } else {
+ // Check if its face down enough.
+ mSamples[mSampleIndex] = z < FACE_DOWN_GRAVITY_THRESHOLD;
+ }
+ if (filterFlipSamples()) {
+ nowFaceUp = !wasFaceUp;
+ }
+
+ mSampleIndex = ((mSampleIndex + 1) % SENSOR_SAMPLES);
+ setIsFaceUp(nowFaceUp);
}
}
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index 8881029..ab749ed 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -18,10 +18,12 @@
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.os.Trace;
+import android.preference.PreferenceManager;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -94,7 +96,8 @@
* presenters that want to listen in on the in-call state changes. TODO: This class has become more
* of a state machine at this point. Consider renaming.
*/
-public class InCallPresenter implements CallList.Listener, AudioModeProvider.AudioModeListener {
+public class InCallPresenter implements CallList.Listener, AudioModeProvider.AudioModeListener,
+ AccelerometerListener.ChangeListener {
private static final String PIXEL2017_SYSTEM_FEATURE =
"com.google.android.feature.PIXEL_2017_EXPERIENCE";
private static final String CALL_CONFIGURATION_EXTRA = "call_configuration";
@@ -198,6 +201,7 @@
};
private InCallState inCallState = InCallState.NO_CALLS;
private ProximitySensor proximitySensor;
+ private AccelerometerListener mAccelerometerListener;
private final PseudoScreenState pseudoScreenState = new PseudoScreenState();
private boolean serviceConnected;
private InCallCameraManager inCallCameraManager;
@@ -374,6 +378,7 @@
this.proximitySensor = proximitySensor;
addListener(this.proximitySensor);
+ mAccelerometerListener = new AccelerometerListener(context, this);
if (themeColorManager == null) {
themeColorManager = new ThemeColorManager(new InCallUIMaterialColorMapUtils(this.context));
@@ -867,6 +872,10 @@
LogUtil.d(
"InCallPresenter.onCallListChange", "onCallListChange newState changed to " + newState);
+ if (!newState.isIncoming() && mAccelerometerListener != null) {
+ mAccelerometerListener.enable(false);
+ }
+
// Set the new state before announcing it to the world
LogUtil.i(
"InCallPresenter.onCallListChange",
@@ -965,6 +974,10 @@
"InCallPresenter.onIncomingCall", "Phone switching state: " + oldState + " -> " + newState);
inCallState = newState;
+ if (newState.isIncoming() && mAccelerometerListener != null) {
+ mAccelerometerListener.enable(true);
+ }
+
Trace.beginSection("listener.onIncomingCall");
for (IncomingCallListener listener : incomingCallListeners) {
listener.onIncomingCall(oldState, inCallState, call);
@@ -1058,6 +1071,22 @@
&& (number.length() <= 8 || number.startsWith("*#*#") || number.endsWith("#*#*"));
}
+ public void onOrientationChanged(int orientation) {
+ // ignored
+ }
+
+ @Override
+ public void onDeviceFlipped(boolean faceDown) {
+ if (!faceDown) {
+ return;
+ }
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ if (prefs.getBoolean("button_smart_mute", false)) {
+ TelecomUtil.silenceRinger(context);
+ }
+ }
+
/** Given the call list, return the state in which the in-call screen should be. */
public InCallState getPotentialStateFromCallList(CallList callList) {
@@ -1344,6 +1373,9 @@
// (1) Attempt to answer a call
if (incomingCall != null) {
incomingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
+ if (mAccelerometerListener != null) {
+ mAccelerometerListener.enable(false);
+ }
return true;
}
@@ -1649,6 +1681,11 @@
}
proximitySensor = null;
+ if (mAccelerometerListener != null) {
+ mAccelerometerListener.enable(false);
+ mAccelerometerListener = null;
+ }
+
if (statusBarNotifier != null) {
removeListener(statusBarNotifier);
EnrichedCallComponent.get(context)
diff --git a/java/com/android/incallui/ProximitySensor.java b/java/com/android/incallui/ProximitySensor.java
index 941dc0b..580e8c7 100644
--- a/java/com/android/incallui/ProximitySensor.java
+++ b/java/com/android/incallui/ProximitySensor.java
@@ -50,7 +50,7 @@
* and disabled. Most of that state is fed into this class through public methods.
*/
public class ProximitySensor
- implements AccelerometerListener.OrientationListener, InCallStateListener, AudioModeListener, SensorEventListener {
+ implements AccelerometerListener.ChangeListener, InCallStateListener, AudioModeListener, SensorEventListener {
private static final String TAG = ProximitySensor.class.getSimpleName();
private static final String PREF_KEY_DISABLE_PROXI_SENSOR = "disable_proximity_sensor_key";
@@ -160,11 +160,16 @@
/** Called to identify when the device is laid down flat. */
@Override
- public void orientationChanged(int orientation) {
+ public void onOrientationChanged(int orientation) {
this.orientation = orientation;
updateProximitySensorMode();
}
+ @Override
+ public void onDeviceFlipped(boolean faceDown) {
+ // ignored
+ }
+
/** Called to keep track of the overall UI state. */
@Override
public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {