1
1
package com .samsung .microbit .ui .activity ;
2
2
3
3
import android .Manifest ;
4
+ import android .annotation .SuppressLint ;
4
5
import android .app .Activity ;
5
6
import android .app .AlertDialog ;
6
7
import android .bluetooth .BluetoothAdapter ;
21
22
import android .provider .DocumentsContract ;
22
23
import android .util .Log ;
23
24
import android .view .Menu ;
25
+ import android .view .MenuItem ;
24
26
import android .view .View ;
25
27
import android .view .Window ;
28
+ import android .webkit .ValueCallback ;
26
29
import android .webkit .WebChromeClient ;
27
30
import android .widget .LinearLayout ;
28
31
import android .widget .ListView ;
31
34
32
35
import androidx .annotation .NonNull ;
33
36
import androidx .annotation .RequiresApi ;
37
+ import androidx .appcompat .widget .PopupMenu ;
34
38
import androidx .core .app .ActivityCompat ;
35
39
import androidx .core .content .ContextCompat ;
36
40
import androidx .core .content .PermissionChecker ;
62
66
import com .samsung .microbit .utils .Utils ;
63
67
import com .samsung .microbit .utils .irmHexUtils ;
64
68
69
+ import java .io .BufferedReader ;
65
70
import java .io .ByteArrayOutputStream ;
66
71
import java .io .File ;
67
72
import java .io .FileInputStream ;
70
75
import java .io .FilenameFilter ;
71
76
import java .io .IOException ;
72
77
import java .io .InputStream ;
78
+ import java .io .InputStreamReader ;
73
79
import java .io .OutputStream ;
74
80
import java .net .URLDecoder ;
75
81
import java .nio .ByteBuffer ;
99
105
import static com .samsung .microbit .ui .activity .PopUpActivity .INTENT_GIFF_ANIMATION_CODE ;
100
106
import static com .samsung .microbit .utils .FileUtils .getFileSize ;
101
107
108
+ import org .microbit .android .partialflashing .HexUtils ;
109
+
102
110
// import com.samsung.microbit.core.GoogleAnalyticsManager;
103
111
104
112
/**
@@ -768,7 +776,7 @@ private void setConnectedDeviceText() {
768
776
|| mActivityState == FlashActivityState .FLASH_STATE_WAIT_DEVICE_REBOOT
769
777
|| mActivityState == FlashActivityState .FLASH_STATE_INIT_DEVICE
770
778
|| mActivityState == FlashActivityState .FLASH_STATE_PROGRESS
771
- ) {
779
+ ) {
772
780
// connectedIndicatorIcon.setImageResource(R.drawable.device_status_connected);
773
781
connectedIndicatorText .setText (getString (R .string .connected_to ));
774
782
@@ -903,8 +911,19 @@ private void setupListAdapter() {
903
911
904
912
@ Override
905
913
protected void onActivityResult (int requestCode , int resultCode , Intent data ) {
914
+ switch ( requestCode ) {
915
+ case REQUEST_CODE_IMPORT :
916
+ onActivityResultScriptsImport ( requestCode , resultCode , data );
917
+ super .onActivityResult (requestCode , resultCode , data );
918
+ return ;
919
+ case REQUEST_CODE_EXPORT :
920
+ onActivityResultScriptsExport ( requestCode , resultCode , data );
921
+ super .onActivityResult (requestCode , resultCode , data );
922
+ return ;
923
+ }
924
+
906
925
boolean flash = mActivityState == FlashActivityState .STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST ||
907
- mActivityState == FlashActivityState .STATE_ENABLE_BT_EXTERNAL_FLASH_REQUEST ;
926
+ mActivityState == FlashActivityState .STATE_ENABLE_BT_EXTERNAL_FLASH_REQUEST ;
908
927
boolean connect = mActivityState == FlashActivityState .STATE_ENABLE_BT_FOR_CONNECT ;
909
928
910
929
if (requestCode == RequestCodes .REQUEST_ENABLE_BT ) {
@@ -982,6 +1001,7 @@ private void proceedAfterBlePermissionGrantedAndBleEnabled() {
982
1001
/**
983
1002
* Starts activity to enable bluetooth.
984
1003
*/
1004
+ @ SuppressLint ("MissingPermission" )
985
1005
private void enableBluetooth () {
986
1006
Intent enableBtIntent = new Intent (BluetoothAdapter .ACTION_REQUEST_ENABLE );
987
1007
startActivityForResult (enableBtIntent , RequestCodes .REQUEST_ENABLE_BT );
@@ -991,7 +1011,7 @@ private boolean havePermission(String permission) {
991
1011
return ContextCompat .checkSelfPermission ( this , permission ) == PermissionChecker .PERMISSION_GRANTED ;
992
1012
}
993
1013
994
- private boolean havePermissionsFlashing () {
1014
+ private boolean havePermissionsFlashing () {
995
1015
boolean yes = true ;
996
1016
if ( Build .VERSION .SDK_INT >= Build .VERSION_CODES .S ) {
997
1017
if ( !havePermission ( Manifest .permission .BLUETOOTH_CONNECT ))
@@ -1103,15 +1123,8 @@ public void sendProject(final Project project) {
1103
1123
@ Override
1104
1124
public void onClick (final View v ) {
1105
1125
switch (v .getId ()) {
1106
- case R .id .createProject : {
1107
- Intent launchMakeCodeIntent = new Intent (this , MakeCodeWebView .class );
1108
- startActivity (launchMakeCodeIntent );
1109
- /*
1110
- Intent intent = new Intent(Intent.ACTION_VIEW);
1111
- intent.setData(Uri.parse(getString(R.string.my_scripts_url)));
1112
- startActivity(intent);
1113
- */
1114
- }
1126
+ case R .id .createProject :
1127
+ scriptsPopup ();
1115
1128
break ;
1116
1129
1117
1130
case R .id .backBtn :
@@ -1781,7 +1794,6 @@ private String[] universalHexToDFU(String inputPath, int hardwareType) {
1781
1794
// return new String[]{"-1", "-1"};
1782
1795
// }
1783
1796
1784
-
1785
1797
private void pfRegister () {
1786
1798
if (pfRegistered ) {
1787
1799
return ;
@@ -1922,7 +1934,7 @@ public void onClick(View v) {
1922
1934
},//override click listener for ok button
1923
1935
null );//pass null to use default listener
1924
1936
} else if (intent .getAction ().equals (PartialFlashingService .BROADCAST_PF_ATTEMPT_DFU )) {
1925
- Log .v (TAG , "Use Nordic DFU" );
1937
+ Log .v (TAG , "Use Nordic DFU" );
1926
1938
startDFUFlash ();
1927
1939
} else if (intent .getAction ().equals (PartialFlashingService .BROADCAST_PF_FAILED )) {
1928
1940
@@ -2294,4 +2306,246 @@ public boolean onCreateOptionsMenu(Menu menu) {
2294
2306
return true ;
2295
2307
}
2296
2308
2309
+
2310
+
2311
+ private void scriptsPopup () {
2312
+ PopupMenu popupMenu = new PopupMenu ( this , findViewById (R .id .createProject ));
2313
+ int itemID = Menu .FIRST ;
2314
+ popupMenu .getMenu ().add ( 0 , itemID , 0 , "Create Code" );
2315
+ itemID ++;
2316
+ popupMenu .getMenu ().add ( 0 , itemID , 1 , "Import" );
2317
+ itemID ++;
2318
+ popupMenu .getMenu ().add ( 0 , itemID , 2 , "Export" );
2319
+ itemID ++;
2320
+
2321
+ popupMenu .setOnMenuItemClickListener ( new PopupMenu .OnMenuItemClickListener () {
2322
+ @ Override
2323
+ public boolean onMenuItemClick (MenuItem item ) {
2324
+ switch ( item .getItemId () - Menu .FIRST ) {
2325
+ case 0 : scriptsCreateCode (); break ;
2326
+ case 1 : scriptsImport (); break ;
2327
+ case 2 : scriptsExport (); break ;
2328
+ }
2329
+ return false ;
2330
+ }
2331
+ });
2332
+ popupMenu .show ();
2333
+ }
2334
+
2335
+ private void scriptsCreateCode () {
2336
+ Intent launchMakeCodeIntent = new Intent (this , MakeCodeWebView .class );
2337
+ startActivity (launchMakeCodeIntent );
2338
+ }
2339
+
2340
+ private static final int REQUEST_CODE_EXPORT = 1 ;
2341
+ private static final int REQUEST_CODE_IMPORT = 2 ;
2342
+
2343
+
2344
+ private void scriptsImport () {
2345
+ String messageTitle = "Import" ;
2346
+ Intent intent = new Intent (Intent .ACTION_OPEN_DOCUMENT );
2347
+ intent .addCategory (Intent .CATEGORY_OPENABLE );
2348
+ intent .setFlags (Intent .FLAG_GRANT_READ_URI_PERMISSION );
2349
+ intent .setType ("application/octet-stream" );
2350
+ startActivityForResult ( Intent .createChooser (intent , messageTitle ), REQUEST_CODE_IMPORT );
2351
+ }
2352
+
2353
+ protected void onActivityResultScriptsImport (int requestCode , int resultCode , Intent data ) {
2354
+ if ( resultCode != RESULT_OK ) {
2355
+ return ;
2356
+ }
2357
+ Toast .makeText (this , "Importing project" , Toast .LENGTH_LONG ).show ();
2358
+ new Thread ( new Runnable () {
2359
+ @ Override
2360
+ public void run () {
2361
+ int error = scriptsImportOpen ( data .getData ());
2362
+ runOnUiThread (new Runnable () {
2363
+ @ Override
2364
+ public void run () {
2365
+ switch (error ) {
2366
+ case 0 :
2367
+ if ( minimumPermissionsGranted ) {
2368
+ updateProjectsListSortOrder (true );
2369
+ }
2370
+ break ;
2371
+ case 1 :
2372
+ Toast .makeText ( ProjectActivity .this ,
2373
+ "Project import failed" , Toast .LENGTH_LONG ).show ();
2374
+ break ;
2375
+ case 2 :
2376
+ Toast .makeText ( ProjectActivity .this ,
2377
+ "A project with the same name already exists" ,
2378
+ Toast .LENGTH_LONG ).show ();
2379
+ break ;
2380
+ }
2381
+ }
2382
+ });
2383
+ }
2384
+ }).start ();
2385
+ }
2386
+
2387
+ private int scriptsImportOpen ( Uri uri ) {
2388
+ String fileName = "microbit-import.hex" ;
2389
+
2390
+ String scheme = uri .getScheme ();
2391
+ String mime = getContentResolver ().getType (uri );
2392
+ if ( scheme .equals ("file" )) {
2393
+ String encodedPath = uri .getEncodedPath ();
2394
+ String path = URLDecoder .decode (encodedPath );
2395
+ fileName = fileNameForFlashing ( path );
2396
+ } else if ( scheme .equals ("content" )) {
2397
+ Cursor cursor = null ;
2398
+ cursor = getContentResolver ().query (uri , null , null , null , null );
2399
+ if (cursor != null && cursor .moveToFirst ()) {
2400
+ int index = cursor .getColumnIndex (DocumentsContract .Document .COLUMN_DISPLAY_NAME );
2401
+ if (index >= 0 ) {
2402
+ fileName = cursor .getString (index );
2403
+ }
2404
+ }
2405
+ }
2406
+
2407
+ String projectPath = ProjectsHelper .projectPath (this , fileName );
2408
+ if ( FileUtils .fileExists ( projectPath )) {
2409
+ return 2 ;
2410
+ }
2411
+
2412
+ boolean ok = true ;
2413
+ FileInputStream fis = null ;
2414
+ BufferedReader reader = null ;
2415
+ try {
2416
+ IOUtils .copy (getContentResolver ().openInputStream (uri ), new FileOutputStream (projectPath ));
2417
+
2418
+ // Check file is hex
2419
+ int lineCount = 0 ;
2420
+ fis = new FileInputStream ( projectPath );
2421
+ reader = new BufferedReader ( new InputStreamReader ( fis ));
2422
+ while ( true ) {
2423
+ String line = reader .readLine ();
2424
+ if ( line == null ) {
2425
+ break ;
2426
+ }
2427
+ lineCount ++;
2428
+ if ( !line .isEmpty () && !line .startsWith (":" )) {
2429
+ ok = false ;
2430
+ break ;
2431
+ }
2432
+ if ( lineCount == 0 ) {
2433
+ ok = false ;
2434
+ }
2435
+ }
2436
+ } catch (Exception e ) {
2437
+ logi ( e .toString ());
2438
+ ok = false ;
2439
+ }
2440
+
2441
+ if ( reader != null ) {
2442
+ try {
2443
+ reader .close ();
2444
+ } catch (IOException e ) {
2445
+ }
2446
+ }
2447
+
2448
+ if ( fis != null ) {
2449
+ try {
2450
+ fis .close ();
2451
+ } catch (IOException e ) {
2452
+ }
2453
+ }
2454
+
2455
+ if ( !ok ) {
2456
+ FileUtils .deleteFile ( projectPath );
2457
+ }
2458
+ return ok ? 0 : 1 ;
2459
+ }
2460
+
2461
+ private void scriptsExport () {
2462
+ String messageTitle = "Export" ;
2463
+ String name = "microbit-projects" ;
2464
+ String mimetype = "application/zip" ;
2465
+ Intent intent = new Intent (Intent .ACTION_CREATE_DOCUMENT );
2466
+ intent .addCategory (Intent .CATEGORY_OPENABLE );
2467
+ intent .setFlags (Intent .FLAG_GRANT_WRITE_URI_PERMISSION );
2468
+ intent .setType ( mimetype );
2469
+ intent .putExtra (Intent .EXTRA_TITLE , name );
2470
+ startActivityForResult ( Intent .createChooser (intent , messageTitle ), REQUEST_CODE_EXPORT );
2471
+ }
2472
+
2473
+ protected void onActivityResultScriptsExport (int requestCode , int resultCode , Intent data ) {
2474
+ if ( resultCode != RESULT_OK ) {
2475
+ return ;
2476
+ }
2477
+ Toast .makeText (this , "Saving Projects ZIP file" , Toast .LENGTH_LONG ).show ();
2478
+ new Thread ( new Runnable () {
2479
+ @ Override
2480
+ public void run () {
2481
+ int error = scriptsExportSave ( data .getData ());
2482
+ runOnUiThread (new Runnable () {
2483
+ @ Override
2484
+ public void run () {
2485
+ switch ( error ) {
2486
+ case 0 :
2487
+ Toast .makeText ( ProjectActivity .this ,
2488
+ "Saved Projects ZIP file" , Toast .LENGTH_LONG ).show ();
2489
+ break ;
2490
+ case 1 :
2491
+ Toast .makeText ( ProjectActivity .this ,
2492
+ "Projects export failed" , Toast .LENGTH_LONG ).show ();
2493
+ break ;
2494
+ case 2 :
2495
+ Toast .makeText ( ProjectActivity .this ,
2496
+ "A file with the same name already exists" ,
2497
+ Toast .LENGTH_LONG ).show ();
2498
+ break ;
2499
+ }
2500
+ }
2501
+ });
2502
+ }
2503
+ }).start ();
2504
+ }
2505
+
2506
+ private int scriptsExportSave ( Uri uri ) {
2507
+ boolean ok = true ;
2508
+
2509
+ byte [] buffer = new byte [1024 ];
2510
+ File [] projects = ProjectsHelper .projectFilesListHEX ( this );
2511
+
2512
+ OutputStream os = null ;
2513
+ ZipOutputStream zipOutputStream = null ;
2514
+ FileInputStream fileInputStream = null ;
2515
+ try {
2516
+ os = getContentResolver ().openOutputStream ( uri );
2517
+ zipOutputStream = new ZipOutputStream (os );
2518
+ for ( int i = 0 ; i < projects .length ; i ++) {
2519
+ fileInputStream = new FileInputStream ( projects [i ]);
2520
+ zipOutputStream .putNextEntry (new ZipEntry ( projects [i ].getName ()));
2521
+
2522
+ int length ;
2523
+ while ((length = fileInputStream .read (buffer )) > 0 ) {
2524
+ zipOutputStream .write (buffer , 0 , length );
2525
+ }
2526
+
2527
+ zipOutputStream .closeEntry ();
2528
+ fileInputStream .close ();
2529
+ fileInputStream = null ;
2530
+ }
2531
+ zipOutputStream .close ();
2532
+ os .close ();
2533
+ } catch (Exception e ) {
2534
+ ok = false ;
2535
+ try {
2536
+ if ( fileInputStream != null ) {
2537
+ fileInputStream .close ();
2538
+ }
2539
+ if ( zipOutputStream != null ) {
2540
+ zipOutputStream .close ();
2541
+ }
2542
+ if ( os != null ) {
2543
+ os .close ();
2544
+ }
2545
+ } catch (Exception e2 ) {
2546
+ e .printStackTrace ();
2547
+ }
2548
+ }
2549
+ return ok ? 0 : 1 ;
2550
+ }
2297
2551
}
0 commit comments