diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7ec50c0674..cb41231c1a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -60,6 +60,9 @@ `ImaServerSideAdInsertionMediaSource.AdsLoader.Builder` to request focusing the skip button on TV devices and set it to true by default. * Bump IMA SDK version to 3.29.0. +* Demo app + * Request notification permission for download notifications at runtime + ([#10884](https://github.com/google/ExoPlayer/issues/10884)). ### 1.0.0-beta03 (2022-11-22) diff --git a/demos/main/src/main/AndroidManifest.xml b/demos/main/src/main/AndroidManifest.xml index 401d73a8e6..21d07e4ee5 100644 --- a/demos/main/src/main/AndroidManifest.xml +++ b/demos/main/src/main/AndroidManifest.xml @@ -23,6 +23,7 @@ + diff --git a/demos/main/src/main/java/androidx/media3/demo/main/SampleChooserActivity.java b/demos/main/src/main/java/androidx/media3/demo/main/SampleChooserActivity.java index fc7144dc91..ef01b148ca 100644 --- a/demos/main/src/main/java/androidx/media3/demo/main/SampleChooserActivity.java +++ b/demos/main/src/main/java/androidx/media3/demo/main/SampleChooserActivity.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -41,8 +42,10 @@ import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.DoNotInline; import androidx.annotation.Nullable; import androidx.annotation.OptIn; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem.ClippingConfiguration; @@ -76,6 +79,7 @@ public class SampleChooserActivity extends AppCompatActivity private static final String TAG = "SampleChooserActivity"; private static final String GROUP_POSITION_PREFERENCE_KEY = "sample_chooser_group_position"; private static final String CHILD_POSITION_PREFERENCE_KEY = "sample_chooser_child_position"; + private static final int POST_NOTIFICATION_PERMISSION_REQUEST_CODE = 100; private String[] uris; private boolean useExtensionRenderers; @@ -83,6 +87,8 @@ public class SampleChooserActivity extends AppCompatActivity private SampleAdapter sampleAdapter; private MenuItem preferExtensionDecodersMenuItem; private ExpandableListView sampleListView; + @Nullable private MediaItem downloadMediaItemWaitingForNotificationPermission; + private boolean notificationPermissionToastShown; @Override public void onCreate(Bundle savedInstanceState) { @@ -172,12 +178,34 @@ public class SampleChooserActivity extends AppCompatActivity public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == POST_NOTIFICATION_PERMISSION_REQUEST_CODE) { + handlePostNotificationPermissionGrantResults(grantResults); + } else { + handleExternalStoragePermissionGrantResults(grantResults); + } + } + + private void handlePostNotificationPermissionGrantResults(int[] grantResults) { + if (!notificationPermissionToastShown + && (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED)) { + Toast.makeText( + getApplicationContext(), R.string.post_notification_not_granted, Toast.LENGTH_LONG) + .show(); + notificationPermissionToastShown = true; + } + if (downloadMediaItemWaitingForNotificationPermission != null) { + // Download with or without permission to post notifications. + toggleDownload(downloadMediaItemWaitingForNotificationPermission); + downloadMediaItemWaitingForNotificationPermission = null; + } + } + + private void handleExternalStoragePermissionGrantResults(int[] grantResults) { if (grantResults.length == 0) { // Empty results are triggered if a permission is requested while another request was already // pending and can be safely ignored in this case. return; - } - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { loadSample(); } else { Toast.makeText(getApplicationContext(), R.string.sample_list_load_error, Toast.LENGTH_LONG) @@ -244,15 +272,26 @@ public class SampleChooserActivity extends AppCompatActivity if (downloadUnsupportedStringId != 0) { Toast.makeText(getApplicationContext(), downloadUnsupportedStringId, Toast.LENGTH_LONG) .show(); + } else if (!notificationPermissionToastShown + && Util.SDK_INT >= 33 + && checkSelfPermission(Api33.getPostNotificationPermissionString()) + != PackageManager.PERMISSION_GRANTED) { + downloadMediaItemWaitingForNotificationPermission = playlistHolder.mediaItems.get(0); + requestPermissions( + new String[] {Api33.getPostNotificationPermissionString()}, + /* requestCode= */ POST_NOTIFICATION_PERMISSION_REQUEST_CODE); } else { - RenderersFactory renderersFactory = - DemoUtil.buildRenderersFactory( - /* context= */ this, isNonNullAndChecked(preferExtensionDecodersMenuItem)); - downloadTracker.toggleDownload( - getSupportFragmentManager(), playlistHolder.mediaItems.get(0), renderersFactory); + toggleDownload(playlistHolder.mediaItems.get(0)); } } + private void toggleDownload(MediaItem mediaItem) { + RenderersFactory renderersFactory = + DemoUtil.buildRenderersFactory( + /* context= */ this, isNonNullAndChecked(preferExtensionDecodersMenuItem)); + downloadTracker.toggleDownload(getSupportFragmentManager(), mediaItem, renderersFactory); + } + private int getDownloadUnsupportedStringId(PlaylistHolder playlistHolder) { if (playlistHolder.mediaItems.size() > 1) { return R.string.download_playlist_unsupported; @@ -630,4 +669,13 @@ public class SampleChooserActivity extends AppCompatActivity this.playlists = new ArrayList<>(); } } + + @RequiresApi(33) + private static class Api33 { + + @DoNotInline + public static String getPostNotificationPermissionString() { + return Manifest.permission.POST_NOTIFICATIONS; + } + } } diff --git a/demos/main/src/main/res/values/strings.xml b/demos/main/src/main/res/values/strings.xml index 49441ef7da..ce9c90d0c2 100644 --- a/demos/main/src/main/res/values/strings.xml +++ b/demos/main/src/main/res/values/strings.xml @@ -45,6 +45,8 @@ One or more sample lists failed to load + Notifications suppressed. Grant permission to see download notifications. + Failed to start download Failed to obtain offline license