Skip to content

Commit 649081f

Browse files
authored
Merge pull request #38 from martinwork/from300
From300
2 parents 5437277 + c4f5e05 commit 649081f

16 files changed

+1131
-464
lines changed

app/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ android {
2525

2626
dependencies {
2727
testImplementation 'junit:junit:4.12'
28-
implementation 'androidx.appcompat:appcompat:1.1.0'
29-
implementation 'com.google.android.material:material:1.0.0'
28+
implementation 'androidx.appcompat:appcompat:1.6.1'
29+
implementation 'com.google.android.material:material:1.11.0'
3030
implementation 'androidx.cardview:cardview:1.0.0'
31-
implementation 'androidx.recyclerview:recyclerview:1.0.0'
31+
implementation 'androidx.recyclerview:recyclerview:1.3.2'
3232
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.19'
3333
implementation 'no.nordicsemi.android:dfu:2.4.1'
3434
implementation project(':pfLibrary')
35-
implementation 'com.google.android.gms:play-services-analytics:9.2.0'
35+
implementation 'com.google.android.gms:play-services-analytics:18.0.4'
3636
implementation 'com.google.code.gson:gson:2.8.2'
37-
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
37+
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
3838
}

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
limitations under the License.
1515
-->
1616
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
17-
android:versionCode="51"
18-
android:versionName="3.0.1">
17+
android:versionCode="52"
18+
android:versionName="3.0.2">
1919

2020
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2121
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

app/src/main/java/com/samsung/microbit/ui/activity/MakeCodeWebView.java

Lines changed: 205 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import android.net.Uri;
77
import android.os.Bundle;
88
import android.os.Environment;
9+
import android.os.Handler;
10+
import android.os.Looper;
911
import android.util.Base64;
1012
import android.util.Log;
1113
import android.view.View;
@@ -16,9 +18,11 @@
1618
import android.webkit.WebSettings;
1719
import android.webkit.WebView;
1820
import android.webkit.WebViewClient;
21+
import android.widget.Toast;
1922

2023
import com.samsung.microbit.BuildConfig;
2124
import com.samsung.microbit.R;
25+
import com.samsung.microbit.utils.FileUtils;
2226
import com.samsung.microbit.utils.ProjectsHelper;
2327

2428
import java.io.File;
@@ -40,10 +44,11 @@ public class MakeCodeWebView extends Activity implements View.OnClickListener {
4044
public static String makecodeUrl = "https://makecode.microbit.org/?androidapp=" + BuildConfig.VERSION_CODE;
4145
public static Activity activityHandle = null;
4246

43-
Uri hexToFlash;
47+
boolean projectDownload = false;
4448

4549
private static final int REQUEST_CODE_SAVEDATA = 1;
4650
private static final int REQUEST_CODE_CHOOSE_FILE = 2;
51+
private static final int REQUEST_CODE_FLASH = 3;
4752
private byte[] dataToSave = null;
4853
private ValueCallback<Uri[]> onShowFileChooser_filePathCallback;
4954

@@ -81,15 +86,9 @@ protected void onCreate(Bundle savedInstanceState) {
8186
webSettings.setBuiltInZoomControls(true);
8287
webSettings.setDisplayZoomControls(false);
8388
webSettings.setDomStorageEnabled(true);
84-
webView.setWebContentsDebuggingEnabled(true);
89+
WebView.setWebContentsDebuggingEnabled(false);
8590

8691
webView.addJavascriptInterface(new JavaScriptInterface(this), "AndroidFunction");
87-
webView.evaluateJavascript("javascript:(function f() { document.getElementsByClassName(\"brand\")[0].addEventListener(\"click\", function(e) { AndroidFunction.returnToHome(); e.preventDefault(); return false; }) })()", new ValueCallback<String>() {
88-
@Override
89-
public void onReceiveValue(String s) {
90-
Log.d(TAG, s);
91-
}
92-
});
9392

9493
webView.setWebViewClient(new WebViewClient() {
9594
@Override
@@ -104,6 +103,13 @@ public void onLoadResource(WebView view, String url) {
104103
super.onLoadResource(view, url);
105104
Log.v(TAG, "onLoadResource(" + url + ");");
106105
}
106+
107+
@Override
108+
public void onPageFinished (WebView view, String url) {
109+
super.onPageFinished(view, url);
110+
Log.v(TAG, "onPageFinished(" + url + ");");
111+
onPageFinishedJS( view, url);
112+
}
107113
}); //setWebViewClient
108114

109115
webView.setWebChromeClient(new WebChromeClient() {
@@ -194,40 +200,49 @@ public void onReceiveValue(String s) {
194200
else if ( !hexName.isEmpty()) {
195201
hexToWrite = getProjectFile(hexName);
196202

197-
/*
198-
// Append n to file until it doesn't exist
199-
int i = 0;
200-
201-
while (hexToWrite.exists()) {
202-
hexName = hexName.replaceAll("-?\\d*\\.","-" + i + ".");
203-
hexToWrite = getProjectFile( hexName);
204-
i++;
203+
// // Replace existing file rather than creating *-n.hex
204+
// // Append n to file until it doesn't exist
205+
// int i = 0;
206+
//
207+
// while (hexToWrite.exists()) {
208+
// hexName = hexName.replaceAll("-?\\d*\\.","-" + i + ".");
209+
// hexToWrite = getProjectFile( hexName);
210+
// i++;
211+
// }
212+
213+
if ( !FileUtils.writeBytesToFile( hexToWrite, decode)) {
214+
ProjectsHelper.importToProjectsToast(
215+
ProjectsHelper.enumImportResult.WriteFailed, MakeCodeWebView.this);
216+
return;
205217
}
206-
*/
207-
// Replace existing file rather than creating *-n.hex
208-
if (hexToWrite.exists()) {
209-
hexToWrite.delete();
210-
}
211-
212-
// Create file
213-
hexToWrite.createNewFile();
214-
outputStream = new FileOutputStream(hexToWrite);
215-
outputStream.write(decode);
216-
outputStream.flush();
217218

218-
// Get file path
219-
hexToFlash = Uri.fromFile(hexToWrite);
219+
boolean download = projectDownload;
220+
projectDownload = false;
220221

221-
openProjectActivity();
222+
if ( download) {
223+
openProjectActivity( hexToWrite);
224+
} else {
225+
Toast.makeText( MakeCodeWebView.this,
226+
"Saved to FLASH page", Toast.LENGTH_LONG).show();
227+
}
222228
}
223-
} catch (IOException e) {
229+
} catch ( Exception e) {
224230
e.printStackTrace();
225231
}
226232
}
227233
}); // setDownloadListener
228234

229235
//Check parameters Before load
230236
Intent intent = getIntent();
237+
238+
boolean importExtra = intent.getBooleanExtra("import", false);
239+
if ( importExtra) {
240+
importInitialise();
241+
} else {
242+
importHex = null;
243+
importName = null;
244+
}
245+
231246
webView.loadUrl(makecodeUrl);
232247
} // onCreate
233248

@@ -244,27 +259,22 @@ private void saveData( String name, String mimetype, byte[] data) {
244259
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
245260
super.onActivityResult(requestCode, resultCode, data);
246261

247-
if ( requestCode == REQUEST_CODE_SAVEDATA) {
262+
if ( requestCode == REQUEST_CODE_FLASH) {
263+
if ( resultCode != RESULT_OK) {
264+
return;
265+
}
266+
} else if ( requestCode == REQUEST_CODE_SAVEDATA) {
248267
if ( resultCode != RESULT_OK) {
249268
dataToSave = null;
250269
return;
251270
}
252-
OutputStream os = null;
253-
try {
254-
os = getContentResolver().openOutputStream( data.getData());
255-
if ( dataToSave != null && dataToSave.length > 0) {
256-
os.write(dataToSave, 0, dataToSave.length);
271+
if ( dataToSave != null && dataToSave.length > 0) {
272+
Uri uri = data.getData();
273+
if ( !FileUtils.writeBytesToUri( uri, dataToSave, this)) {
274+
Toast.makeText(this, "Could not save file", Toast.LENGTH_LONG).show();
257275
}
258-
} catch (IOException e) {
259-
e.printStackTrace();
260-
} finally {
261-
try {
262-
dataToSave = null;
263-
if ( os != null) {
264-
os.close();
265-
}
266-
} catch (IOException e) { }
267276
}
277+
dataToSave = null;
268278
} else if (requestCode == REQUEST_CODE_CHOOSE_FILE) {
269279
if ( resultCode != RESULT_OK) {
270280
onShowFileChooser_filePathCallback.onReceiveValue( null);
@@ -295,27 +305,169 @@ public void onClick(final View v) {
295305
}
296306
}
297307

298-
void openProjectActivity() {
308+
public final static String ACTION_FLASH = "com.samsung.microbit.ACTION_FLASH";
309+
310+
void openProjectActivity( File hexToWrite) {
299311
Intent i = new Intent(this, ProjectActivity.class);
300-
i.setData(hexToFlash);
301-
startActivity(i);
312+
i.setAction( ACTION_FLASH);
313+
i.putExtra("path", hexToWrite.getAbsolutePath());
314+
startActivityForResult( i, REQUEST_CODE_FLASH);
315+
}
316+
317+
public static String importHex = null;
318+
public static String importName = null;
319+
private boolean importPosting = false;
320+
Handler importHandler = null;
321+
322+
private void importInitialise() {
323+
if ( importHex != null) {
324+
importHex = importHex.replaceAll("\r\n", "\\\\n");
325+
importHex = importHex.replaceAll("\r", "\\\\n");
326+
importHex = importHex.replaceAll("\n", "\\\\n");
327+
328+
//TODO - does MakeCode signal when ready?
329+
Looper looper = Looper.getMainLooper();
330+
importHandler = new Handler(looper);
331+
importHandler.postDelayed(importCallback, 2000);
332+
}
333+
}
334+
private final Runnable importCallback = new Runnable() {
335+
@Override
336+
public void run() {
337+
if ( importHex != null) {
338+
importPostMessage();
339+
importHandler.postDelayed( importCallback, 1000);
340+
} else {
341+
importHandler.removeCallbacks( importCallback);
342+
importHandler = null;
343+
}
344+
}
345+
};
346+
347+
public void importPostMessage() {
348+
Log.d(TAG, "importPostMessage");
349+
350+
if ( importHex == null) {
351+
return;
352+
}
353+
if ( importPosting) {
354+
return;
355+
}
356+
if ( webView == null) {
357+
return;
358+
}
359+
if ( importName == null || importName.isEmpty()) {
360+
importName = "import.hex";
361+
}
362+
363+
importPosting = true;
364+
365+
StringBuilder sb = new StringBuilder();
366+
String nl = "\n";
367+
sb.append( "javascript:(");
368+
sb.append(nl).append("function f() {");
369+
sb.append(nl).append( "var ret = 'OK'");
370+
sb.append(nl).append( "try {");
371+
sb.append(nl).append( "var loading = document.getElementById('loading')");
372+
sb.append(nl).append( "if ( loading && loading.parentElement) {");
373+
sb.append(nl).append( "ret = 'loading'");
374+
sb.append(nl).append( "} else {");
375+
sb.append(nl).append( "var name = '").append(importName).append("'");
376+
sb.append(nl).append( "var hex = '").append(importHex).append("'");
377+
sb.append(nl).append( "var msg = {");
378+
sb.append(nl).append( "type: 'importfile',");
379+
sb.append(nl).append( "filename: name,");
380+
sb.append(nl).append( "parts: [ hex ]");
381+
sb.append(nl).append( "}");
382+
sb.append(nl).append( "window.postMessage( msg, '*')");
383+
sb.append(nl).append( "}");
384+
sb.append(nl).append( "} catch( err) {");
385+
sb.append(nl).append( "ret = err.message");
386+
sb.append(nl).append( "}");
387+
sb.append(nl).append( "return ret");
388+
sb.append(nl).append("}");
389+
sb.append(nl).append(")()");
390+
391+
webView.evaluateJavascript( sb.toString(), new ValueCallback<String>() {
392+
@Override
393+
public void onReceiveValue(String s) {
394+
Log.i(TAG, "importPostMessage: " + s);
395+
String loading = "\"loading\"";
396+
String ok = "\"OK\"";
397+
if ( s.equals( ok)) {
398+
importHex = null;
399+
} else if ( !s.equals( loading)) {
400+
}
401+
}
402+
});
403+
importPosting = false;
302404
}
303-
}
405+
406+
public void onPageFinishedJS( WebView view, String url) {
407+
Log.v(TAG, "addListeners(" + url + ");");
408+
409+
StringBuilder sb = new StringBuilder();
410+
String nl = "\n";
411+
sb.append( "javascript:(");
412+
sb.append(nl).append("function f() {");
413+
sb.append(nl).append( "var ret = 'OK'");
414+
sb.append(nl).append( "try {");
415+
sb.append(nl).append( "var brands = document.getElementsByClassName(\"brand\")");
416+
sb.append(nl).append( "for (let i = 0; brands != null && i < brands.length; i++) {");
417+
sb.append(nl).append( "brands[i].addEventListener(\"click\",");
418+
sb.append(nl).append( "function(e) {");
419+
sb.append(nl).append( "AndroidFunction.clickBrand();");
420+
sb.append(nl).append( "e.preventDefault();");
421+
sb.append(nl).append( "return false;");
422+
sb.append(nl).append( "})");
423+
sb.append(nl).append( "}");
424+
sb.append(nl).append( "var downs = document.getElementsByClassName(\"download-button\")");
425+
sb.append(nl).append( "for (let i = 0; downs != null && i < downs.length; i++) {");
426+
sb.append(nl).append( "downs[i].addEventListener(\"click\",");
427+
sb.append(nl).append( "function(e) {");
428+
sb.append(nl).append( "AndroidFunction.clickDownload();");
429+
sb.append(nl).append( "e.preventDefault();");
430+
sb.append(nl).append( "return false;");
431+
sb.append(nl).append( "})");
432+
sb.append(nl).append( "}");
433+
sb.append(nl).append( "} catch( err) {");
434+
sb.append(nl).append( "ret = err.message");
435+
sb.append(nl).append( "}");
436+
sb.append(nl).append( "return ret");
437+
sb.append(nl).append("}");
438+
sb.append(nl).append(")()");
439+
440+
webView.evaluateJavascript( sb.toString(), new ValueCallback<String>() {
441+
@Override
442+
public void onReceiveValue(String s) {
443+
Log.d(TAG, s);
444+
}
445+
});
446+
}}
304447

305448
/* Javascript Interface */
306449
class JavaScriptInterface {
307-
Context mContext;
450+
MakeCodeWebView mContext;
308451

309-
JavaScriptInterface(Context c) {
452+
JavaScriptInterface( MakeCodeWebView c) {
310453
mContext = c;
311454
}
312455

313456
@JavascriptInterface
314-
public void returnToHome() {
457+
public void clickBrand() {
315458
try {
316459
MakeCodeWebView.activityHandle.finish();
317460
} catch(Exception e) {
318461
Log.v(TAG, e.toString());
319462
}
320463
}
464+
465+
@JavascriptInterface
466+
public void clickDownload() {
467+
try {
468+
mContext.projectDownload = true;
469+
} catch(Exception e) {
470+
Log.v(TAG, e.toString());
471+
}
472+
}
321473
}

0 commit comments

Comments
 (0)