Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lock Screen Controls and Metadata Support for Windows, Android, IOS and Mac Catalyst #1782

Merged
merged 70 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
69df1c4
The most significant changes involve the addition of new metadata pro…
ne0rrmatrix Mar 26, 2024
e366a71
Merge branch 'CommunityToolkit:main' into MetaData
ne0rrmatrix Mar 26, 2024
0c86c02
The most significant changes involve updates to various project files…
ne0rrmatrix Mar 29, 2024
a30fc2e
Merge branch 'MetaData' of https://github.com/ne0rrmatrix/MauiOld int…
ne0rrmatrix Mar 29, 2024
0c583dd
Merge branch 'CommunityToolkit:main' into MetaData
ne0rrmatrix Mar 29, 2024
71b2cc5
The most significant changes involve the refactoring of the `MediaCon…
ne0rrmatrix Mar 30, 2024
70cf495
Merge branch 'MetaData' of https://github.com/ne0rrmatrix/MauiOld int…
ne0rrmatrix Mar 30, 2024
e65e46d
The most significant changes involve the addition of a new parameter …
ne0rrmatrix Mar 30, 2024
5d4a163
The most significant changes were made to the `MediaControlsService.a…
ne0rrmatrix Mar 31, 2024
c941467
The most significant changes involve the addition of new media contro…
ne0rrmatrix Mar 31, 2024
663917e
Add permissions and background modes for MacCatalyst app
ne0rrmatrix Apr 1, 2024
c546305
Fix playback rate type conversion in MetaDataExtensions.macios.cs and…
ne0rrmatrix Apr 1, 2024
753ea1b
The most significant changes involve the removal of the `MetaDataExte…
ne0rrmatrix Apr 1, 2024
0bd376a
The most significant changes were made to the `MediaControlsService.a…
ne0rrmatrix Apr 4, 2024
5201496
Merge branch 'main' into MetaData
ne0rrmatrix Apr 4, 2024
57d334f
The most significant changes to the `MediaControlsService` class invo…
ne0rrmatrix Apr 4, 2024
ddcb23d
minor cosmetic fixes
ne0rrmatrix Apr 4, 2024
8cb93a4
Merge branch 'main' into MetaData
ne0rrmatrix Apr 4, 2024
1480655
Merge branch 'main' into MetaData
ne0rrmatrix Apr 4, 2024
d9f97f2
The most significant changes involve renaming and redefining certain …
ne0rrmatrix Apr 5, 2024
82c2adc
Merge branch 'MetaData' of https://github.com/ne0rrmatrix/MauiOld int…
ne0rrmatrix Apr 5, 2024
8500178
The most significant changes involve renaming and redefining certain …
ne0rrmatrix Apr 5, 2024
6bfff10
The most significant change is the removal of a line of code from the…
ne0rrmatrix Apr 6, 2024
35076a2
The most significant change is the modification of the `Dispose` meth…
ne0rrmatrix Apr 6, 2024
a756d20
The most significant changes in the code involve the refactoring of t…
ne0rrmatrix Apr 7, 2024
8fb824b
The most significant changes in the code include the removal of unuse…
ne0rrmatrix Apr 7, 2024
5ddea49
The `LaunchMode` attribute in `MainActivity.cs` was changed from `Sin…
ne0rrmatrix Apr 7, 2024
5757d3a
The most significant changes involve the `MediaControlsService` and `…
ne0rrmatrix Apr 7, 2024
b33b1e4
The most significant changes involve the addition of new actions to t…
ne0rrmatrix Apr 7, 2024
bcd62cc
The most significant changes involve the refactoring of the `MetaData…
ne0rrmatrix Apr 7, 2024
6c67206
The most significant changes involve the display of album name and ar…
ne0rrmatrix Apr 11, 2024
d1940dd
The most significant changes involve the removal of the `SourceType` …
ne0rrmatrix Apr 11, 2024
cc69920
The most significant change is the reorganization of services related…
ne0rrmatrix Apr 12, 2024
770836f
Merge branch 'main' into MetaData
ne0rrmatrix Apr 18, 2024
cd8f9b7
The most significant changes include the conditional inclusion of per…
ne0rrmatrix Apr 19, 2024
1a37aaf
The most significant changes involve modifications to the `MediaContr…
ne0rrmatrix Apr 19, 2024
7b07ace
The most significant changes involve the `MetaDataExtensions` class i…
ne0rrmatrix Apr 19, 2024
d899312
The most significant changes in the code are the refactoring of condi…
ne0rrmatrix Apr 21, 2024
a404dbe
Fix potential security issue with having `android:exported` by not ex…
ne0rrmatrix Apr 21, 2024
39a90a0
Update src/CommunityToolkit.Maui.MediaElement/Extensions/MetaDataExte…
ne0rrmatrix Apr 21, 2024
140a9e6
Update src/CommunityToolkit.Maui.MediaElement/Extensions/MetaDataExte…
ne0rrmatrix Apr 21, 2024
346afd3
Update src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.andr…
ne0rrmatrix Apr 21, 2024
e3abfa1
Update src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.andr…
ne0rrmatrix Apr 21, 2024
31c5fbe
The most significant changes are in the `MetaDataExtensions.macios.cs…
ne0rrmatrix Apr 21, 2024
48a3ebb
The most significant changes involve the addition of four new fields …
ne0rrmatrix Apr 21, 2024
29efe47
The `Dispose(bool disposing)` method has been updated to remove the e…
ne0rrmatrix Apr 21, 2024
f6bce0b
reverting last change. Outside scope of PR. Change is needed but is n…
ne0rrmatrix Apr 21, 2024
6958df6
cache the android permissions
pictos Apr 22, 2024
badf750
adjust player to work better with async code
pictos Apr 22, 2024
1208c99
removed cast
pictos Apr 22, 2024
d0d675e
updated tokens to be optional and add a timeout on TCS
pictos Apr 22, 2024
b5cc156
adjust async call with ContinueWith
pictos Apr 22, 2024
a17e076
inline action since will be used just once
pictos Apr 22, 2024
fc2229e
update event name
pictos Apr 22, 2024
8d4d33e
use string instead of String
pictos Apr 22, 2024
3269bed
fix build error
pictos Apr 22, 2024
f66023d
Fix build error - class name was changed but filename was not.
ne0rrmatrix Apr 22, 2024
29efd2e
The most significant changes involve the refactoring of the `GetBitma…
ne0rrmatrix Apr 22, 2024
ac98b64
The most significant changes involve the update of the URL for the `M…
ne0rrmatrix Apr 24, 2024
6239c5f
Merge branch 'main' into MetaData
ne0rrmatrix Apr 28, 2024
bb62898
Merge branch 'main' into MetaData
ne0rrmatrix Apr 29, 2024
16e930f
The most significant change is the renaming of the service in the And…
ne0rrmatrix Apr 29, 2024
4de39e0
Merge branch 'main' into MetaData
ne0rrmatrix Apr 30, 2024
828633d
Merge branch 'main' into MetaData
ne0rrmatrix May 27, 2024
a143587
Merge branch 'main' into MetaData
ne0rrmatrix May 28, 2024
10798a5
Merge branch 'main' into MetaData
brminnick Jun 3, 2024
a150b84
Update Naming + Formatting
brminnick Jun 5, 2024
98cafe2
Fix naming violation
brminnick Jun 5, 2024
5ec1c20
`dotnet format`
brminnick Jun 5, 2024
339e97d
Remove `NSAppTransportSecurity`
brminnick Jun 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetVersion)-ios;$(NetVersion)-android;$(NetVersion)-maccatalyst</TargetFrameworks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@
x:Name="MediaElement"
ShouldAutoPlay="True"
Source="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
MetadataArtworkUrl="https://lh3.googleusercontent.com/pw/AP1GczNRrebWCJvfdIau1EbsyyYiwAfwHS0JXjbioXvHqEwYIIdCzuLodQCZmA57GADIo5iB3yMMx3t_vsefbfoHwSg0jfUjIXaI83xpiih6d-oT7qD_slR0VgNtfAwJhDBU09kS5V2T5ZML-WWZn8IrjD4J-g=w1792-h1024-s-no-gm"
MetadataTitle="Big Buck Bunny"
MetadataArtist="Blender Foundation"
MediaEnded="OnMediaEnded"
MediaFailed="OnMediaFailed"
MediaOpened="OnMediaOpened"
PositionChanged="OnPositionChanged"
StateChanged="OnStateChanged"
SeekCompleted="OnSeekCompleted"/>

<HorizontalStackLayout Grid.Row="1" Padding="0,0,0,15">
<Label HorizontalOptions="Center">
<Label.Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel;
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Core.Primitives;
using CommunityToolkit.Maui.Sample.ViewModels.Views;
using CommunityToolkit.Maui.Views;
Expand Down Expand Up @@ -159,22 +160,35 @@ async void ChangeSourceClicked(Object sender, EventArgs e)
switch (result)
{
case loadOnlineMp4:
MediaElement.MetadataTitle = "Big Buck Bunny";
MediaElement.MetadataArtworkUrl = "https://lh3.googleusercontent.com/pw/AP1GczNRrebWCJvfdIau1EbsyyYiwAfwHS0JXjbioXvHqEwYIIdCzuLodQCZmA57GADIo5iB3yMMx3t_vsefbfoHwSg0jfUjIXaI83xpiih6d-oT7qD_slR0VgNtfAwJhDBU09kS5V2T5ZML-WWZn8IrjD4J-g=w1792-h1024-s-no-gm";
MediaElement.MetadataArtist = "Big Buck Bunny Album";
MediaElement.Source =
MediaSource.FromUri(
"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4");
return;

case loadHls:
MediaElement.MetadataArtist = "HLS Album";
MediaElement.MetadataArtworkUrl = "https://lh3.googleusercontent.com/pw/AP1GczNRrebWCJvfdIau1EbsyyYiwAfwHS0JXjbioXvHqEwYIIdCzuLodQCZmA57GADIo5iB3yMMx3t_vsefbfoHwSg0jfUjIXaI83xpiih6d-oT7qD_slR0VgNtfAwJhDBU09kS5V2T5ZML-WWZn8IrjD4J-g=w1792-h1024-s-no-gm";
MediaElement.MetadataTitle = "HLS Title";
MediaElement.Source
= MediaSource.FromUri(
"https://mtoczko.github.io/hls-test-streams/test-gap/playlist.m3u8");
return;

case resetSource:
MediaElement.MetadataArtworkUrl = string.Empty;
MediaElement.MetadataTitle = string.Empty;
MediaElement.MetadataArtist = string.Empty;
MediaElement.Source = null;
return;

case loadLocalResource:
MediaElement.MetadataArtworkUrl = "https://lh3.googleusercontent.com/pw/AP1GczNRrebWCJvfdIau1EbsyyYiwAfwHS0JXjbioXvHqEwYIIdCzuLodQCZmA57GADIo5iB3yMMx3t_vsefbfoHwSg0jfUjIXaI83xpiih6d-oT7qD_slR0VgNtfAwJhDBU09kS5V2T5ZML-WWZn8IrjD4J-g=w1792-h1024-s-no-gm";
MediaElement.MetadataTitle = "Local Resource Title";
MediaElement.MetadataArtist = "Local Resource Album";

ne0rrmatrix marked this conversation as resolved.
Show resolved Hide resolved
if (DeviceInfo.Platform == DevicePlatform.MacCatalyst
|| DeviceInfo.Platform == DevicePlatform.iOS)
{
Expand All @@ -192,7 +206,7 @@ async void ChangeSourceClicked(Object sender, EventArgs e)
}
}

async void ChangeAspectClicked(Object sender, EventArgs e)
async void ChangeAspectClicked(object? sender, EventArgs e)
{
var resultAspect = await DisplayActionSheet("Choose aspect ratio",
"Cancel", null, Aspect.AspectFit.ToString(),
Expand All @@ -203,11 +217,9 @@ async void ChangeAspectClicked(Object sender, EventArgs e)
return;
}

if (!Enum.TryParse(typeof(Aspect), resultAspect, true, out var aspectEnum)
|| aspectEnum is null)
if (!Enum.TryParse(typeof(Aspect), resultAspect, true, out var aspectEnum))
{
await DisplayAlert("Error", "There was an error determining the selected aspect",
"OK");
await DisplayAlert("Error", "There was an error determining the selected aspect", "OK");

return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true" />
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:enableOnBackInvokedCallback="true" android:supportsRtl="true">
<service android:name="CommunityToolkit.Maui.Media.Services" android:exported="false" android:enabled="true" android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />

<!-- Samsung -->
<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<queries>
<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@
<string>Assets.xcassets/appicon.appiconset</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>ISpeechToText Uses Speech Recognition</string>
<key>NSLocalNetworkUsageDescription</key>
<string></string>
<key>NSMicrophoneUsageDescription</key>
<string>ISpeechToText Uses Microphone</string>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>audio</string>
</array>
</dict>
</plist>
4 changes: 4 additions & 0 deletions samples/CommunityToolkit.Maui.Sample/Platforms/iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@
<string>ISpeechToText Uses Speech Recognition</string>
<key>NSMicrophoneUsageDescription</key>
<string>ISpeechToText Uses Microphone</string>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CommunityToolkit.Maui.Core.Handlers;
using CommunityToolkit.Maui.Core.Views;
using CommunityToolkit.Maui.Views;

namespace CommunityToolkit.Maui;
Expand All @@ -20,6 +21,9 @@ public static MauiAppBuilder UseMauiCommunityToolkitMediaElement(this MauiAppBui
h.AddHandler<MediaElement, MediaElementHandler>();
});

#if ANDROID
builder.Services.AddSingleton<Media.Services.MediaControlsService>();
#endif
return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@
<None Include="..\CommunityToolkit.Maui.MediaElement.Analyzers\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Maui.MediaElement.Analyzers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false"/>
<None Include="..\CommunityToolkit.Maui.MediaElement.Analyzers.CodeFixes\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Maui.MediaElement.Analyzers.CodeFixes.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false"/>
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.Contains('-android'))">
<PackageReference Include="Xam.Plugins.Android.ExoPlayer" Version="[2.19.1,)"/>
<PackageReference Include="Xam.Plugins.Android.ExoPlayer.Transformer" Version="[2.19.1,)"/>
<PackageReference Include="Xam.Plugins.Android.ExoPlayer.MediaSession" Version="[2.19.1,)"/>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public sealed class FileMediaSourceConverter : TypeConverter
{
/// <inheritdoc/>
/// <exception cref="InvalidOperationException">Thrown when <paramref name="value"/> is <see langword="null"/> or empty.</exception>
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var filePath = value?.ToString() ?? string.Empty;
var filePath = value.ToString() ?? string.Empty;

return string.IsNullOrWhiteSpace(filePath)
? (FileMediaSource)MediaSource.FromFile(filePath)
Expand Down
15 changes: 15 additions & 0 deletions src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ namespace CommunityToolkit.Maui.Core;
/// </summary>
public interface IMediaElement : IView, IAsynchronousMediaElementHandler
{
/// <summary>
/// Gets or sets the title of the media.
/// </summary>
string MetadataTitle { get; set; }

/// <summary>
/// Gets or sets the artist of the media.
/// </summary>
string MetadataArtist { get; set; }

/// <summary>
/// Gets or sets the artwork Image Url.
/// </summary>
string MetadataArtworkUrl { get; set; }

/// <summary>
/// Gets the media aspect ratio.
/// </summary>
Expand Down
52 changes: 49 additions & 3 deletions src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ public class MediaElement : View, IMediaElement, IDisposable
public static readonly BindableProperty AspectProperty =
BindableProperty.Create(nameof(Aspect), typeof(Aspect), typeof(MediaElement), Aspect.AspectFit);

static readonly BindablePropertyKey durationPropertyKey =
BindableProperty.CreateReadOnly(nameof(Duration), typeof(TimeSpan), typeof(MediaElement), TimeSpan.Zero);

/// <summary>
/// Backing store for the <see cref="CurrentState"/> property.
/// </summary>
public static readonly BindableProperty CurrentStateProperty =
BindableProperty.Create(nameof(CurrentState), typeof(MediaElementState), typeof(MediaElement),
MediaElementState.None, propertyChanged: OnCurrentStatePropertyChanged);

static readonly BindablePropertyKey durationPropertyKey =
BindableProperty.CreateReadOnly(nameof(Duration), typeof(TimeSpan), typeof(MediaElement), TimeSpan.Zero);

/// <summary>
/// Backing store for the <see cref="Duration"/> property.
/// </summary>
Expand Down Expand Up @@ -99,6 +99,21 @@ public class MediaElement : View, IMediaElement, IDisposable
BindableProperty.Create(nameof(Volume), typeof(double), typeof(MediaElement), 1.0,
BindingMode.TwoWay, propertyChanging: ValidateVolume);

/// <summary>
/// Backing store for the <see cref="MetadataTitle"/> property.
/// </summary>
public static readonly BindableProperty MetadataTitleProperty = BindableProperty.Create(nameof(MetadataTitle), typeof(string), typeof(MediaElement), string.Empty);

/// <summary>
/// Backing store for the <see cref="MetadataArtist"/> property.
/// </summary>
public static readonly BindableProperty MetadataArtistProperty = BindableProperty.Create(nameof(MetadataArtist), typeof(string), typeof(MediaElement), string.Empty);

/// <summary>
/// Backing store for the <see cref="MetadataArtworkUrl"/> property.
/// </summary>
public static readonly BindableProperty MetadataArtworkUrlProperty = BindableProperty.Create(nameof(MetadataArtworkUrl), typeof(string), typeof(MediaElement), string.Empty);

readonly WeakEventManager eventManager = new();
readonly SemaphoreSlim seekToSemaphoreSlim = new(1, 1);

Expand Down Expand Up @@ -315,6 +330,36 @@ public int MediaWidth
internal set => SetValue(MediaWidthProperty, value);
}

/// <summary>
/// Gets or sets the Title of the media.
/// This is a bindable property.
/// </summary>
public string MetadataTitle
{
get => (string)GetValue(MetadataTitleProperty);
set => SetValue(MetadataTitleProperty, value);
}

/// <summary>
/// Gets or sets the Artist of the media.
/// This is a bindable property.
/// </summary>
public string MetadataArtist
{
get => (string)GetValue(MetadataArtistProperty);
set => SetValue(MetadataArtistProperty, value);
}

/// <summary>
/// Gets or sets the Artwork Image Url of the media.
/// This is a bindable property.
/// </summary>
public string MetadataArtworkUrl
{
get => (string)GetValue(MetadataArtworkUrlProperty);
set => SetValue(MetadataArtworkUrlProperty, value);
}

/// <summary>
/// Gets or sets how the media will be scaled to fit the display area.
/// Default value is <see cref="Aspect.AspectFit"/>. This is a bindable property.
Expand Down Expand Up @@ -355,6 +400,7 @@ TimeSpan IMediaElement.Duration
set => SetValue(durationPropertyKey, value);
}


/// <inheritdoc/>
TaskCompletionSource IAsynchronousMediaElementHandler.SeekCompletedTCS => seekCompletedTaskCompletionSource;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using static Microsoft.Maui.ApplicationModel.Permissions;

namespace CommunityToolkit.Maui.ApplicationModel.Permissions;

sealed class AndroidMediaPermissions : BasePlatformPermission
{
static readonly Lazy<(string androidPermission, bool isRuntime)[]> permissionsHolder = new(CreatePermissions);

public override (string androidPermission, bool isRuntime)[] RequiredPermissions => permissionsHolder.Value;

static (string androidPermission, bool isRuntime)[] CreatePermissions()
{
List<(string androidPermission, bool isRuntime)> requiredPermissionsList = new();

if (OperatingSystem.IsAndroidVersionAtLeast(28))
{
requiredPermissionsList.Add((global::Android.Manifest.Permission.ForegroundService, true));
}

if (OperatingSystem.IsAndroidVersionAtLeast(33))
{
requiredPermissionsList.Add((global::Android.Manifest.Permission.PostNotifications, true));
}

return [.. requiredPermissionsList];
}
}
Loading
Loading