Skip to content

Commit fed7b5d

Browse files
committed
ANDROID: updated storage handling
1 parent 49cf29e commit fed7b5d

File tree

3 files changed

+100
-87
lines changed

3 files changed

+100
-87
lines changed

src/platform/android/app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@
6767
<!-- Permissions -->
6868
<uses-permission android:name="android.permission.INTERNET" />
6969
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
70-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
71-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
7270
<uses-permission android:name="android.permission.ACCESS_COURSE_LOCATION" />
7371
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
7472
</manifest>

src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java

Lines changed: 74 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import android.view.inputmethod.InputMethodManager;
3939
import android.widget.Toast;
4040

41-
import androidx.annotation.NonNull;
4241
import androidx.core.app.ActivityCompat;
4342
import androidx.core.content.ContextCompat;
4443
import androidx.core.content.FileProvider;
@@ -95,10 +94,10 @@ public class MainActivity extends NativeActivity {
9594
private static final int BASE_FONT_SIZE = 18;
9695
private static final long LOCATION_INTERVAL = 1000;
9796
private static final float LOCATION_DISTANCE = 1;
98-
private static final int REQUEST_STORAGE_PERMISSION = 1;
9997
private static final int REQUEST_LOCATION_PERMISSION = 2;
10098
private static final String FOLDER_NAME = "SmallBASIC";
10199
private static final int COPY_BUFFER_SIZE = 1024;
100+
private static final String[] SAMPLES = {"welcome.bas"};
102101
private String _startupBas = null;
103102
private boolean _untrusted = false;
104103
private final ExecutorService _audioExecutor = Executors.newSingleThreadExecutor();
@@ -254,6 +253,18 @@ public void run() {
254253
return result;
255254
}
256255

256+
public String getExternalStorage() {
257+
String result = null;
258+
File files = getExternalFilesDir(null);
259+
if (files != null) {
260+
String externalFiles = files.getAbsolutePath();
261+
if (isPublicStorage(externalFiles)) {
262+
result = externalFiles;
263+
}
264+
}
265+
return result;
266+
}
267+
257268
public String getIpAddress() {
258269
String result = "";
259270
try {
@@ -397,16 +408,6 @@ public boolean onPrepareOptionsMenu(Menu menu) {
397408
return super.onPrepareOptionsMenu(menu);
398409
}
399410

400-
@Override
401-
public void onRequestPermissionsResult(int requestCode,
402-
@NonNull String[] permissions,
403-
@NonNull int[] grantResults) {
404-
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
405-
if (requestCode == REQUEST_STORAGE_PERMISSION && grantResults[0] != PackageManager.PERMISSION_DENIED) {
406-
setupStorageEnvironment(true);
407-
}
408-
}
409-
410411
public void optionsBox(final String[] items) {
411412
this._options = items;
412413
runOnUiThread(new Runnable() {
@@ -448,10 +449,10 @@ public void run() {
448449
}).start();
449450
}
450451

451-
public void playTone(int frq, int dur, int vol, boolean bgplay) {
452+
public void playTone(int frq, int dur, int vol, boolean backgroundPlay) {
452453
float volume = (vol / 100f);
453454
final Sound sound = new Sound(frq, dur, volume);
454-
if (bgplay) {
455+
if (backgroundPlay) {
455456
_sounds.add(sound);
456457
_audioExecutor.execute(new Runnable() {
457458
@Override
@@ -641,7 +642,8 @@ protected void onCreate(Bundle savedInstanceState) {
641642
super.onCreate(savedInstanceState);
642643
processIntent();
643644
processSettings();
644-
checkFilePermission();
645+
String homeFolder = setupStorageEnvironment();
646+
installSamples(homeFolder);
645647
}
646648

647649
@Override
@@ -669,21 +671,6 @@ protected void onStop() {
669671
}
670672
}
671673

672-
private void checkFilePermission() {
673-
if (!permitted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
674-
setupStorageEnvironment(false);
675-
Runnable handler = new Runnable() {
676-
@Override
677-
public void run() {
678-
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, REQUEST_STORAGE_PERMISSION);
679-
}
680-
};
681-
new Handler().postDelayed(handler, 250);
682-
} else {
683-
setupStorageEnvironment(true);
684-
}
685-
}
686-
687674
private void checkPermission(final String permission, final int result) {
688675
runOnUiThread(new Runnable() {
689676
@Override
@@ -711,18 +698,6 @@ private void copy(File src, File dst) throws IOException {
711698
copy(new FileInputStream(src), new FileOutputStream(dst));
712699
}
713700

714-
private String execBuffer(final String buffer, final String name, boolean run) throws IOException {
715-
File outputFile = new File(getInternalStorage(), name);
716-
BufferedWriter output = new BufferedWriter(new FileWriter(outputFile));
717-
output.write(buffer);
718-
output.close();
719-
if (run) {
720-
Log.i(TAG, "invoke runFile: " + outputFile.getAbsolutePath());
721-
runFile(outputFile.getAbsolutePath());
722-
}
723-
return outputFile.getAbsolutePath();
724-
}
725-
726701
private void execScheme(final String data) {
727702
try {
728703
String input = data.substring(SCHEME.length());
@@ -742,7 +717,7 @@ private void execScheme(final String data) {
742717
} else {
743718
bas = URLDecoder.decode(input, "utf-8");
744719
}
745-
_startupBas = execBuffer(bas, SCHEME_BAS, false);
720+
_startupBas = saveSchemeData(bas);
746721
_untrusted = true;
747722
} catch (IOException e) {
748723
Log.i(TAG, "saveSchemeData failed: ", e);
@@ -763,7 +738,11 @@ private void execStream(InputStream inputStream) throws IOException {
763738
runFile(outputFile.getAbsolutePath());
764739
}
765740

766-
private String getExternalStorage() {
741+
private String getInternalStorage() {
742+
return getFilesDir().getAbsolutePath();
743+
}
744+
745+
private String getLegacyStorage() {
767746
String result;
768747
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
769748
if (isPublicStorage(path)) {
@@ -773,18 +752,23 @@ private String getExternalStorage() {
773752
} else {
774753
result = path;
775754
}
776-
} else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
777-
// https://commonsware.com/blog/2019/06/07/death-external-storage-end-saga.html
778-
File[] dirs = getExternalMediaDirs();
779-
result = dirs != null && dirs.length > 0 ? dirs[0].getAbsolutePath() : getInternalStorage();
780755
} else {
781-
result = getInternalStorage();
756+
result = null;
782757
}
783758
return result;
784759
}
785760

786-
private String getInternalStorage() {
787-
return getFilesDir().getAbsolutePath();
761+
private String getMediaStorage() {
762+
String result = null;
763+
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
764+
// https://commonsware.com/blog/2019/06/07/death-external-storage-end-saga.html
765+
File[] dirs = getExternalMediaDirs();
766+
String path = dirs != null && dirs.length > 0 ? dirs[0].getAbsolutePath() : null;
767+
if (isPublicStorage(path)) {
768+
result = path;
769+
}
770+
}
771+
return result;
788772
}
789773

790774
private Uri getSharedFile(File file) {
@@ -813,6 +797,20 @@ private String getString(final byte[] bytes) {
813797
}
814798
}
815799

800+
private void installSamples(String toDir) {
801+
File[] toFiles = new File(toDir).listFiles(new BasFileFilter());
802+
if (toFiles == null || toFiles.length == 0) {
803+
// only attempt with a clean destination folder
804+
try {
805+
for (String sample : SAMPLES) {
806+
copy(getAssets().open("samples/" + sample), new FileOutputStream(new File(toDir, sample)));
807+
}
808+
} catch (IOException e) {
809+
Log.d(TAG, "Failed to copy sample: ", e);
810+
}
811+
}
812+
}
813+
816814
private boolean isPublicStorage(String dir) {
817815
boolean result;
818816
if (dir == null || dir.isEmpty()) {
@@ -824,27 +822,6 @@ private boolean isPublicStorage(String dir) {
824822
return result;
825823
}
826824

827-
private void migrateFiles(File fromDir, File toDir) {
828-
FilenameFilter filter = new FilenameFilter() {
829-
@Override
830-
public boolean accept(File dir, String name) {
831-
return name != null && name.endsWith(".bas");
832-
}
833-
};
834-
File[] toFiles = toDir.listFiles(filter);
835-
File[] fromFiles = fromDir.listFiles(filter);
836-
if (fromFiles != null && (toFiles == null || toFiles.length == 0)) {
837-
// only attempt file copy into a clean destination folder
838-
for (File file : fromFiles) {
839-
try {
840-
copy(file, new File(toDir, file.getName()));
841-
} catch (IOException e) {
842-
Log.d(TAG, "failed to copy: ", e);
843-
}
844-
}
845-
}
846-
}
847-
848825
private boolean permitted(String permission) {
849826
return (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED);
850827
}
@@ -921,21 +898,26 @@ private String readLine(InputStream inputReader) throws IOException {
921898
return b == -1 ? null : out.size() == 0 ? "" : out.toString();
922899
}
923900

924-
private void setupStorageEnvironment(boolean external) {
901+
private String saveSchemeData(final String buffer) throws IOException {
902+
File outputFile = new File(getInternalStorage(), SCHEME_BAS);
903+
BufferedWriter output = new BufferedWriter(new FileWriter(outputFile));
904+
output.write(buffer);
905+
output.close();
906+
return outputFile.getAbsolutePath();
907+
}
908+
909+
private String setupStorageEnvironment() {
925910
setenv("INTERNAL_DIR", getInternalStorage());
926-
if (external) {
927-
String externalDir = getExternalStorage();
928-
File files = getExternalFilesDir(null);
929-
if (files != null) {
930-
String externalFiles = files.getAbsolutePath();
931-
if (!externalDir.equals(externalFiles) && isPublicStorage(externalFiles)) {
932-
migrateFiles(new File(externalDir), files);
933-
setenv("LEGACY_DIR", externalDir);
934-
externalDir = externalFiles;
935-
}
936-
}
937-
setenv("EXTERNAL_DIR", externalDir);
911+
setenv("LEGACY_DIR", getMediaStorage());
912+
String legacyStorage = getLegacyStorage();
913+
String externalStorage;
914+
if (isPublicStorage(legacyStorage)) {
915+
externalStorage = legacyStorage;
916+
} else {
917+
externalStorage = getExternalStorage();
938918
}
919+
setenv("EXTERNAL_DIR", externalStorage);
920+
return externalStorage;
939921
}
940922

941923
private static class BasFileFilter implements FilenameFilter {
@@ -963,6 +945,9 @@ protected Response getFile(String path, boolean asset) throws IOException {
963945
result = new Response(getAssets().open(name), length);
964946
} else {
965947
File file = getFile(getExternalStorage(), path);
948+
if (file == null) {
949+
file = getFile(getMediaStorage(), path);
950+
}
966951
if (file == null) {
967952
file = getFile(getInternalStorage(), path);
968953
}
@@ -979,6 +964,7 @@ protected Response getFile(String path, boolean asset) throws IOException {
979964
protected Collection<FileData> getFileData() throws IOException {
980965
Collection<FileData> result = new ArrayList<>();
981966
result.addAll(getFiles(new File(getExternalStorage())));
967+
result.addAll(getFiles(new File(getMediaStorage())));
982968
result.addAll(getFiles(new File(getInternalStorage())));
983969
return result;
984970
}
@@ -1009,6 +995,9 @@ protected void renameFile(String from, String to) throws IOException {
1009995
if (fromFile == null) {
1010996
fromFile = getFile(getExternalStorage(), from);
1011997
}
998+
if (fromFile == null) {
999+
fromFile = getFile(getInternalStorage(), from);
1000+
}
10121001
if (fromFile == null) {
10131002
throw new IOException("Previous file does not exist");
10141003
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<project xmlns="http://maven.apache.org/POM/4.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
6+
<modelVersion>4.0.0</modelVersion>
7+
<groupId>net.sourceforge.smallbasic</groupId>
8+
<artifactId>smallbasic</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
<name>smallbasic</name>
11+
12+
<properties>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
<maven.compiler.source>1.8</maven.compiler.source>
15+
<maven.compiler.target>1.8</maven.compiler.target>
16+
</properties>
17+
18+
<dependencies>
19+
<dependency>
20+
<groupId>junit</groupId>
21+
<artifactId>junit</artifactId>
22+
<version>4.11</version>
23+
<scope>test</scope>
24+
</dependency>
25+
</dependencies>
26+
</project>

0 commit comments

Comments
 (0)