Skip to content

Commit

Permalink
fx
Browse files Browse the repository at this point in the history
  • Loading branch information
weihuoya committed Jun 1, 2022
1 parent c619e9d commit 6d4270e
Show file tree
Hide file tree
Showing 13 changed files with 371 additions and 39 deletions.
11 changes: 11 additions & 0 deletions src/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_citra"
android:appCategory="game"
android:hasFragileUserData="true"
android:isGame="true"
android:label="Citra">
<meta-data
Expand Down Expand Up @@ -114,6 +115,16 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nnf_provider_paths" />
</provider>
<provider
android:name="org.citra.emu.UserPathProvider"
android:authorities="${applicationId}.userpathprovider"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
</application>

</manifest>
1 change: 1 addition & 0 deletions src/android/app/src/main/assets/3dstdb-zh_CN.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
0004000000071A00 = SD高达 G世纪
0004000000039800 = 机动战士高达 3D战争
00040000001CF400 = 死亡热力破碎机
00040000001C4900 = 死亡热力破碎机
00040000000F5100 = 三国志
0004000000072A00 = 真三国无双 VS
0004000000031E00 = 战国无双 历代记1
Expand Down
20 changes: 13 additions & 7 deletions src/android/app/src/main/assets/config/config-games.ini
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,25 @@
00040000000BAC00 // Mirror of Fate
000400000009E500 // Mirror of Fate
0004000000096600 // Mirror of Fate
000400000007C700 // Mario Tennis Open
000400000007C800 // Mario Tennis Open
0004000000064D00 // Mario Tennis Open
00040000000B9100 // Mario Tennis Open
00040000000DCD00 // Mario Golf: World Tour
00040000000A5300 // Mario Golf: World Tour
00040000000DCE00 // Mario Golf: World Tour
0004000000030500 // Super Street Fighter
0004000000032D00 // Super Street Fighter
0004000000033C00 // Super Street Fighter
000400000F700800 // The Binding of Isaac: Rebirth [USA]
000400000F701700 // The Binding of Isaac: Rebirth [JPN]
000400000F700900 // The Binding of Isaac: Rebirth [EUR]
[cpu_usage_limit2]
000400000007C700 // Mario Tennis Open
000400000007C800 // Mario Tennis Open
0004000000064D00 // Mario Tennis Open
00040000000B9100 // Mario Tennis Open
00040000000D0000 // Luigi's Mansion: Dark Moon
0004000000076400 // Luigi's Mansion: Dark Moon
0004000000055F00 // Luigi's Mansion: Dark Moon
0004000000076500 // Luigi's Mansion: Dark Moon
000400000F700800 // The Binding of Isaac: Rebirth [USA]
000400000F701700 // The Binding of Isaac: Rebirth [JPN]
000400000F700900 // The Binding of Isaac: Rebirth [EUR]
[skip_texture_copy]
0004000000030000 // Kid Icarus: Uprising
Expand Down Expand Up @@ -228,6 +230,7 @@
000400000008C500 // Tomodachi Life
000400000008F900 // The Legend of Zelda: Ocarina of Time 3D
0004000000033400 // The Legend of Zelda: Ocarina of Time 3D
00040000001C4900 // The Dead Heat Breakers
[game_region_usa]
000400000F70CC00 // Fire Emblem Warriors [USA]
Expand All @@ -248,9 +251,12 @@
0004001000022700 // Mii Maker
000400000008C400 // Tomodachi Life
0004000000033600 // The Legend of Zelda: Ocarina of Time 3D
00040000001CF400 // The Dead Heat Breakers
[game_region_chn]
[game_region_twn]
00040000000B9100 // Mario Tennis Open
[use_fmv_hack]
00040000000BAC00 // Mirror of Fate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ public static void addNetPlayMessage(int type, String message) {
public static native int GetAppRegion(String path);
public static native boolean IsAppExecutable(String path);
public static native boolean IsAppVisible(String path);
public static native String GetBuildDate();
public static native String GetDeviceIinfo(Surface surface);

