forked from amazingfate/loongoffice
android: Turn 3 "internal" docs into raw resources
Make 'example.odt', 'license.txt' and 'notice.txt' (which can be opened via the "About" dialog) resources of the app by copying them to a new directory 'res_generated' instead of into assets, and include 'res_generated' into resources, then use an 'android.resource://' URI instead of a 'file:///assets/' one in AboutDialogFragment. The latter does not work with when passed as a parameter to 'ContentResolver.openInputStream'. Adapt/Simplify 'LibreOfficeMainActivity#copyFileToTemp' to make loading those docs using the 'android.resource://' URI work and use the existing 'copyStream' method for copying from the input to the output stream. This is in preparation for upcoming commit with Change-Id I7731ef81a4242fa0ce3b3fd8ced1683a6a6bee8c, "android: Always create a temporary local copy of the doc". Change-Id: I7731ef81a4242fa0ce3b3fd8ced1683a6a6bee8c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113881 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
This commit is contained in:
1
android/.gitignore
vendored
1
android/.gitignore
vendored
@ -6,6 +6,7 @@
|
||||
/source/build/
|
||||
/source/captures/
|
||||
/source/jni/Application.mk
|
||||
/source/res_generated
|
||||
/jniLibs/
|
||||
/source/liboSettings.gradle
|
||||
/source/local.properties
|
||||
|
||||
@ -42,7 +42,7 @@ android {
|
||||
sourceSets {
|
||||
main.manifest.srcFile 'AndroidManifest.xml'
|
||||
main.assets.srcDirs = ['assets']
|
||||
main.res.srcDirs = ['res']
|
||||
main.res.srcDirs = ['res', 'res_generated']
|
||||
main.java.srcDirs = ['../Bootstrap/src', 'src/java']
|
||||
main.jniLibs.srcDirs = ["${liboJniLibsdir}"]
|
||||
main.jni.srcDirs = [] // don't attempt to build native-lib via gradle
|
||||
@ -144,14 +144,6 @@ task copyUnpackAssets(type: Copy) {
|
||||
task copyAssets(type: Copy) {
|
||||
description "copies assets that can be accessed within the installed apk"
|
||||
into 'assets'
|
||||
from("${liboInstdir}") {
|
||||
includes = ["LICENSE", "NOTICE"]
|
||||
rename "LICENSE", "license.txt"
|
||||
rename "NOTICE", "notice.txt"
|
||||
}
|
||||
from("${liboExampleDocument}") {
|
||||
rename ".*", "example.odt"
|
||||
}
|
||||
|
||||
// include icons
|
||||
into ('share') {
|
||||
@ -193,6 +185,19 @@ task copyAssets(type: Copy) {
|
||||
}
|
||||
}
|
||||
|
||||
task copyAppResources(type: Copy) {
|
||||
description "copies documents to make them available as app resources"
|
||||
into 'res_generated/raw'
|
||||
from("${liboInstdir}") {
|
||||
includes = ["LICENSE", "NOTICE"]
|
||||
rename "LICENSE", "license.txt"
|
||||
rename "NOTICE", "notice.txt"
|
||||
}
|
||||
from("${liboExampleDocument}") {
|
||||
rename ".*", "example.odt"
|
||||
}
|
||||
}
|
||||
|
||||
task createFullConfig(type: Copy) {
|
||||
// grab dir to clear whole hierarchy on clean target
|
||||
outputs.dir "assets_fullUI"
|
||||
@ -290,7 +295,8 @@ task createRCfiles {
|
||||
preBuild.dependsOn 'createRCfiles',
|
||||
'createStrippedConfigMain',
|
||||
'createStrippedConfigRegistry',
|
||||
'createFullConfig'
|
||||
'createFullConfig',
|
||||
'copyAppResources'
|
||||
|
||||
clean.dependsOn 'cleanCopyAssets',
|
||||
'cleanCreateStrippedConfig',
|
||||
|
||||
@ -30,9 +30,6 @@ import java.io.File;
|
||||
|
||||
public class AboutDialogFragment extends DialogFragment {
|
||||
|
||||
private static final String DEFAULT_DOC_PATH = "/assets/example.odt";
|
||||
|
||||
|
||||
@NonNull @Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
|
||||
@ -81,21 +78,21 @@ public class AboutDialogFragment extends DialogFragment {
|
||||
.setNegativeButton(R.string.about_license, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
loadFromAbout("/assets/license.txt");
|
||||
loadFromAbout(R.raw.license);
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.setPositiveButton(R.string.about_notice, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
loadFromAbout("/assets/notice.txt");
|
||||
loadFromAbout(R.raw.notice);
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.setNeutralButton(R.string.about_moreinfo, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
loadFromAbout(DEFAULT_DOC_PATH);
|
||||
loadFromAbout(R.raw.example);
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
@ -103,8 +100,8 @@ public class AboutDialogFragment extends DialogFragment {
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void loadFromAbout(String input) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.fromFile(new File(input)));
|
||||
private void loadFromAbout(int resourceId) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("android.resource://" + BuildConfig.APPLICATION_ID + "/" + resourceId));
|
||||
String packageName = getActivity().getApplicationContext().getPackageName();
|
||||
ComponentName componentName = new ComponentName(packageName, LibreOfficeMainActivity.class.getName());
|
||||
i.setComponent(componentName);
|
||||
|
||||
@ -175,7 +175,8 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
|
||||
|
||||
mDocumentUri = getIntent().getData();
|
||||
if (mDocumentUri != null) {
|
||||
if (mDocumentUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
|
||||
if (mDocumentUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
|
||||
|| mDocumentUri.getScheme().equals(ContentResolver.SCHEME_ANDROID_RESOURCE)) {
|
||||
final boolean isReadOnlyDoc;
|
||||
if (getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY) != null) {
|
||||
// New document type string is not null, meaning we want to open a new document
|
||||
@ -296,53 +297,37 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
|
||||
|
||||
try {
|
||||
mTempFile = File.createTempFile("LibreOffice", suffix, this.getCacheDir());
|
||||
final FileChannel outputChannel = new FileOutputStream(mTempFile).getChannel();
|
||||
try {
|
||||
// need to run copy operation in a separate thread, since network access is not
|
||||
// allowed from main thread, but that may happen here when underlying
|
||||
// DocumentsProvider (like the NextCloud one) does that
|
||||
class CopyThread extends Thread {
|
||||
/** Whether copy operation was successful. */
|
||||
private boolean result = false;
|
||||
final FileOutputStream outputStream = new FileOutputStream(mTempFile);
|
||||
// need to run copy operation in a separate thread, since network access is not
|
||||
// allowed from main thread, but that may happen here when underlying
|
||||
// DocumentsProvider (like the NextCloud one) does that
|
||||
class CopyThread extends Thread {
|
||||
/** Whether copy operation was successful. */
|
||||
private boolean result = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
result = false;
|
||||
try {
|
||||
final AssetFileDescriptor assetFD = contentResolver.openAssetFileDescriptor(mDocumentUri, "r");
|
||||
if (assetFD == null) {
|
||||
Log.e(LOGTAG, "couldn't create assetfiledescriptor from " + mDocumentUri);
|
||||
return;
|
||||
}
|
||||
FileChannel inputChannel = assetFD.createInputStream().getChannel();
|
||||
long bytesTransferred = 0;
|
||||
// might not copy all at once, so make sure everything gets copied...
|
||||
while (bytesTransferred < inputChannel.size()) {
|
||||
bytesTransferred += outputChannel.transferFrom(inputChannel, bytesTransferred, inputChannel.size());
|
||||
}
|
||||
Log.e(LOGTAG, "Success copying " + bytesTransferred + " bytes");
|
||||
inputChannel.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
result = true;
|
||||
@Override
|
||||
public void run() {
|
||||
result = false;
|
||||
try {
|
||||
InputStream inputStream = contentResolver.openInputStream(mDocumentUri);
|
||||
result = copyStream(inputStream, outputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
};
|
||||
CopyThread copyThread = new CopyThread();
|
||||
copyThread.start();
|
||||
try {
|
||||
// wait for copy operation to finish
|
||||
// NOTE: might be useful to add some indicator in UI for long copy operations involving network...
|
||||
copyThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return copyThread.result;
|
||||
} finally {
|
||||
outputChannel.close();
|
||||
};
|
||||
CopyThread copyThread = new CopyThread();
|
||||
copyThread.start();
|
||||
try {
|
||||
// wait for copy operation to finish
|
||||
// NOTE: might be useful to add some indicator in UI for long copy operations involving network...
|
||||
copyThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return copyThread.result;
|
||||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
|
||||
Reference in New Issue
Block a user