3838import android .view .inputmethod .InputMethodManager ;
3939import android .widget .Toast ;
4040
41- import androidx .annotation .NonNull ;
4241import androidx .core .app .ActivityCompat ;
4342import androidx .core .content .ContextCompat ;
4443import 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 }
0 commit comments