mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-08 14:56:12 -04:00
WIP on adding proper android content:// provider
This commit is contained in:
parent
ef40f872e0
commit
2582f0a182
@ -11,6 +11,12 @@
|
|||||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="26"/>
|
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="26"/>
|
||||||
|
|
||||||
<application android:icon="@mipmap/ccicon" android:label="ClassiCube">
|
<application android:icon="@mipmap/ccicon" android:label="ClassiCube">
|
||||||
|
<provider
|
||||||
|
android:name="com.classicube.CCFileProvider"
|
||||||
|
android:authorities="com.classicube.android.client.ccfiles"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true" >
|
||||||
|
</provider>
|
||||||
|
|
||||||
<activity android:name="com.classicube.MainActivity" android:label="ClassiCube"
|
<activity android:name="com.classicube.MainActivity" android:label="ClassiCube"
|
||||||
android:configChanges="orientation|screenSize|keyboard|keyboardHidden">
|
android:configChanges="orientation|screenSize|keyboard|keyboardHidden">
|
||||||
|
111
android/app/src/main/java/com/classicube/CCFileProvider.java
Normal file
111
android/app/src/main/java/com/classicube/CCFileProvider.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package com.classicube;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ProviderInfo;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
|
||||||
|
public class CCFileProvider extends ContentProvider
|
||||||
|
{
|
||||||
|
final static String[] DEFAULT_COLUMNS = { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE };
|
||||||
|
File root;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attachInfo(Context context, ProviderInfo info) {
|
||||||
|
super.attachInfo(context, info);
|
||||||
|
root = context.getExternalFilesDir(null); // getGameDataDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||||
|
File file = getFileForUri(uri);
|
||||||
|
// can be null when caller is requesting all supported columns
|
||||||
|
if (projection == null) projection = DEFAULT_COLUMNS;
|
||||||
|
|
||||||
|
ArrayList<String> cols = new ArrayList<String>(2);
|
||||||
|
ArrayList<Object> vals = new ArrayList<Object>(2);
|
||||||
|
|
||||||
|
for (String column : projection) {
|
||||||
|
if (column.equals(OpenableColumns.DISPLAY_NAME)) {
|
||||||
|
cols.add(OpenableColumns.DISPLAY_NAME);
|
||||||
|
vals.add(file.getName());
|
||||||
|
} else if (column.equals(OpenableColumns.SIZE)) {
|
||||||
|
cols.add(OpenableColumns.SIZE);
|
||||||
|
vals.add(file.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/4042434/converting-arrayliststring-to-string-in-java
|
||||||
|
MatrixCursor cursor = new MatrixCursor(cols.toArray(new String[0]), 1);
|
||||||
|
cursor.addRow(vals.toArray());
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType(Uri uri) {
|
||||||
|
String path = uri.getEncodedPath();
|
||||||
|
int sepExt = path.lastIndexOf('.');
|
||||||
|
|
||||||
|
if (sepExt >= 0) {
|
||||||
|
String fileExt = path.substring(sepExt);
|
||||||
|
if (fileExt.equals(".png")) return "image/png";
|
||||||
|
}
|
||||||
|
return "application/octet-stream";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
|
throw new UnsupportedOperationException("Readonly access");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||||
|
throw new UnsupportedOperationException("Readonly access");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||||
|
throw new UnsupportedOperationException("Readonly access");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||||
|
File file = getFileForUri(uri);
|
||||||
|
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Uri getUriForFile(String path) {
|
||||||
|
// See AndroidManifest.xml for authority
|
||||||
|
return new Uri.Builder()
|
||||||
|
.scheme("content")
|
||||||
|
.authority("com.classicube.android.client.ccfiles")
|
||||||
|
.encodedPath(Uri.encode(path, "/"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
File getFileForUri(Uri uri) {
|
||||||
|
String path = uri.getPath();
|
||||||
|
File file = new File(root, path);
|
||||||
|
|
||||||
|
file = file.getAbsoluteFile();
|
||||||
|
// security validation check
|
||||||
|
if (!file.getPath().startsWith(root.getPath())) {
|
||||||
|
throw new SecurityException("Resolved path lies outside app directory:" + path);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,6 @@ import android.database.Cursor;
|
|||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.StrictMode;
|
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.provider.Settings.Secure;
|
import android.provider.Settings.Secure;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
@ -159,19 +158,6 @@ public class MainActivity extends Activity
|
|||||||
runGameAsync();
|
runGameAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HACK_avoidFileUriExposedErrors() {
|
|
||||||
// StrictMode - API level 9
|
|
||||||
// disableDeathOnFileUriExposure - API level 24 ?????
|
|
||||||
try {
|
|
||||||
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
|
|
||||||
m.invoke(null);
|
|
||||||
} catch (NoClassDefFoundError ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
// requestWindowFeature - API level 1
|
// requestWindowFeature - API level 1
|
||||||
@ -193,9 +179,6 @@ public class MainActivity extends Activity
|
|||||||
// renderOverDisplayCutouts();
|
// renderOverDisplayCutouts();
|
||||||
// TODO: semaphore for destroyed and surfaceDestroyed
|
// TODO: semaphore for destroyed and surfaceDestroyed
|
||||||
|
|
||||||
// avoid FileUriExposed exception when taking screenshots on recent Android versions
|
|
||||||
HACK_avoidFileUriExposedErrors();
|
|
||||||
|
|
||||||
if (!gameRunning) startGameAsync();
|
if (!gameRunning) startGameAsync();
|
||||||
// TODO rethink to avoid this
|
// TODO rethink to avoid this
|
||||||
if (gameRunning) updateInstance();
|
if (gameRunning) updateInstance();
|
||||||
@ -811,11 +794,11 @@ public class MainActivity extends Activity
|
|||||||
|
|
||||||
public String shareScreenshot(String path) {
|
public String shareScreenshot(String path) {
|
||||||
try {
|
try {
|
||||||
File file = new File(getGameDataDirectory() + "/screenshots/" + path);
|
Uri uri = CCFileProvider.getUriForFile("screenshots", path);
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
|
|
||||||
intent.setAction(Intent.ACTION_SEND);
|
intent.setAction(Intent.ACTION_SEND);
|
||||||
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
|
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
intent.setType("image/png");
|
intent.setType("image/png");
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
startActivity(Intent.createChooser(intent, "share via"));
|
startActivity(Intent.createChooser(intent, "share via"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user