Add Proximity sensing back to voice note.

This commit is contained in:
Alex Hart 2020-10-16 16:23:04 -03:00 committed by GitHub
parent ec706e95cc
commit 8a2d20403e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 14 deletions

View file

@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.components.voice; package org.thoughtcrime.securesms.components.voice;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -11,19 +10,14 @@ import android.os.Bundle;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.support.v4.media.MediaBrowserCompat; import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat; import android.support.v4.media.session.PlaybackStateCompat;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.media.MediaBrowserServiceCompat; import androidx.media.MediaBrowserServiceCompat;
import androidx.media.session.MediaButtonReceiver;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultLoadControl;
@ -38,18 +32,10 @@ import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.ui.PlayerNotificationManager; import com.google.android.exoplayer2.ui.PlayerNotificationManager;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.RecipientId;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Android Service responsible for playback of voice notes. * Android Service responsible for playback of voice notes.
@ -74,6 +60,7 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
private VoiceNoteNotificationManager voiceNoteNotificationManager; private VoiceNoteNotificationManager voiceNoteNotificationManager;
private VoiceNoteQueueDataAdapter queueDataAdapter; private VoiceNoteQueueDataAdapter queueDataAdapter;
private VoiceNotePlaybackPreparer voiceNotePlaybackPreparer; private VoiceNotePlaybackPreparer voiceNotePlaybackPreparer;
private VoiceNoteProximityManager voiceNoteProximityManager;
private boolean isForegroundService; private boolean isForegroundService;
private final LoadControl loadControl = new DefaultLoadControl.Builder() private final LoadControl loadControl = new DefaultLoadControl.Builder()
@ -102,6 +89,7 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
VoiceNoteMediaSourceFactory mediaSourceFactory = new VoiceNoteMediaSourceFactory(this); VoiceNoteMediaSourceFactory mediaSourceFactory = new VoiceNoteMediaSourceFactory(this);
voiceNotePlaybackPreparer = new VoiceNotePlaybackPreparer(this, player, queueDataAdapter, mediaSourceFactory); voiceNotePlaybackPreparer = new VoiceNotePlaybackPreparer(this, player, queueDataAdapter, mediaSourceFactory);
voiceNoteProximityManager = new VoiceNoteProximityManager(this, player);
mediaSession.setPlaybackState(stateBuilder.build()); mediaSession.setPlaybackState(stateBuilder.build());
@ -155,6 +143,7 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
switch (playbackState) { switch (playbackState) {
case Player.STATE_BUFFERING: case Player.STATE_BUFFERING:
case Player.STATE_READY: case Player.STATE_READY:
voiceNoteProximityManager.onPlayerReady();
voiceNoteNotificationManager.showNotification(player); voiceNoteNotificationManager.showNotification(player);
if (!playWhenReady) { if (!playWhenReady) {
@ -165,6 +154,7 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
} }
break; break;
default: default:
voiceNoteProximityManager.onPlayerEnded();
becomingNoisyReceiver.unregister(); becomingNoisyReceiver.unregister();
voiceNoteNotificationManager.hideNotification(); voiceNoteNotificationManager.hideNotification();
} }
@ -184,6 +174,7 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(ExoPlaybackException error) {
Log.w(TAG, "ExoPlayer error occurred:", error); Log.w(TAG, "ExoPlayer error occurred:", error);
voiceNoteProximityManager.onPlayerError();
} }
} }

View file

@ -0,0 +1,119 @@
package org.thoughtcrime.securesms.components.voice;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.os.Build;
import android.os.PowerManager;
import androidx.annotation.NonNull;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.util.Util;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.ServiceUtil;
import java.util.concurrent.TimeUnit;
class VoiceNoteProximityManager implements SensorEventListener {
private static final String TAG = Log.tag(VoiceNoteProximityManager.class);
private static final float PROXIMITY_THRESHOLD = 5f;
private final SimpleExoPlayer player;
private final AudioManager audioManager;
private final SensorManager sensorManager;
private final Sensor proximitySensor;
private final PowerManager.WakeLock wakeLock;
private long startTime;
VoiceNoteProximityManager(@NonNull Context context, @NonNull SimpleExoPlayer player) {
this.player = player;
this.audioManager = ServiceUtil.getAudioManager(context);
this.sensorManager = ServiceUtil.getSensorManager(context);
this.proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (Build.VERSION.SDK_INT >= 21) {
this.wakeLock = ServiceUtil.getPowerManager(context).newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
} else {
this.wakeLock = null;
}
}
void onPlayerReady() {
startTime = System.currentTimeMillis();
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
}
void onPlayerEnded() {
sensorManager.unregisterListener(this);
if (wakeLock != null && wakeLock.isHeld() && Build.VERSION.SDK_INT >= 21) {
wakeLock.release(PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY);
}
}
void onPlayerError() {
onPlayerEnded();
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_PROXIMITY || player.getPlaybackState() != Player.STATE_READY) {
return;
}
final int desiredStreamType;
if (event.values[0] < PROXIMITY_THRESHOLD && event.values[0] != proximitySensor.getMaximumRange()) {
desiredStreamType = AudioManager.STREAM_VOICE_CALL;
} else {
desiredStreamType = AudioManager.STREAM_MUSIC;
}
final int currentStreamType = Util.getStreamTypeForAudioUsage(player.getAudioAttributes().usage);
if (desiredStreamType == AudioManager.STREAM_VOICE_CALL &&
desiredStreamType != currentStreamType &&
!audioManager.isWiredHeadsetOn())
{
if (wakeLock != null) {
wakeLock.acquire(TimeUnit.MINUTES.toMillis(30));
}
player.setPlayWhenReady(false);
player.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(C.CONTENT_TYPE_SPEECH)
.setUsage(C.USAGE_VOICE_COMMUNICATION)
.build());
player.setPlayWhenReady(true);
startTime = System.currentTimeMillis();
} else if (desiredStreamType == AudioManager.STREAM_MUSIC &&
desiredStreamType != currentStreamType &&
System.currentTimeMillis() - startTime > 500)
{
if (wakeLock != null) {
wakeLock.release();
player.setPlayWhenReady(false);
player.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(C.CONTENT_TYPE_MUSIC)
.setUsage(C.USAGE_MEDIA)
.build(),
true);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}

View file

@ -7,6 +7,7 @@ import android.app.NotificationManager;
import android.app.job.JobScheduler; import android.app.job.JobScheduler;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager;
import android.location.LocationManager; import android.location.LocationManager;
import android.media.AudioManager; import android.media.AudioManager;
@ -49,6 +50,10 @@ public class ServiceUtil {
return (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); return (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
} }
public static SensorManager getSensorManager(Context context) {
return (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
}
public static PowerManager getPowerManager(Context context) { public static PowerManager getPowerManager(Context context) {
return (PowerManager)context.getSystemService(Context.POWER_SERVICE); return (PowerManager)context.getSystemService(Context.POWER_SERVICE);
} }