/**
* emulation
Expand Down Expand Up @@ -360,7 +362,7 @@ public static void addNetPlayMessage(int type, String message) {
* emulation
*/
public static native boolean IsRunning();
public static native void SurfaceChanged(Surface surf);
public static native void SurfaceChanged(Surface surface);
public static native void SurfaceDestroyed();
public static native void WindowChanged();
public static native void DoFrame();
Expand Down
227 changes: 227 additions & 0 deletions src/android/app/src/main/java/org/citra/emu/UserPathProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package org.citra.emu;

import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.webkit.MimeTypeMap;

import androidx.annotation.Nullable;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Collections;
import java.util.LinkedList;

public final class UserPathProvider extends DocumentsProvider {

private final String[] DEFAULT_ROOT_PROJECTION = new String[] {
DocumentsContract.Root.COLUMN_ROOT_ID,
DocumentsContract.Root.COLUMN_MIME_TYPES,
DocumentsContract.Root.COLUMN_FLAGS,
DocumentsContract.Root.COLUMN_ICON,
DocumentsContract.Root.COLUMN_TITLE,
DocumentsContract.Root.COLUMN_SUMMARY,
DocumentsContract.Root.COLUMN_DOCUMENT_ID,
DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
};

private final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
DocumentsContract.Document.COLUMN_MIME_TYPE,
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_LAST_MODIFIED,
DocumentsContract.Document.COLUMN_FLAGS,
DocumentsContract.Document.COLUMN_SIZE
};

private String ROOT_ID;
private File BASE_DIR;

private String getRelativePath(File file) {
if (file == BASE_DIR) {
return "";
}
return file.getAbsolutePath().substring(BASE_DIR.getAbsolutePath().length() + 1);
}

/**
* Get the document id given a file (The reverse of @{link #getDocumentId}).
*/
private File getFile(String documentId) throws FileNotFoundException {
if (documentId.startsWith(ROOT_ID)) {
File file = new File(BASE_DIR, documentId.substring(ROOT_ID.length() + 1));
if (!file.exists()) {
throw new FileNotFoundException("document not found");
}
return file;
} else {
throw new FileNotFoundException("document is not in any known root");
}
}

/**
* Get the file given a document id (the reverse of {@link #getFile}).
*/
private String getDocumentId(File file) {
String path = getRelativePath(file);
return ROOT_ID + "/" + path;
}

@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
String title = getContext().getString(R.string.app_name);
int flags = DocumentsContract.Root.FLAG_SUPPORTS_CREATE;
flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH;
flags |= DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD;

MatrixCursor cursor = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
MatrixCursor.RowBuilder row = cursor.newRow();
row.add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID);
row.add(DocumentsContract.Root.COLUMN_FLAGS, flags);
row.add(DocumentsContract.Root.COLUMN_TITLE, title);
row.add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, getDocumentId(BASE_DIR));
row.add(DocumentsContract.Root.COLUMN_MIME_TYPES, "*/*");
row.add(DocumentsContract.Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
row.add(DocumentsContract.Root.COLUMN_ICON, R.mipmap.ic_citra);
return cursor;
}

@Override
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
MatrixCursor cursor = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
includeFile(cursor, documentId, null);
return cursor;
}

@Override
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException {
MatrixCursor cursor = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
File parent = getFile(parentDocumentId);
for (File file : parent.listFiles()) {
includeFile(cursor, null, file);
}
return cursor;
}

@Override
public ParcelFileDescriptor openDocument(String documentId, String mode, @Nullable CancellationSignal signal) throws FileNotFoundException {
File file = getFile(documentId);
int accessMode = ParcelFileDescriptor.parseMode(mode);
return ParcelFileDescriptor.open(file, accessMode);
}

