Voice Note Beta Feedback fixes.

This commit is contained in:
Alex Hart 2020-10-16 13:14:01 -03:00 committed by GitHub
parent 36da519b26
commit 082d9e852c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 145 additions and 27 deletions

View File

@ -14,7 +14,6 @@ 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.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
@ -22,7 +21,6 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.Util;
import java.util.Objects; import java.util.Objects;
@ -38,6 +36,7 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
public static final String EXTRA_MESSAGE_ID = "voice.note.message_id"; public static final String EXTRA_MESSAGE_ID = "voice.note.message_id";
public static final String EXTRA_PLAYHEAD = "voice.note.playhead"; public static final String EXTRA_PLAYHEAD = "voice.note.playhead";
public static final String EXTRA_PLAY_SINGLE = "voice.note.play.single";
private static final String TAG = Log.tag(VoiceNoteMediaController.class); private static final String TAG = Log.tag(VoiceNoteMediaController.class);
@ -97,6 +96,15 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
return MediaControllerCompat.getMediaController(activity); return MediaControllerCompat.getMediaController(activity);
} }
public void startConsecutivePlayback(@NonNull Uri audioSlideUri, long messageId, long position) {
startPlayback(audioSlideUri, messageId, position, false);
}
public void startSinglePlayback(@NonNull Uri audioSlideUri, long messageId, long position) {
startPlayback(audioSlideUri, messageId, position, true);
}
/** /**
* Tells the Media service to begin playback of a given audio slide. If the audio * Tells the Media service to begin playback of a given audio slide. If the audio
* slide is currently playing, we jump to the desired position and then begin playback. * slide is currently playing, we jump to the desired position and then begin playback.
@ -104,8 +112,9 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
* @param audioSlideUri The Uri of the desired audio slide * @param audioSlideUri The Uri of the desired audio slide
* @param messageId The Message id of the given audio slide * @param messageId The Message id of the given audio slide
* @param position The desired position in milliseconds at which to start playback. * @param position The desired position in milliseconds at which to start playback.
* @param singlePlayback The player will only play back the specified Uri, and not build a playlist.
*/ */
public void startPlayback(@NonNull Uri audioSlideUri, long messageId, long position) { private void startPlayback(@NonNull Uri audioSlideUri, long messageId, long position, boolean singlePlayback) {
if (isCurrentTrack(audioSlideUri)) { if (isCurrentTrack(audioSlideUri)) {
getMediaController().getTransportControls().seekTo(position); getMediaController().getTransportControls().seekTo(position);
getMediaController().getTransportControls().play(); getMediaController().getTransportControls().play();
@ -113,6 +122,7 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putLong(EXTRA_MESSAGE_ID, messageId); extras.putLong(EXTRA_MESSAGE_ID, messageId);
extras.putLong(EXTRA_PLAYHEAD, position); extras.putLong(EXTRA_PLAYHEAD, position);
extras.putBoolean(EXTRA_PLAY_SINGLE, singlePlayback);
getMediaController().getTransportControls().playFromUri(audioSlideUri, extras); getMediaController().getTransportControls().playFromUri(audioSlideUri, extras);
} }

View File

@ -50,8 +50,8 @@ class VoiceNoteNotificationManager {
} }
notificationManager = PlayerNotificationManager.createWithNotificationChannel(context, notificationManager = PlayerNotificationManager.createWithNotificationChannel(context,
NotificationChannels.OTHER, NotificationChannels.VOICE_NOTES,
R.string.NotificationChannel_other, R.string.NotificationChannel_voice_notes,
NOW_PLAYING_NOTIFICATION_ID, NOW_PLAYING_NOTIFICATION_ID,
new DescriptionAdapter()); new DescriptionAdapter());

View File

@ -90,6 +90,7 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
public void onPrepareFromUri(final Uri uri, Bundle extras) { public void onPrepareFromUri(final Uri uri, Bundle extras) {
long messageId = extras.getLong(VoiceNoteMediaController.EXTRA_MESSAGE_ID); long messageId = extras.getLong(VoiceNoteMediaController.EXTRA_MESSAGE_ID);
long position = extras.getLong(VoiceNoteMediaController.EXTRA_PLAYHEAD, 0); long position = extras.getLong(VoiceNoteMediaController.EXTRA_PLAYHEAD, 0);
boolean singlePlayback = extras.getBoolean(VoiceNoteMediaController.EXTRA_PLAY_SINGLE, false);
canLoadMore = false; canLoadMore = false;
latestUri = uri; latestUri = uri;
@ -98,7 +99,13 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
dataSource.clear(); dataSource.clear();
SimpleTask.run(EXECUTOR, SimpleTask.run(EXECUTOR,
() -> loadMediaDescriptions(messageId), () -> {
if (singlePlayback) {
return loadMediaDescriptionForSinglePlayback(messageId);
} else {
return loadMediaDescriptionsForConsecutivePlayback(messageId);
}
},
descriptions -> { descriptions -> {
if (Util.hasItems(descriptions) && Objects.equals(latestUri, uri)) { if (Util.hasItems(descriptions) && Objects.equals(latestUri, uri)) {
applyDescriptionsToQueue(descriptions); applyDescriptionsToQueue(descriptions);
@ -116,7 +123,7 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
}); });
player.prepare(dataSource); player.prepare(dataSource);
canLoadMore = true; canLoadMore = !singlePlayback;
} }
}); });
} }
@ -203,7 +210,7 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
long messageId = mediaDescriptionCompat.getExtras().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_MESSAGE_ID); long messageId = mediaDescriptionCompat.getExtras().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_MESSAGE_ID);
SimpleTask.run(EXECUTOR, SimpleTask.run(EXECUTOR,
() -> loadMediaDescriptions(messageId), () -> loadMediaDescriptionsForConsecutivePlayback(messageId),
descriptions -> { descriptions -> {
if (Util.hasItems(descriptions) && canLoadMore) { if (Util.hasItems(descriptions) && canLoadMore) {
applyDescriptionsToQueue(descriptions); applyDescriptionsToQueue(descriptions);
@ -211,8 +218,24 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
}); });
} }
private @NonNull List<MediaDescriptionCompat> loadMediaDescriptionForSinglePlayback(long messageId) {
try {
MessageRecord messageRecord = DatabaseFactory.getMmsDatabase(context).getMessageRecord(messageId);
if (!MessageRecordUtil.hasAudio(messageRecord)) {
Log.w(TAG, "Message does not contain audio.");
return Collections.emptyList();
}
return Collections.singletonList(VoiceNoteMediaDescriptionCompatFactory.buildMediaDescription(context ,messageRecord));
} catch (NoSuchMessageException e) {
Log.w(TAG, "Could not find message.", e);
return Collections.emptyList();
}
}
@WorkerThread @WorkerThread
private @NonNull List<MediaDescriptionCompat> loadMediaDescriptions(long messageId) { private @NonNull List<MediaDescriptionCompat> loadMediaDescriptionsForConsecutivePlayback(long messageId) {
try { try {
List<MessageRecord> recordsBefore = DatabaseFactory.getMmsSmsDatabase(context).getMessagesBeforeVoiceNoteExclusive(messageId, LIMIT); List<MessageRecord> recordsBefore = DatabaseFactory.getMmsSmsDatabase(context).getMessagesBeforeVoiceNoteExclusive(messageId, LIMIT);
List<MessageRecord> recordsAfter = DatabaseFactory.getMmsSmsDatabase(context).getMessagesAfterVoiceNoteInclusive(messageId, LIMIT); List<MessageRecord> recordsAfter = DatabaseFactory.getMmsSmsDatabase(context).getMessagesAfterVoiceNoteInclusive(messageId, LIMIT);

View File

@ -28,6 +28,7 @@ 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;
import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.LoadControl; import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
@ -179,6 +180,11 @@ public class VoiceNotePlaybackService extends MediaBrowserServiceCompat {
voiceNotePlaybackPreparer.loadMoreVoiceNotes(); voiceNotePlaybackPreparer.loadMoreVoiceNotes();
} }
} }
@Override
public void onPlayerError(ExoPlaybackException error) {
Log.w(TAG, "ExoPlayer error occurred:", error);
}
} }
private class VoiceNoteNotificationManagerListener implements PlayerNotificationManager.NotificationListener { private class VoiceNoteNotificationManagerListener implements PlayerNotificationManager.NotificationListener {

View File

@ -118,7 +118,6 @@ import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.stickers.StickerPackPreviewActivity; import org.thoughtcrime.securesms.stickers.StickerPackPreviewActivity;
import org.thoughtcrime.securesms.util.CachedInflater; import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.CommunicationActions; import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.HtmlUtil; import org.thoughtcrime.securesms.util.HtmlUtil;
import org.thoughtcrime.securesms.util.RemoteDeleteUtil; import org.thoughtcrime.securesms.util.RemoteDeleteUtil;
import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.SaveAttachmentTask;
@ -353,10 +352,18 @@ public class ConversationFragment extends LoggingFragment {
actionMode.finish(); actionMode.finish();
} }
long oldThreadId = threadId;
initializeResources(); initializeResources();
messageRequestViewModel.setConversationInfo(recipient.getId(), threadId); messageRequestViewModel.setConversationInfo(recipient.getId(), threadId);
int startingPosition = getStartPosition();
if (startingPosition != -1 && oldThreadId == threadId) {
list.post(() -> moveToPosition(startingPosition, () -> Log.w(TAG, "Could not scroll to requested message.")));
} else {
initializeListAdapter(); initializeListAdapter();
} }
}
public void moveToLastSeen() { public void moveToLastSeen() {
if (conversationViewModel.getLastSeenPosition() <= 0) { if (conversationViewModel.getLastSeenPosition() <= 0) {
@ -373,6 +380,10 @@ public class ConversationFragment extends LoggingFragment {
snapToTopDataObserver.requestScrollPosition(position); snapToTopDataObserver.requestScrollPosition(position);
} }
private int getStartPosition() {
return requireActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1);
}
private void initializeMessageRequestViewModel() { private void initializeMessageRequestViewModel() {
MessageRequestViewModel.Factory factory = new MessageRequestViewModel.Factory(requireContext()); MessageRequestViewModel.Factory factory = new MessageRequestViewModel.Factory(requireContext());
@ -460,7 +471,7 @@ public class ConversationFragment extends LoggingFragment {
private void initializeResources() { private void initializeResources() {
long oldThreadId = threadId; long oldThreadId = threadId;
int startingPosition = this.getActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1); int startingPosition = getStartPosition();
this.recipient = Recipient.live(getActivity().getIntent().getParcelableExtra(ConversationActivity.RECIPIENT_EXTRA)); this.recipient = Recipient.live(getActivity().getIntent().getParcelableExtra(ConversationActivity.RECIPIENT_EXTRA));
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1); this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
@ -1367,7 +1378,7 @@ public class ConversationFragment extends LoggingFragment {
@Override @Override
public void onVoiceNotePlay(@NonNull Uri uri, long messageId, long position) { public void onVoiceNotePlay(@NonNull Uri uri, long messageId, long position) {
voiceNoteMediaController.startPlayback(uri, messageId, position); voiceNoteMediaController.startConsecutivePlayback(uri, messageId, position);
} }
@Override @Override

View File

@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.AttachmentId; import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.components.AudioView; import org.thoughtcrime.securesms.components.AudioView;
import org.thoughtcrime.securesms.components.ThumbnailView; import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
import org.thoughtcrime.securesms.database.MediaDatabase; import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord; import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.GroupedThreadMediaLoader.GroupedThreadMedia; import org.thoughtcrime.securesms.database.loaders.GroupedThreadMediaLoader.GroupedThreadMedia;
@ -56,6 +57,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects;
final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter { final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
@ -64,7 +66,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
private final GlideRequests glideRequests; private final GlideRequests glideRequests;
private final ItemClickListener itemClickListener; private final ItemClickListener itemClickListener;
private final Map<AttachmentId, MediaRecord> selected = new HashMap<>(); private final Map<AttachmentId, MediaRecord> selected = new HashMap<>();
private final AudioView.Callbacks audioViewCallbacks; private final AudioItemListener audioItemListener;
private GroupedThreadMedia media; private GroupedThreadMedia media;
private boolean showFileSizes; private boolean showFileSizes;
@ -94,7 +96,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
@NonNull GlideRequests glideRequests, @NonNull GlideRequests glideRequests,
GroupedThreadMedia media, GroupedThreadMedia media,
ItemClickListener clickListener, ItemClickListener clickListener,
@NonNull AudioView.Callbacks audioViewCallbacks, @NonNull AudioItemListener audioItemListener,
boolean showFileSizes, boolean showFileSizes,
boolean showThread) boolean showThread)
{ {
@ -102,7 +104,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
this.glideRequests = glideRequests; this.glideRequests = glideRequests;
this.media = media; this.media = media;
this.itemClickListener = clickListener; this.itemClickListener = clickListener;
this.audioViewCallbacks = audioViewCallbacks; this.audioItemListener = audioItemListener;
this.showFileSizes = showFileSizes; this.showFileSizes = showFileSizes;
this.showThread = showThread; this.showThread = showThread;
} }
@ -435,11 +437,22 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
throw new AssertionError(); throw new AssertionError();
} }
audioView.setAudio((AudioSlide) slide, audioViewCallbacks, true); long mmsId = Objects.requireNonNull(mediaRecord.getAttachment()).getMmsId();
audioItemListener.unregisterPlaybackStateObserver(audioView.getPlaybackStateObserver());
audioView.setAudio((AudioSlide) slide, new AudioViewCallbacksAdapter(audioItemListener, mmsId), true);
audioItemListener.registerPlaybackStateObserver(audioView.getPlaybackStateObserver());
audioView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord)); audioView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord));
itemView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord)); itemView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord));
} }
@Override
void unbind() {
super.unbind();
audioItemListener.unregisterPlaybackStateObserver(audioView.getPlaybackStateObserver());
}
@Override @Override
protected String getFileTypeDescription(@NonNull Context context, @NonNull Slide slide) { protected String getFileTypeDescription(@NonNull Context context, @NonNull Slide slide) {
return context.getString(R.string.MediaOverviewActivity_audio); return context.getString(R.string.MediaOverviewActivity_audio);
@ -478,8 +491,48 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
} }
} }
private static final class AudioViewCallbacksAdapter implements AudioView.Callbacks {
private final AudioItemListener audioItemListener;
private final long messageId;
private AudioViewCallbacksAdapter(@NonNull AudioItemListener audioItemListener, long messageId) {
this.audioItemListener = audioItemListener;
this.messageId = messageId;
}
@Override
public void onPlay(@NonNull Uri audioUri, long position) {
audioItemListener.onPlay(audioUri, position, messageId);
}
@Override
public void onPause(@NonNull Uri audioUri) {
audioItemListener.onPause(audioUri);
}
@Override
public void onSeekTo(@NonNull Uri audioUri, long position) {
audioItemListener.onSeekTo(audioUri, position);
}
@Override
public void onStopAndReset(@NonNull Uri audioUri) {
audioItemListener.onStopAndReset(audioUri);
}
}
interface ItemClickListener { interface ItemClickListener {
void onMediaClicked(@NonNull MediaDatabase.MediaRecord mediaRecord); void onMediaClicked(@NonNull MediaDatabase.MediaRecord mediaRecord);
void onMediaLongClicked(MediaDatabase.MediaRecord mediaRecord); void onMediaLongClicked(MediaDatabase.MediaRecord mediaRecord);
} }
interface AudioItemListener {
void onPlay(@NonNull Uri audioUri, long position, long messageId);
void onPause(@NonNull Uri audioUri);
void onSeekTo(@NonNull Uri audioUri, long position);
void onStopAndReset(@NonNull Uri audioUri);
void registerPlaybackStateObserver(@NonNull Observer<VoiceNotePlaybackState> observer);
void unregisterPlaybackStateObserver(@NonNull Observer<VoiceNotePlaybackState> observer);
}
} }

