Skip to content

Commit

Permalink
Merge pull request #408 from androidx/release-1.0.2
Browse files Browse the repository at this point in the history
1.0.2
  • Loading branch information
icbaker committed May 17, 2023
2 parents 3c01488 + d77e79a commit 2fc189d
Show file tree
Hide file tree
Showing 59 changed files with 1,294 additions and 372 deletions.
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ body:
label: Media3 Version
description: What version of Media3 (or ExoPlayer) are you using?
options:
- Media3 1.1.0-alpha01
- Media3 1.0.2
- Media3 1.0.1
- Media3 1.0.0
- Media3 1.0.0-rc02
Expand All @@ -30,6 +32,8 @@ body:
- Media3 1.0.0-alpha03
- Media3 1.0.0-alpha02
- Media3 1.0.0-alpha01
- Media3 `main` branch
- ExoPlayer 2.18.7
- ExoPlayer 2.18.6
- ExoPlayer 2.18.5
- ExoPlayer 2.18.4
Expand All @@ -46,6 +50,7 @@ body:
- ExoPlayer 2.14.2
- ExoPlayer 2.14.1
- ExoPlayer 2.14.0
- ExoPlayer `dev-v2` branch
- Older (unsupported)
validations:
required: true
Expand Down
35 changes: 35 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
# Release notes

### 1.0.2 (2023-05-18)

