From 1b8608f1794af2ae643439f2109feff7481bbfda Mon Sep 17 00:00:00 2001 From: bachinger Date: Wed, 11 Jan 2023 18:39:11 +0000 Subject: [PATCH] Request notification permission in demo app for API 33+ Starting with API 33 the POST_NOTIFICATION permission needs to be requested at runtime or the notification is not shown. Note that with an app with targetSdkVersion < 33 but on a device with API 33 the notification permission is automatically requested when the app starts for the first time. If the user does not grant the permission, requesting the permission at runtime result in an empty array of grant results. Issue: google/ExoPlayer#10884 PiperOrigin-RevId: 501320632 (cherry picked from commit 6484c14acd4197d335cab0b5f2ab9d3eba8c2b39) --- RELEASENOTES.md | 3 + demos/main/src/main/AndroidManifest.xml | 1 + .../demo/main/SampleChooserActivity.java | 62 ++++++++++++++++--- demos/main/src/main/res/values/strings.xml | 2 + 4 files changed, 61 insertions(+), 7 deletions(-) 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