@Override
public void deleteDocument(String documentId) throws FileNotFoundException {
File file = getFile(documentId);
if (!file.delete()) {
throw new FileNotFoundException("Failed to delete document with id " + documentId);
}
}

@Override
public String getDocumentType(String documentId) throws FileNotFoundException {
File file = getFile(documentId);
return getMimeType(file);
}

@Override
public Cursor querySearchDocuments(String rootId, String query, String[] projection) throws FileNotFoundException {
MatrixCursor cursor = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
File parent = getFile(rootId);

// This example implementation searches file names for the query and doesn't rank search
// results, so we can stop as soon as we find a sufficient number of matches. Other
// implementations might rank results and use other data about files, rather than the file
// name, to produce a match.
LinkedList<File> pending = new LinkedList<>();
pending.add(parent);

int MAX_SEARCH_RESULTS = 50;
while (!pending.isEmpty() && cursor.getCount() < MAX_SEARCH_RESULTS) {
final File file = pending.removeFirst();
if (file.isDirectory()) {
Collections.addAll(pending, file.listFiles());
} else {
if (file.getName().toLowerCase().contains(query)) {
includeFile(cursor, null, file);
}
}
}

return cursor;
}

@Override
public boolean onCreate() {
ROOT_ID = "root";
BASE_DIR = getContext().getExternalFilesDir(null);
return true;
}

/**
* Add a representation of a file to a cursor.
*
* @param cursor the cursor to modify
* @param documentId the document ID representing the desired file (may be null if given file)
* @param file the File object representing the desired file (may be null if given docID)
*/
private void includeFile(MatrixCursor cursor, String documentId, File file) throws FileNotFoundException {
if (documentId == null) {
documentId = getDocumentId(file);
} else if (file == null) {
file = getFile(documentId);
}

String mimeType = getMimeType(file);

int flags = 0;
if (file.isDirectory()) {
if (file.canWrite()) {
flags = DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
}
} else if (file.canWrite()) {
flags = DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
flags = flags | DocumentsContract.Document.FLAG_SUPPORTS_DELETE;
flags = flags | DocumentsContract.Document.FLAG_SUPPORTS_REMOVE;
flags = flags | DocumentsContract.Document.FLAG_SUPPORTS_MOVE;
flags = flags | DocumentsContract.Document.FLAG_SUPPORTS_COPY;
flags = flags | DocumentsContract.Document.FLAG_SUPPORTS_RENAME;
if (mimeType.startsWith("image/")) {
flags |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
}
}

MatrixCursor.RowBuilder row = cursor.newRow();
row.add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, documentId);
row.add(DocumentsContract.Document.COLUMN_SIZE, file.length());
row.add(DocumentsContract.Document.COLUMN_MIME_TYPE, mimeType);
row.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, file.lastModified());
row.add(DocumentsContract.Document.COLUMN_FLAGS, flags);
row.add(DocumentsContract.Root.COLUMN_ICON, R.mipmap.ic_citra);

if (file == BASE_DIR) {
String title = getContext().getString(R.string.app_name);
row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, title);
} else {
row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, file.getName());
}
}

private static String getMimeType(File file) {
if (file.isDirectory()) {
return DocumentsContract.Document.MIME_TYPE_DIR;
} else {
final String name = file.getName();
final int lastDot = name.lastIndexOf('.');
if (lastDot >= 0) {
final String extension = name.substring(lastDot + 1).toLowerCase();
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mime != null) return mime;
}
return "application/octet-stream";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ private List<String> getFileList(String path, String ext) {
File file = new File(path);
File[] files = file.listFiles();
if (files != null) {
for (int i = 0; i < files.length; ++i) {
String name = files[i].getName();
for (File f : files) {
String name = f.getName();
int extensionIndex = name.indexOf(ext);
if (extensionIndex > 0) {
values.add(name.substring(0, extensionIndex));
Expand Down

0 comments on commit 6d4270e

Please sign in to comment.