mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-15 03:20:30 +00:00
178 lines
7.4 KiB
C#
178 lines
7.4 KiB
C#
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Android.App;
|
|
using Android.Content;
|
|
using AndroidX.Core.Content;
|
|
using osu.Framework.Android.Graphics.Textures;
|
|
using osu.Framework.Android.Graphics.Video;
|
|
using osu.Framework.Configuration;
|
|
using osu.Framework.Extensions;
|
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
|
using osu.Framework.Extensions.ObjectExtensions;
|
|
using osu.Framework.Graphics.Textures;
|
|
using osu.Framework.Graphics.Video;
|
|
using osu.Framework.IO.Stores;
|
|
using osu.Framework.Logging;
|
|
using osu.Framework.Platform;
|
|
using Stream = System.IO.Stream;
|
|
using Uri = Android.Net.Uri;
|
|
|
|
namespace osu.Framework.Android
|
|
{
|
|
public class AndroidGameHost : SDLGameHost
|
|
{
|
|
private readonly AndroidGameActivity activity;
|
|
|
|
public AndroidGameHost(AndroidGameActivity activity)
|
|
: base(string.Empty)
|
|
{
|
|
this.activity = activity;
|
|
}
|
|
|
|
protected override void SetupConfig(IDictionary<FrameworkSetting, object> defaultOverrides)
|
|
{
|
|
if (!defaultOverrides.ContainsKey(FrameworkSetting.ExecutionMode))
|
|
defaultOverrides.Add(FrameworkSetting.ExecutionMode, ExecutionMode.SingleThread);
|
|
|
|
base.SetupConfig(defaultOverrides);
|
|
}
|
|
|
|
protected override IWindow CreateWindow(GraphicsSurfaceType preferredSurface) => new AndroidGameWindow(preferredSurface, Options.FriendlyGameName);
|
|
|
|
protected override void DrawFrame()
|
|
{
|
|
if (AndroidGameActivity.Surface.IsSurfaceReady)
|
|
base.DrawFrame();
|
|
}
|
|
|
|
public override bool CanExit => false;
|
|
|
|
public override bool CanSuspendToBackground => true;
|
|
|
|
public override bool OnScreenKeyboardOverlapsGameWindow => true;
|
|
|
|
public override Storage GetStorage(string path) => new AndroidStorage(path, this);
|
|
|
|
public override IEnumerable<string> UserStoragePaths
|
|
// not null as internal "external storage" is always available.
|
|
=> Application.Context.GetExternalFilesDir(string.Empty).AsNonNull().ToString().Yield();
|
|
|
|
public override ISystemFileSelector CreateSystemFileSelector(string[] allowedExtensions)
|
|
=> new AndroidFileSelector(activity, allowedExtensions);
|
|
|
|
/// <inheritdoc />
|
|
/// <remarks>
|
|
/// <para>
|
|
/// On Android, this method and <see cref="PresentFileExternally"/> have the same behaviour.
|
|
/// </para>
|
|
/// <para>
|
|
/// Because of Android's stringent restrictions on accessing files on the device,
|
|
/// this method will pretty much only work on files that the game directly controls or creates in its dedicated storages,
|
|
/// and even then, only if they are explicitly allowlisted as accessible via a <c>FileProvider</c>.
|
|
/// See provided example below for how to set up sharing.
|
|
/// </para>
|
|
/// <para>
|
|
/// If this method is prompted to open a file that is not in this game's storages, or the file path is not whitelisted, this method will return <see langword="false"/>
|
|
/// and log the appropriate error.
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <para>
|
|
/// In <c>AndroidManifest.xml</c>:
|
|
/// <code>
|
|
/// <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.MyGame" android:installLocation="auto">
|
|
/// <application android:label="osu!framework test">
|
|
/// <provider android:name="androidx.core.content.FileProvider"
|
|
/// android:authorities="com.example.MyGame.fileprovider"
|
|
/// android:grantUriPermissions="true"
|
|
/// android:exported="false">
|
|
/// <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
|
|
/// android:resource="@xml/filepaths" />
|
|
/// </provider>
|
|
/// </application>
|
|
/// </manifest>
|
|
/// </code>
|
|
/// Note that the authority of the file provider MUST be the package name suffixed with <c>.fileprovider</c>.
|
|
/// </para>
|
|
/// <para>
|
|
/// In <c>Resources/xml/filepaths.xml</c>:
|
|
/// <code>
|
|
/// <?xml version="1.0" encoding="utf-8"?>
|
|
/// <paths>
|
|
/// <external-files-path path="logs" name="logs" />
|
|
/// </paths>
|
|
/// </code>
|
|
/// Paths in <c><external-files-path></c> tags are relative to the only path in <see cref="UserStoragePaths"/>.
|
|
/// </para>
|
|
/// </example>
|
|
public override bool OpenFileExternally(string filename)
|
|
{
|
|
var context = activity.ApplicationContext!;
|
|
Java.IO.File file = new Java.IO.File(filename);
|
|
Uri? contentUri;
|
|
|
|
try
|
|
{
|
|
contentUri = FileProvider.GetUriForFile(context, $"{context.PackageName}.fileprovider", file);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Log($"Failed to create content URI for file: {filename}.\nError: {ex}");
|
|
return false;
|
|
}
|
|
|
|
if (contentUri == null)
|
|
return false;
|
|
|
|
// https://developer.android.com/training/sharing/send#send-binary-content
|
|
// https://developer.android.com/reference/android/content/Intent#ACTION_SEND
|
|
var shareIntent = new Intent(Intent.ActionSend);
|
|
shareIntent.PutExtra(Intent.ExtraStream, contentUri);
|
|
shareIntent.SetType(activity.ContentResolver?.GetType(contentUri));
|
|
activity.StartActivity(Intent.CreateChooser(shareIntent, "Share"));
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
/// <remarks>
|
|
/// On Android, this method and <see cref="OpenFileExternally"/> have the same behaviour.
|
|
/// See remarks of that method for instructions how to set up file sharing on Android.
|
|
/// </remarks>
|
|
public override bool PresentFileExternally(string filename) => OpenFileExternally(filename);
|
|
|
|
public override void OpenUrlExternally(string url)
|
|
{
|
|
if (!url.CheckIsValidUrl())
|
|
throw new ArgumentException("The provided URL must be one of either http://, https:// or mailto: protocols.", nameof(url));
|
|
|
|
try
|
|
{
|
|
using (var intent = new Intent(Intent.ActionView, Uri.Parse(url)))
|
|
{
|
|
// Recommended way to open URLs on Android 11+
|
|
// https://developer.android.com/training/package-visibility/use-cases#open-urls-browser-or-other-app
|
|
activity.StartActivity(intent);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Error(ex, "Unable to open external link.");
|
|
}
|
|
}
|
|
|
|
public override IResourceStore<TextureUpload> CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore)
|
|
=> new AndroidTextureLoaderStore(underlyingStore);
|
|
|
|
public override VideoDecoder CreateVideoDecoder(Stream stream)
|
|
=> new AndroidVideoDecoder(Renderer, stream);
|
|
|
|
public override bool SuspendToBackground()
|
|
{
|
|
return activity.MoveTaskToBack(true);
|
|
}
|
|
}
|
|
}
|