mirror of
https://github.com/love2d/love-android.git
synced 2026-08-12 08:31:04 +02:00
Impelement "Share to LOVE" support.
This allows you to share either .love game to launch as game (for the non-fused APKs and instance of LOVE isn't running) or any file that gets passed as love.filedropped. Caveat: Ensure the intended game is running before sending files to LOVE app. Otherwise, LOVE will attempt to open it as *.love file, which is may not what you want.
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation"
|
||||
android:launchMode="singleTask"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="landscape">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -43,5 +43,19 @@
|
||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".IntentReceiverActivity"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:taskAffinity=""
|
||||
android:excludeFromRecents="true"
|
||||
android:relinquishTaskIdentity="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.OPENABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
+1
-1
Submodule app/src/main/cpp/love updated: 2879074177...7b66e50cfc
@@ -43,7 +43,6 @@ import android.util.Log;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -58,8 +57,8 @@ public class GameActivity extends SDLActivity {
|
||||
protected Vibrator vibrator;
|
||||
protected boolean shortEdgesMode;
|
||||
protected final int[] recordAudioRequestDummy = new int[1];
|
||||
private int delayedFd = -1;
|
||||
private String[] args = new String[0];
|
||||
private Uri delayedUri = null;
|
||||
private String[] args;
|
||||
private boolean isFused;
|
||||
|
||||
private static native void nativeSetDefaultStreamValues(int sampleRate, int framesPerBurst);
|
||||
@@ -95,13 +94,16 @@ public class GameActivity extends SDLActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "started");
|
||||
isFused = hasEmbeddedGame();
|
||||
args = new String[0];
|
||||
|
||||
if (checkCallingOrSelfPermission(Manifest.permission.VIBRATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
}
|
||||
|
||||
Intent intent = getIntent();
|
||||
handleIntent(intent);
|
||||
// Prevent SDL sending filedropped event. Let us do that instead.
|
||||
setIntent(null);
|
||||
handleIntent(intent, true);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
@@ -118,17 +120,17 @@ public class GameActivity extends SDLActivity {
|
||||
shortEdgesMode = false;
|
||||
}
|
||||
|
||||
if (delayedFd != -1) {
|
||||
if (delayedUri != null) {
|
||||
// This delayed fd is only sent if an embedded game is present.
|
||||
sendFileDescriptorAsDroppedFile(delayedFd);
|
||||
delayedFd = -1;
|
||||
sendUriAsDroppedFile(delayedUri);
|
||||
delayedUri = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
handleIntent(intent);
|
||||
handleIntent(intent, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,6 +332,11 @@ public class GameActivity extends SDLActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
public int convertToFileDescriptor(String uri) {
|
||||
return convertToFileDescriptor(Uri.parse(uri));
|
||||
}
|
||||
|
||||
public int getAudioSMP() {
|
||||
int smp = 256;
|
||||
AudioManager a = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
@@ -363,32 +370,28 @@ public class GameActivity extends SDLActivity {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendFileDescriptorAsDroppedFile(int fd) {
|
||||
if (fd != -1) {
|
||||
SDLActivity.onNativeDropFile("love2d://fd/" + fd);
|
||||
}
|
||||
public void sendUriAsDroppedFile(Uri uri) {
|
||||
SDLActivity.onNativeDropFile(uri.toString());
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
private void handleIntent(Intent intent, boolean onCreate) {
|
||||
Uri game = intent.getData();
|
||||
if (game == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSingleton == null) {
|
||||
// Game is not running, consider setting the currentGameInfo here
|
||||
|
||||
if (onCreate) {
|
||||
// Game is not running
|
||||
if (isFused) {
|
||||
// Send it as dropped file later
|
||||
delayedFd = convertToFileDescriptor(game);
|
||||
delayedUri = game;
|
||||
} else {
|
||||
// Process for arguments
|
||||
processOpenGame(game);
|
||||
}
|
||||
} else {
|
||||
// Game is already running. Send it as dropped file.
|
||||
int fd = convertToFileDescriptor(game);
|
||||
sendFileDescriptorAsDroppedFile(fd);
|
||||
sendUriAsDroppedFile(game);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,14 +436,17 @@ public class GameActivity extends SDLActivity {
|
||||
}
|
||||
|
||||
private int convertToFileDescriptor(Uri uri) {
|
||||
int fd = -1;
|
||||
|
||||
try {
|
||||
ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "r");
|
||||
return pfd.dup().detachFd();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Failed attempt to convert " + uri.toString() + " to file descriptor", e);
|
||||
fd = pfd.dup().detachFd();
|
||||
pfd.close();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed attempt to convert " + uri.toString() + " to file descriptor", e);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
private void processOpenGame(Uri game) {
|
||||
@@ -448,9 +454,10 @@ public class GameActivity extends SDLActivity {
|
||||
String path = game.getPath();
|
||||
|
||||
if (scheme.equals("content")) {
|
||||
// The intent may have more information about the filename
|
||||
// Convert the URI to file descriptor.
|
||||
args = new String[] {"/love2d://fd/" + convertToFileDescriptor(game)};
|
||||
} else if (scheme.equals("file")) {
|
||||
// Regular file, pass as-is.
|
||||
args = new String[] {path};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.love2d.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class IntentReceiverActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent mainIntent = getIntent();
|
||||
Intent intent = new Intent(this, GameActivity.class);
|
||||
|
||||
if (mainIntent.getAction().equals(Intent.ACTION_SEND)) {
|
||||
// Convert to simpler intent that our GameActivity can process.
|
||||
Uri uri = mainIntent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
intent.setData(uri);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/Theme.AppCompat.DayNight">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
Reference in New Issue
Block a user