View File

@ -22,6 +22,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ActionMode; import androidx.appcompat.view.ActionMode;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -31,8 +32,8 @@ import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager;
import org.thoughtcrime.securesms.MediaPreviewActivity; import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.AudioView;
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController; import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
import org.thoughtcrime.securesms.database.MediaDatabase; import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.loaders.GroupedThreadMediaLoader; import org.thoughtcrime.securesms.database.loaders.GroupedThreadMediaLoader;
import org.thoughtcrime.securesms.database.loaders.MediaLoader; import org.thoughtcrime.securesms.database.loaders.MediaLoader;
@ -44,7 +45,7 @@ import org.thoughtcrime.securesms.util.Util;
public final class MediaOverviewPageFragment extends Fragment public final class MediaOverviewPageFragment extends Fragment
implements MediaGalleryAllAdapter.ItemClickListener, implements MediaGalleryAllAdapter.ItemClickListener,
AudioView.Callbacks, MediaGalleryAllAdapter.AudioItemListener,
LoaderManager.LoaderCallbacks<GroupedThreadMediaLoader.GroupedThreadMedia> LoaderManager.LoaderCallbacks<GroupedThreadMediaLoader.GroupedThreadMedia>
{ {
@ -310,8 +311,8 @@ public final class MediaOverviewPageFragment extends Fragment
} }
@Override @Override
public void onPlay(@NonNull Uri audioUri, long position) { public void onPlay(@NonNull Uri audioUri, long position, long messageId) {
voiceNoteMediaController.startPlayback(audioUri, -1, position); voiceNoteMediaController.startSinglePlayback(audioUri, messageId, position);
} }
@Override @Override
@ -329,6 +330,16 @@ public final class MediaOverviewPageFragment extends Fragment
voiceNoteMediaController.stopPlaybackAndReset(audioUri); voiceNoteMediaController.stopPlaybackAndReset(audioUri);
} }
@Override
public void registerPlaybackStateObserver(@NonNull Observer<VoiceNotePlaybackState> observer) {
voiceNoteMediaController.getVoiceNotePlaybackState().observe(getViewLifecycleOwner(), observer);
}
@Override
public void unregisterPlaybackStateObserver(@NonNull Observer<VoiceNotePlaybackState> observer) {
voiceNoteMediaController.getVoiceNotePlaybackState().removeObserver(observer);
}
private class ActionModeCallback implements ActionMode.Callback { private class ActionModeCallback implements ActionMode.Callback {
private int originalStatusBarColor; private int originalStatusBarColor;

View File

@ -57,6 +57,7 @@ public class NotificationChannels {
public static final String BACKUPS = "backups_v2"; public static final String BACKUPS = "backups_v2";
public static final String LOCKED_STATUS = "locked_status_v2"; public static final String LOCKED_STATUS = "locked_status_v2";
public static final String OTHER = "other_v2"; public static final String OTHER = "other_v2";
public static final String VOICE_NOTES = "voice_notes";
/** /**
* Ensures all of the notification channels are created. No harm in repeat calls. Call is safely * Ensures all of the notification channels are created. No harm in repeat calls. Call is safely
@ -449,6 +450,7 @@ public class NotificationChannels {
NotificationChannel backups = new NotificationChannel(BACKUPS, context.getString(R.string.NotificationChannel_backups), NotificationManager.IMPORTANCE_LOW); NotificationChannel backups = new NotificationChannel(BACKUPS, context.getString(R.string.NotificationChannel_backups), NotificationManager.IMPORTANCE_LOW);
NotificationChannel lockedStatus = new NotificationChannel(LOCKED_STATUS, context.getString(R.string.NotificationChannel_locked_status), NotificationManager.IMPORTANCE_LOW); NotificationChannel lockedStatus = new NotificationChannel(LOCKED_STATUS, context.getString(R.string.NotificationChannel_locked_status), NotificationManager.IMPORTANCE_LOW);
NotificationChannel other = new NotificationChannel(OTHER, context.getString(R.string.NotificationChannel_other), NotificationManager.IMPORTANCE_LOW); NotificationChannel other = new NotificationChannel(OTHER, context.getString(R.string.NotificationChannel_other), NotificationManager.IMPORTANCE_LOW);
NotificationChannel voiceNotes = new NotificationChannel(VOICE_NOTES, context.getString(R.string.NotificationChannel_voice_notes), NotificationManager.IMPORTANCE_LOW);
messages.setGroup(CATEGORY_MESSAGES); messages.setGroup(CATEGORY_MESSAGES);
messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context)); messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context));
@ -459,8 +461,9 @@ public class NotificationChannels {
backups.setShowBadge(false); backups.setShowBadge(false);
lockedStatus.setShowBadge(false); lockedStatus.setShowBadge(false);
other.setShowBadge(false); other.setShowBadge(false);
voiceNotes.setShowBadge(false);
notificationManager.createNotificationChannels(Arrays.asList(messages, calls, failures, backups, lockedStatus, other)); notificationManager.createNotificationChannels(Arrays.asList(messages, calls, failures, backups, lockedStatus, other, voiceNotes));
if (BuildConfig.PLAY_STORE_DISABLED) { if (BuildConfig.PLAY_STORE_DISABLED) {
NotificationChannel appUpdates = new NotificationChannel(APP_UPDATES, context.getString(R.string.NotificationChannel_app_updates), NotificationManager.IMPORTANCE_HIGH); NotificationChannel appUpdates = new NotificationChannel(APP_UPDATES, context.getString(R.string.NotificationChannel_app_updates), NotificationManager.IMPORTANCE_HIGH);

View File

@ -1587,6 +1587,7 @@
<string name="NotificationChannel_other">Other</string> <string name="NotificationChannel_other">Other</string>
<string name="NotificationChannel_group_messages">Messages</string> <string name="NotificationChannel_group_messages">Messages</string>
<string name="NotificationChannel_missing_display_name">Unknown</string> <string name="NotificationChannel_missing_display_name">Unknown</string>
<string name="NotificationChannel_voice_notes">Voice Notes</string>
<!-- ProfileEditNameFragment --> <!-- ProfileEditNameFragment -->
<string name="ProfileEditNameFragment_successfully_set_profile_name">Successfully set profile name.</string> <string name="ProfileEditNameFragment_successfully_set_profile_name">Successfully set profile name.</string>