Voice Note Beta Feedback fixes.

fork-5.53.8
Alex Hart 2020-10-16 13:14:01 -03:00 zatwierdzone przez GitHub
rodzic 36da519b26
commit 082d9e852c
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
9 zmienionych plików z 145 dodań i 27 usunięć

Wyświetl plik

@ -14,7 +14,6 @@ import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
@ -22,7 +21,6 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.Util;
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_PLAYHEAD = "voice.note.playhead";
public static final String EXTRA_PLAY_SINGLE = "voice.note.play.single";
private static final String TAG = Log.tag(VoiceNoteMediaController.class);
@ -97,15 +96,25 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
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
* slide is currently playing, we jump to the desired position and then begin playback.
*
* @param audioSlideUri The Uri of the desired 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 audioSlideUri The Uri of the desired 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 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)) {
getMediaController().getTransportControls().seekTo(position);
getMediaController().getTransportControls().play();
@ -113,6 +122,7 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
Bundle extras = new Bundle();
extras.putLong(EXTRA_MESSAGE_ID, messageId);
extras.putLong(EXTRA_PLAYHEAD, position);
extras.putBoolean(EXTRA_PLAY_SINGLE, singlePlayback);
getMediaController().getTransportControls().playFromUri(audioSlideUri, extras);
}

Wyświetl plik

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

Wyświetl plik

@ -88,8 +88,9 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
@Override
public void onPrepareFromUri(final Uri uri, Bundle extras) {
long messageId = extras.getLong(VoiceNoteMediaController.EXTRA_MESSAGE_ID);
long position = extras.getLong(VoiceNoteMediaController.EXTRA_PLAYHEAD, 0);
long messageId = extras.getLong(VoiceNoteMediaController.EXTRA_MESSAGE_ID);
long position = extras.getLong(VoiceNoteMediaController.EXTRA_PLAYHEAD, 0);
boolean singlePlayback = extras.getBoolean(VoiceNoteMediaController.EXTRA_PLAY_SINGLE, false);
canLoadMore = false;
latestUri = uri;
@ -98,7 +99,13 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
dataSource.clear();
SimpleTask.run(EXECUTOR,
() -> loadMediaDescriptions(messageId),
() -> {
if (singlePlayback) {
return loadMediaDescriptionForSinglePlayback(messageId);
} else {
return loadMediaDescriptionsForConsecutivePlayback(messageId);
}
},
descriptions -> {
if (Util.hasItems(descriptions) && Objects.equals(latestUri, uri)) {
applyDescriptionsToQueue(descriptions);
@ -116,7 +123,7 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
});
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);
SimpleTask.run(EXECUTOR,
() -> loadMediaDescriptions(messageId),
() -> loadMediaDescriptionsForConsecutivePlayback(messageId),
descriptions -> {
if (Util.hasItems(descriptions) && canLoadMore) {
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
private @NonNull List<MediaDescriptionCompat> loadMediaDescriptions(long messageId) {
private @NonNull List<MediaDescriptionCompat> loadMediaDescriptionsForConsecutivePlayback(long messageId) {
try {
List<MessageRecord> recordsBefore = DatabaseFactory.getMmsSmsDatabase(context).getMessagesBeforeVoiceNoteExclusive(messageId, LIMIT);
List<MessageRecord> recordsAfter = DatabaseFactory.getMmsSmsDatabase(context).getMessagesAfterVoiceNoteInclusive(messageId, LIMIT);

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.components.AudioView;
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.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.GroupedThreadMediaLoader.GroupedThreadMedia;
@ -56,6 +57,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
@ -64,7 +66,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
private final GlideRequests glideRequests;
private final ItemClickListener itemClickListener;
private final Map<AttachmentId, MediaRecord> selected = new HashMap<>();
private final AudioView.Callbacks audioViewCallbacks;
private final AudioItemListener audioItemListener;
private GroupedThreadMedia media;
private boolean showFileSizes;
@ -94,7 +96,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
@NonNull GlideRequests glideRequests,
GroupedThreadMedia media,
ItemClickListener clickListener,
@NonNull AudioView.Callbacks audioViewCallbacks,
@NonNull AudioItemListener audioItemListener,
boolean showFileSizes,
boolean showThread)
{
@ -102,7 +104,7 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
this.glideRequests = glideRequests;
this.media = media;
this.itemClickListener = clickListener;
this.audioViewCallbacks = audioViewCallbacks;
this.audioItemListener = audioItemListener;
this.showFileSizes = showFileSizes;
this.showThread = showThread;
}
@ -435,11 +437,22 @@ final class MediaGalleryAllAdapter extends StickyHeaderGridAdapter {
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));
itemView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord));
}
@Override
void unbind() {
super.unbind();
audioItemListener.unregisterPlaybackStateObserver(audioView.getPlaybackStateObserver());
}
@Override
protected String getFileTypeDescription(@NonNull Context context, @NonNull Slide slide) {
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 {
void onMediaClicked(@NonNull 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);
}
}

Wyświetl plik

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

Wyświetl plik

@ -57,6 +57,7 @@ public class NotificationChannels {
public static final String BACKUPS = "backups_v2";
public static final String LOCKED_STATUS = "locked_status_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
@ -449,6 +450,7 @@ public class NotificationChannels {
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 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.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context));
@ -459,8 +461,9 @@ public class NotificationChannels {
backups.setShowBadge(false);
lockedStatus.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) {
NotificationChannel appUpdates = new NotificationChannel(APP_UPDATES, context.getString(R.string.NotificationChannel_app_updates), NotificationManager.IMPORTANCE_HIGH);

Wyświetl plik

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