Skip to content

Commit

Permalink
Add Proximity sensing back to voice note.
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-signal committed Oct 16, 2020
1 parent ec706e9 commit 8a2d204
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.components.voice;

import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
Expand All @@ -11,19 +10,14 @@
import android.os.Process;
import android.os.RemoteException;
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.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.media.MediaBrowserServiceCompat;
import androidx.media.session.MediaButtonReceiver;

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
Expand All @@ -38,18 +32,10 @@
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
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.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.RecipientId;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
* Android Service responsible for playback of voice notes.
Expand All @@ -74,6 +60,7 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
private VoiceNoteNotificationManager voiceNoteNotificationManager;
private VoiceNoteQueueDataAdapter queueDataAdapter;
private VoiceNotePlaybackPreparer voiceNotePlaybackPreparer;
private VoiceNoteProximityManager voiceNoteProximityManager;
private boolean isForegroundService;

private final LoadControl loadControl = new DefaultLoadControl.Builder()
Expand Down Expand Up @@ -102,6 +89,7 @@ public void onCreate() {
VoiceNoteMediaSourceFactory mediaSourceFactory = new VoiceNoteMediaSourceFactory(this);

voiceNotePlaybackPreparer = new VoiceNotePlaybackPreparer(this, player, queueDataAdapter, mediaSourceFactory);
voiceNoteProximityManager = new VoiceNoteProximityManager(this, player);

mediaSession.setPlaybackState(stateBuilder.build());

Expand Down Expand Up @@ -155,6 +143,7 @@ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case Player.STATE_BUFFERING:
case Player.STATE_READY:
voiceNoteProximityManager.onPlayerReady();
voiceNoteNotificationManager.showNotification(player);

if (!playWhenReady) {
Expand All @@ -165,6 +154,7 @@ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
}
break;
default:
voiceNoteProximityManager.onPlayerEnded();
becomingNoisyReceiver.unregister();
voiceNoteNotificationManager.hideNotification();
}
Expand All @@ -184,6 +174,7 @@ public void onPositionDiscontinuity(int reason) {
@Override
public void onPlayerError(ExoPlaybackException error) {
Log.w(TAG, "ExoPlayer error occurred:", error);
voiceNoteProximityManager.onPlayerError();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.app.job.JobScheduler;
import android.content.ClipboardManager;
import android.content.Context;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManager;
import android.location.LocationManager;
import android.media.AudioManager;
Expand Down Expand Up @@ -49,6 +50,10 @@ public static AudioManager getAudioManager(Context context) {
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) {
return (PowerManager)context.getSystemService(Context.POWER_SERVICE);
}
Expand Down

0 comments on commit 8a2d204

Please sign in to comment.