Merge pull request #14813 from hrydgard/scoped-storage-shortcut-fix

Various Android shortcut fixes
This commit is contained in:
Henrik Rydgård
2021-09-09 09:12:49 +02:00
committed by GitHub
7 changed files with 140 additions and 18 deletions
+9 -3
View File
@@ -98,7 +98,7 @@ static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread)
}
void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) {
if (!global_->threads_.empty()) {
if (IsInitialized()) {
Teardown();
}
@@ -118,6 +118,8 @@ void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) {
}
void ThreadManager::EnqueueTask(Task *task, TaskType taskType) {
_assert_msg_(IsInitialized(), "ThreadManager not initialized");
int maxThread;
int threadOffset = 0;
if (taskType == TaskType::CPU_COMPUTE) {
@@ -158,7 +160,7 @@ void ThreadManager::EnqueueTask(Task *task, TaskType taskType) {
}
void ThreadManager::EnqueueTaskOnThread(int threadNum, Task *task, TaskType taskType) {
_assert_(threadNum >= 0 && threadNum < (int)global_->threads_.size());
_assert_msg_(threadNum >= 0 && threadNum < (int)global_->threads_.size(), "Bad threadnum or not initialized");
ThreadContext *thread = global_->threads_[threadNum];
{
std::unique_lock<std::mutex> lock(thread->mutex);
@@ -172,5 +174,9 @@ int ThreadManager::GetNumLooperThreads() const {
}
void ThreadManager::TryCancelTask(uint64_t taskID) {
// Do nothing
// Do nothing for now, just let it finish.
}
bool ThreadManager::IsInitialized() const {
return !global_->threads_.empty();
}
+4 -1
View File
@@ -48,6 +48,8 @@ public:
void EnqueueTaskOnThread(int threadNum, Task *task, TaskType taskType);
void Teardown();
bool IsInitialized() const;
// Currently does nothing. It will always be best-effort - maybe it cancels,
// maybe it doesn't. Note that the id is the id() returned by the task. You need to make that
// something meaningful yourself.
@@ -58,7 +60,8 @@ public:
int GetNumLooperThreads() const;
private:
GlobalThreadContext *global_ = nullptr;
// This is always pointing to a context, initialized in the constructor.
GlobalThreadContext *global_;
int numThreads_ = 0;
int numComputeThreads_ = 0;
+1 -1
View File
@@ -71,7 +71,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
}
if (!fileLoader->Exists()) {
*errorString = "IdentifyFile: File doesn't exist" + fileLoader->GetPath().ToString();
*errorString = "IdentifyFile: File doesn't exist: " + fileLoader->GetPath().ToString();
return IdentifiedFileType::ERROR_IDENTIFYING;
}
+9 -1
View File
@@ -46,6 +46,7 @@
#include "Common/Net/HTTPClient.h"
#include "Common/Net/Resolve.h"
#include "Common/Net/URL.h"
#include "Common/Render/TextureAtlas.h"
#include "Common/Render/Text/draw_text.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
@@ -683,7 +684,14 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
}
}
if (okToLoad) {
boot_filename = Path(std::string(argv[i]));
std::string str = std::string(argv[i]);
// Handle file:/// URIs, since you get those when creating shortcuts on some Android systems.
if (startsWith(str, "file:///")) {
str = UriDecode(str.substr(7));
INFO_LOG(IO, "Decoding '%s' to '%s'", argv[i], str.c_str());
}
boot_filename = Path(str);
skipLogo = true;
}
if (okToLoad && okToCheck) {
+25
View File
@@ -1441,15 +1441,30 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J
return true;
}
// NOTE: This is defunct and not working, due to how the Android storage functions currently require
// a PpssppActivity specifically and we don't have one here.
extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv *env, jclass, jstring jpath) {
bool teardownThreadManager = false;
if (!g_threadManager.IsInitialized()) {
INFO_LOG(SYSTEM, "No thread manager - initializing one");
// Need a thread manager.
teardownThreadManager = true;
g_threadManager.Init(1, 1);
}
Path path = Path(GetJavaString(env, jpath));
INFO_LOG(SYSTEM, "queryGameName(%s)", path.c_str());
std::string result = "";
GameInfoCache *cache = new GameInfoCache();
std::shared_ptr<GameInfo> info = cache->GetInfo(nullptr, path, 0);
// Wait until it's done: this is synchronous, unfortunately.
if (info) {
INFO_LOG(SYSTEM, "GetInfo successful, waiting");
cache->WaitUntilDone(info);
INFO_LOG(SYSTEM, "Done waiting");
if (info->fileType != IdentifiedFileType::UNKNOWN) {
result = info->GetTitle();
@@ -1458,9 +1473,19 @@ extern "C" jstring Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameName(JNIEnv
if (result.length() > strlen("The ") && startsWithNoCase(result, "The ")) {
result = result.substr(strlen("The "));
}
INFO_LOG(SYSTEM, "queryGameName: Got '%s'", result.c_str());
} else {
INFO_LOG(SYSTEM, "queryGameName: Filetype unknown");
}
} else {
INFO_LOG(SYSTEM, "No info from cache");
}
delete cache;
if (teardownThreadManager) {
g_threadManager.Teardown();
}
return env->NewStringUTF(result.c_str());
}
@@ -98,7 +98,7 @@ public class PpssppActivity extends NativeActivity {
// String action = intent.getAction();
Uri data = intent.getData();
if (data != null) {
String path = intent.getData().getPath();
String path = data.toString();
Log.i(TAG, "Found Shortcut Parameter in data: " + path);
super.setShortcutParam("\"" + path.replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
// Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
@@ -5,11 +5,13 @@ import android.app.AlertDialog;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import java.io.File;
import java.nio.charset.StandardCharsets;
/**
* This class will respond to android.intent.action.CREATE_SHORTCUT intent from launcher homescreen.
@@ -18,35 +20,114 @@ import java.io.File;
public class ShortcutActivity extends Activity {
private static final String TAG = "PPSSPP";
private boolean scoped = false;
private static final int RESULT_OPEN_DOCUMENT = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show file selector dialog here.
SimpleFileChooser fileDialog = new SimpleFileChooser(this, Environment.getExternalStorageDirectory(), onFileSelectedListener);
fileDialog.showDialog();
// Show file selector dialog here. If Android version is more than or equal to 11,
// use the native document file browser instead of our SimpleFileChooser.
scoped = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R);
if (scoped) {
try {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
// Possible alternative approach:
// String[] mimeTypes = {"application/octet-stream", "/x-iso9660-image"};
// intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
startActivityForResult(intent, RESULT_OPEN_DOCUMENT);
// intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
Log.i(TAG, "Starting open document activity");
} catch (Exception e) {
Log.e(TAG, e.toString());
}
} else {
SimpleFileChooser fileDialog = new SimpleFileChooser(this, Environment.getExternalStorageDirectory(), onFileSelectedListener);
fileDialog.showDialog();
}
}
// Respond to native file dialog.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_OPEN_DOCUMENT && data != null) {
Uri selectedFile = data.getData();
if (selectedFile != null) {
// Grab permanent permission so we can show it in recents list etc.
if (Build.VERSION.SDK_INT >= 19) {
Log.i(TAG, "Taking URI permission");
getContentResolver().takePersistableUriPermission(selectedFile, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
Log.i(TAG, "Browse file finished:" + selectedFile.toString());
respondToShortcutRequest(selectedFile); // finishes.
return;
}
}
// We're done, no matter how it went.
finish();
}
public static native String queryGameName(String path);
// Create shortcut as response for ACTION_CREATE_SHORTCUT intent.
private void respondToShortcutRequest(String path) {
private void respondToShortcutRequest(Uri uri) {
// This is Intent that will be sent when user execute our shortcut on
// homescreen. Set our app as target Context. Set Main activity as
// target class. Add any parameter as data.
Intent shortcutIntent = new Intent(this, PpssppActivity.class);
Uri uri = Uri.fromFile(new File(path));
Intent shortcutIntent = new Intent(getApplicationContext(), PpssppActivity.class);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Log.i(TAG, "Shortcut URI: " + uri.toString());
shortcutIntent.setData(uri);
String path = uri.toString();
shortcutIntent.putExtra(PpssppActivity.SHORTCUT_EXTRA_KEY, path);
// We can't call C++ functions here that use storage APIs since there's no
// NativeActivity and all the AndroidStorage methods are methods on that.
// Should probably change that. In the meantime, let's just process the URI to make
// up a name.
String name = "PPSSPP Game";
String pathStr = "PPSSPP Game";
if (path.startsWith("content://")) {
String [] segments = path.split("/");
try {
pathStr = java.net.URLDecoder.decode(segments[segments.length - 1], StandardCharsets.UTF_8.name());
} catch (Exception e) {
Log.i(TAG, "Exception getting name: " + e);
}
} else if (path.startsWith("file:///")) {
try {
pathStr = java.net.URLDecoder.decode(path.substring(7), StandardCharsets.UTF_8.name());
} catch (Exception e) {
Log.i(TAG, "Exception getting name: " + e);
}
} else {
pathStr = path;
}
String[] pathSegments = pathStr.split("/");
name = pathSegments[pathSegments.length - 1];
/*
// No longer working for various reasons.
PpssppActivity.CheckABIAndLoadLibrary();
String name = queryGameName(path);
if (name.equals("")) {
Log.i(TAG, "Failed to retrieve game name - ignoring.");
showBadGameMessage();
return;
}
}*/
Log.i(TAG, "Game name: " + name + " : Creating shortcut to " + uri.toString());
// This is Intent that will be returned by this method, as response to
// ACTION_CREATE_SHORTCUT. Wrap shortcut intent inside this intent.
@@ -80,8 +161,6 @@ public class ShortcutActivity extends Activity {
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(-1);
}
// Event when a file is selected on file dialog.
@@ -89,7 +168,8 @@ public class ShortcutActivity extends Activity {
@Override
public void onFileSelected(File file) {
// create shortcut using file path
respondToShortcutRequest(file.getAbsolutePath());
Uri uri = Uri.fromFile(new File(file.getAbsolutePath()));
respondToShortcutRequest(uri);
}
};
}