This release corresponds to the
[ExoPlayer 2.18.7 release](https://github.com/google/ExoPlayer/releases/tag/r2.18.7).

This release contains the following changes since the
[1.0.1 release](#101-2023-04-18):

* Core library:
* Add `Buffer.isLastSample()` that denotes if `Buffer` contains flag
`C.BUFFER_FLAG_LAST_SAMPLE`.
* Fix issue where last frame may not be rendered if the last sample with
frames is dequeued without reading the 'end of stream' sample.
([#11079](https://github.com/google/ExoPlayer/issues/11079)).
* Extractors:
* Fix parsing of H.265 SPS in MPEG-TS files by re-using the parsing logic
already used by RTSP and MP4 extractors
([#303](https://github.com/androidx/media/issues/303)).
* Text:
* SSA: Add support for UTF-16 files if they start with a byte order mark
([#319](https://github.com/androidx/media/issues/319)).
* Session:
* Fix issue where `MediaController` doesn't update its available commands
when connected to a legacy `MediaSessionCompat` that updates its
actions.
* Fix bug that prevented the `MediaLibraryService` from returning null for
a call from System UI to `Callback.onGetLibraryRoot` with
`params.isRecent == true` on API 30
([#355](https://github.com/androidx/media/issues/355)).
* Fix memory leak of `MediaSessionService` or `MediaLibraryService`
([#346](https://github.com/androidx/media/issues/346)).
* Fix bug where a combined `Timeline` and position update in a
`MediaSession` may cause a `MediaController` to throw an
`IllegalStateException`.

### 1.0.1 (2023-04-18)

This release corresponds to the
Expand Down
4 changes: 2 additions & 2 deletions constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
project.ext {
releaseVersion = '1.0.1'
releaseVersionCode = 1_000_001_3_00
releaseVersion = '1.0.2'
releaseVersionCode = 1_000_002_3_00
minSdkVersion = 16
appTargetSdkVersion = 33
// API version before restricting local file access.
Expand Down
2 changes: 2 additions & 0 deletions core_settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ if (gradle.ext.has('androidxMediaModulePrefix')) {
modulePrefix += gradle.ext.androidxMediaModulePrefix
}

rootProject.name = gradle.ext.androidxMediaProjectName

include modulePrefix + 'lib-common'
project(modulePrefix + 'lib-common').projectDir = new File(rootDir, 'libraries/common')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ public void onTracksChanged(Tracks tracks) {

private class PlayerErrorMessageProvider implements ErrorMessageProvider<PlaybackException> {

@OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
@Override
public Pair<Integer, String> getErrorMessage(PlaybackException e) {
String errorString = getString(R.string.error_generic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.JsonReader;
Expand Down Expand Up @@ -273,7 +274,7 @@ private void onSampleDownloadButtonClicked(PlaylistHolder playlistHolder) {
Toast.makeText(getApplicationContext(), downloadUnsupportedStringId, Toast.LENGTH_LONG)
.show();
} else if (!notificationPermissionToastShown
&& Util.SDK_INT >= 33
&& Build.VERSION.SDK_INT >= 33
&& checkSelfPermission(Api33.getPostNotificationPermissionString())
!= PackageManager.PERMISSION_GRANTED) {
downloadMediaItemWaitingForNotificationPermission = playlistHolder.mediaItems.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package androidx.media3.demo.session

import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent.*
Expand All @@ -29,6 +30,7 @@ import androidx.media3.common.MediaItem
import androidx.media3.common.util.Util
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.*
import androidx.media3.session.LibraryResult.RESULT_ERROR_NOT_SUPPORTED
import androidx.media3.session.MediaSession.ControllerInfo
import com.google.common.collect.ImmutableList
import com.google.common.util.concurrent.Futures
Expand Down Expand Up @@ -95,7 +97,7 @@ class PlaybackService : MediaLibraryService() {
): MediaSession.ConnectionResult {
val connectionResult = super.onConnect(session, controller)
val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon()
customCommands.forEach { commandButton ->
for (commandButton in customCommands) {
// Add custom command to available session commands.
commandButton.sessionCommand?.let { availableSessionCommands.add(it) }
}
Expand Down Expand Up @@ -142,6 +144,12 @@ class PlaybackService : MediaLibraryService() {
browser: ControllerInfo,
params: LibraryParams?
): ListenableFuture<LibraryResult<MediaItem>> {
if (params != null && params.isRecent) {
// The service currently does not support playback resumption. Tell System UI by returning
// an error of type 'RESULT_ERROR_NOT_SUPPORTED' for a `params.isRecent` request. See
// https://github.com/androidx/media/issues/355
return Futures.immediateFuture(LibraryResult.ofError(RESULT_ERROR_NOT_SUPPORTED))
}
return Futures.immediateFuture(LibraryResult.ofItem(MediaItemTree.getRootItem(), params))
}

Expand Down Expand Up @@ -270,6 +278,7 @@ class PlaybackService : MediaLibraryService() {
* by a media controller to resume playback when the {@link MediaSessionService} is in the
* background.
*/
@SuppressLint("MissingPermission") // TODO: b/280766358 - Request this permission at runtime.
override fun onForegroundServiceStartNotAllowedException() {
val notificationManagerCompat = NotificationManagerCompat.from(this@PlaybackService)
ensureNotificationChannel(notificationManagerCompat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,6 @@ class PlayerActivity : AppCompatActivity() {
initializeController()
}

override fun onResume() {
super.onResume()
playerView.onResume()
}

override fun onPause() {
super.onPause()
playerView.onPause()
}

override fun onStop() {
super.onStop()
playerView.player = null
Expand Down
2 changes: 1 addition & 1 deletion libraries/common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ rootProject.allprojects.forEach {
evaluationDependsOn(':' + it.name)
}
}
// copybara:media3-only

android {
buildTypes {
debug {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ public final class MediaLibraryInfo {

/** The version of the library expressed as a string, for example "1.2.3" or "1.2.3-beta01". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public static final String VERSION = "1.0.1";
public static final String VERSION = "1.0.2";

/** The version of the library expressed as {@code TAG + "/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final String VERSION_SLASHY = "AndroidXMedia3/1.0.1";
public static final String VERSION_SLASHY = "AndroidXMedia3/1.0.2";

/**
* The version of the library expressed as an integer, for example 1002003300.
Expand All @@ -47,7 +47,7 @@ public final class MediaLibraryInfo {
* (123-045-006-3-00).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final int VERSION_INT = 1_000_001_3_00;
public static final int VERSION_INT = 1_000_002_3_00;

/** Whether the library was compiled with {@link Assertions} checks enabled. */
public static final boolean ASSERTIONS_ENABLED = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,28 @@ public int peekUnsignedByte() {
return (data[position] & 0xFF);
}

/** Peeks at the next char. */
/**
* Peeks at the next char.
*
* <p>Equivalent to passing {@link Charsets#UTF_16} or {@link Charsets#UTF_16BE} to {@link
* #peekChar(Charset)}.
*/
public char peekChar() {
return (char) ((data[position] & 0xFF) << 8 | (data[position + 1] & 0xFF));
}

/**
* Peeks at the next char (as decoded by {@code charset})
*
* @throws IllegalArgumentException if charset is not supported. Only US_ASCII, UTF-8, UTF-16,
* UTF-16BE, and UTF-16LE are supported.
*/
public char peekChar(Charset charset) {
Assertions.checkArgument(
SUPPORTED_CHARSETS_FOR_READLINE.contains(charset), "Unsupported charset: " + charset);
return (char) (peekCharacterAndSize(charset) >> Short.SIZE);
}

/** Reads the next byte as an unsigned value. */
public int readUnsignedByte() {
return (data[position++] & 0xFF);
Expand Down Expand Up @@ -649,27 +666,42 @@ private void skipLineTerminator(Charset charset) {
* UTF-8 and two bytes for UTF-16).
*/
private char readCharacterIfInList(Charset charset, char[] chars) {
char character;
int characterSize;
int characterAndSize = peekCharacterAndSize(charset);

if (characterAndSize != 0 && Chars.contains(chars, (char) (characterAndSize >> Short.SIZE))) {
position += characterAndSize & 0xFFFF;
return (char) (characterAndSize >> Short.SIZE);
} else {
return 0;
}
}

/**
* Peeks at the character at {@link #position} (as decoded by {@code charset}), returns it and the
* number of bytes the character takes up within the array packed into an int. First four bytes
* are the character and the second four is the size in bytes it takes. Returns 0 if {@link
* #bytesLeft()} doesn't allow reading a whole character in {@code charset} or if the {@code
* charset} is not one of US_ASCII, UTF-8, UTF-16, UTF-16BE, or UTF-16LE.
*
* <p>Only supports characters that occupy a single code unit (i.e. one byte for UTF-8 and two
* bytes for UTF-16).
*/
private int peekCharacterAndSize(Charset charset) {
byte character;
short characterSize;
if ((charset.equals(Charsets.UTF_8) || charset.equals(Charsets.US_ASCII)) && bytesLeft() >= 1) {
character = Chars.checkedCast(UnsignedBytes.toInt(data[position]));
character = (byte) Chars.checkedCast(UnsignedBytes.toInt(data[position]));
characterSize = 1;
} else if ((charset.equals(Charsets.UTF_16) || charset.equals(Charsets.UTF_16BE))
&& bytesLeft() >= 2) {
character = Chars.fromBytes(data[position], data[position + 1]);
character = (byte) Chars.fromBytes(data[position], data[position + 1]);
characterSize = 2;
} else if (charset.equals(Charsets.UTF_16LE) && bytesLeft() >= 2) {
character = Chars.fromBytes(data[position + 1], data[position]);
character = (byte) Chars.fromBytes(data[position + 1], data[position]);
characterSize = 2;
} else {
return 0;
}

if (Chars.contains(chars, character)) {
position += characterSize;
return Chars.checkedCast(character);
} else {
return 0;
}
return (Chars.checkedCast(character) << Short.SIZE) + characterSize;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package androidx.media3.common;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.truth.Truth.assertThat;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.truth.Expect;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

/** Tests for {@link MediaLibraryInfo}. */
@RunWith(AndroidJUnit4.class)
public class MediaLibraryInfoTest {

private static final Pattern VERSION_PATTERN =
Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-(alpha|beta|rc)(\\d\\d))?");

@Rule public final Expect expect = Expect.create();

@Test
public void versionAndSlashyAreConsistent() {
assertThat(MediaLibraryInfo.VERSION_SLASHY)
.isEqualTo("AndroidXMedia3/" + MediaLibraryInfo.VERSION);
}

@Test
public void versionIntIsSelfConsistentAndConsistentWithVersionString() {
// Use the Truth .matches() call so any failure has a clearer error message, then call
// Matcher#matches() below so the subsequent group(int) calls work.
assertThat(MediaLibraryInfo.VERSION).matches(VERSION_PATTERN);
Matcher matcher = VERSION_PATTERN.matcher(MediaLibraryInfo.VERSION);
checkState(matcher.matches());

int major = Integer.parseInt(matcher.group(1));
int minor = Integer.parseInt(matcher.group(2));
int bugfix = Integer.parseInt(matcher.group(3));
String phase = matcher.group(4);

expect.that(major).isAtLeast(1);

int expectedVersionInt = 0;
expectedVersionInt += major * 1_000_000_000;
expectedVersionInt += minor * 1_000_000;
expectedVersionInt += bugfix * 1000;

int phaseInt;
if (phase != null) {
expect.that(bugfix).isEqualTo(0);
switch (phase) {
case "alpha":
phaseInt = 0;
break;
case "beta":
phaseInt = 1;
break;
case "rc":
phaseInt = 2;
break;
default:
throw new AssertionError("Unrecognized phase: " + phase);
}
int phaseCount = Integer.parseInt(matcher.group(5));
expect.that(phaseCount).isAtLeast(1);
expectedVersionInt += phaseCount;
} else {
// phase == null, so this is a stable or bugfix release.
phaseInt = 3;
}
expectedVersionInt += phaseInt * 100;
expect
.withMessage("VERSION_INT for " + MediaLibraryInfo.VERSION)
.that(MediaLibraryInfo.VERSION_INT)
.isEqualTo(expectedVersionInt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public final boolean isKeyFrame() {
return getFlag(C.BUFFER_FLAG_KEY_FRAME);
}

/** Returns whether the {@link C#BUFFER_FLAG_LAST_SAMPLE} flag is set. */
public final boolean isLastSample() {
return getFlag(C.BUFFER_FLAG_LAST_SAMPLE);
}

/** Returns whether the {@link C#BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA} flag is set. */
public final boolean hasSupplementalData() {
return getFlag(C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA);
Expand Down
Loading

0 comments on commit 2fc189d

Please sign in to comment.