diff --git a/SpaccDotWeb.Android/app/build.gradle b/SpaccDotWeb.Android/app/build.gradle
index 93de6ca..9d57da6 100644
--- a/SpaccDotWeb.Android/app/build.gradle
+++ b/SpaccDotWeb.Android/app/build.gradle
@@ -20,6 +20,7 @@ android {
}
release {
minifyEnabled true
+ shrinkResources true
signingConfig signingConfigs.debug
}
}
diff --git a/SpaccDotWeb.Android/app/src/main/AndroidManifest.xml b/SpaccDotWeb.Android/app/src/main/AndroidManifest.xml
index 87ab13b..b822565 100644
--- a/SpaccDotWeb.Android/app/src/main/AndroidManifest.xml
+++ b/SpaccDotWeb.Android/app/src/main/AndroidManifest.xml
@@ -7,18 +7,23 @@
-
-
+
+
+
https://gitlab.com/SpaccInc/SpaccDotWeb
+ + +Repository: https://gitlab.com/SpaccInc/SpaccDotWeb.
++ + +
++ + + +
+Upload:
+Download: Download
+ + \ No newline at end of file diff --git a/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainActivity.java b/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainActivity.java index 02c11d5..a763913 100644 --- a/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainActivity.java +++ b/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainActivity.java @@ -1,28 +1,18 @@ package com.example.spaccwebviewapplication; -import android.app.Activity; import android.os.Bundle; import org.eu.spacc.spaccdotweb.android.*; -public class MainActivity extends Activity { - private SpaccWebView webView; +public class MainActivity extends SpaccWebViewActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - webView = findViewById(R.id.webview); - webView.loadAppIndex(); - } + DataMoveHelper.run(this, R.string.exit, R.string.move_app_data, R.string.move_app_data_info); - @Override - public void onBackPressed() { - if (webView.canGoBack()) { - webView.goBack(); - } else { - super.onBackPressed(); - } + this.webView = findViewById(R.id.webview); + this.webView.loadAppIndex(); } } diff --git a/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainApplication.java b/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainApplication.java new file mode 100644 index 0000000..de00044 --- /dev/null +++ b/SpaccDotWeb.Android/app/src/main/java/com/example/spaccwebviewapplication/MainApplication.java @@ -0,0 +1,8 @@ +package com.example.spaccwebviewapplication; + +import org.eu.spacc.spaccdotweb.android.SpaccWebViewApplication; + +public class MainApplication extends SpaccWebViewApplication { + // This proxy class can be left empty, + // it exists just to provide an unique android:name for the manifest +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/ApiUtils.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/ApiUtils.java index 3a092fd..2419569 100644 --- a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/ApiUtils.java +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/ApiUtils.java @@ -9,4 +9,4 @@ public class ApiUtils { action.run(); } } -} \ No newline at end of file +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Config.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Config.java index 1a57706..6471e27 100644 --- a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Config.java +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Config.java @@ -8,4 +8,4 @@ public class Config { public static final AppIndex APP_INDEX = AppIndex.LOCAL; public static final String LOCAL_INDEX = "index.html"; public static final String REMOTE_INDEX = "https://example.com"; -} \ No newline at end of file +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Constants.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Constants.java index be39f19..f4336d4 100644 --- a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Constants.java +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/Constants.java @@ -1,5 +1,6 @@ package org.eu.spacc.spaccdotweb.android; public class Constants { - public static enum AppIndex { LOCAL, REMOTE } -} \ No newline at end of file + public enum AppIndex { LOCAL, REMOTE } + public enum DataLocation { INTERNAL, EXTERNAL } +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/DataMoveHelper.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/DataMoveHelper.java new file mode 100644 index 0000000..c565bc1 --- /dev/null +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/DataMoveHelper.java @@ -0,0 +1,58 @@ +package org.eu.spacc.spaccdotweb.android; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Build; +import java.io.IOException; + +public class DataMoveHelper { + + public static void run(Context context, int labelExit, int dialogTitle, int dialogMessage) { + Activity activity = (Activity)context; + SharedPrefHelper sharedPrefHelper = new SharedPrefHelper(context); + Constants.DataLocation dataLocationReal = (StorageUtils.isInstalledOnExternalStorage(context) ? Constants.DataLocation.EXTERNAL : Constants.DataLocation.INTERNAL); + Integer dataLocationSaved = sharedPrefHelper.getInt("data_location"); + if (dataLocationSaved == null) { + sharedPrefHelper.setInt("data_location", dataLocationReal.ordinal()); + } else if (!dataLocationSaved.equals(dataLocationReal.ordinal())) { + new AlertDialog.Builder(context) + .setTitle(dialogTitle) + .setMessage(dialogMessage) + .setCancelable(false) + .setNegativeButton(labelExit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + ((Activity)context).finish(); + } + }) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + // TODO: Check that the storage locations are all present to copy, and implement an error dialog + try { + FileUtils.moveDirectory(StorageUtils.dataDirFromEnum(context, Constants.DataLocation.values()[dataLocationSaved]), StorageUtils.dataDirFromEnum(context, dataLocationReal), false); + } catch (IOException e) { + throw new RuntimeException(e); + } + sharedPrefHelper.setInt("data_location", dataLocationReal.ordinal()); + restartActivity(context); + } + }) + .show(); + } + } + + private static void restartActivity(Context context) { + Activity activity = (Activity)context; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + activity.recreate(); + } else { + Intent intent = activity.getIntent(); + activity.finish(); + context.startActivity(intent); + } + } +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/FileUtils.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/FileUtils.java new file mode 100644 index 0000000..f90b4c6 --- /dev/null +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/FileUtils.java @@ -0,0 +1,63 @@ +package org.eu.spacc.spaccdotweb.android; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class FileUtils { + + public static void moveDirectory(File sourceLocation, File targetLocation, boolean deleteRoot) throws IOException { + copyDirectory(sourceLocation, targetLocation); + recursiveDelete(sourceLocation, deleteRoot); + } + + /* https://subversivebytes.wordpress.com/2012/11/05/java-copy-directory-recursive-delete/ */ + + public static void copyDirectory(File sourceLocation, File targetLocation) throws IOException { + if (sourceLocation.isDirectory()) { + if (!targetLocation.exists()) { + targetLocation.mkdir(); + } + String[] children = sourceLocation.list(); + for (int i = 0; i < children.length; i++) { + copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i])); + } + } + else { + InputStream in = new FileInputStream(sourceLocation); + OutputStream out = new FileOutputStream(targetLocation); + try { + byte[] buf = new byte[1024]; + int len; + while((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } finally { + in.close(); + out.close(); + } + } + } + + public void recursiveDelete(File rootDir) { + recursiveDelete(rootDir, true); + } + + public static void recursiveDelete(File rootDir, boolean deleteRoot) { + File[] childDirs = rootDir.listFiles(); + for (File childDir : childDirs) { + if (childDir.isFile()) { + childDir.delete(); + } else { + recursiveDelete(childDir, deleteRoot); + childDir.delete(); + } + } + if (deleteRoot) { + rootDir.delete(); + } + } +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/SharedPrefHelper.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/SharedPrefHelper.java new file mode 100644 index 0000000..0f912fa --- /dev/null +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/SharedPrefHelper.java @@ -0,0 +1,27 @@ +package org.eu.spacc.spaccdotweb.android; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; + +public class SharedPrefHelper { + private final SharedPreferences sharedPref; + + public SharedPrefHelper(Context context) { + this.sharedPref = context.getSharedPreferences("SpaccWebView", Context.MODE_PRIVATE); + } + + public Integer getInt(String name) { + Integer value = (Integer)sharedPref.getInt(name, -1); + return (value != -1 ? value : null); + } + + public void setInt(String name, int value) { + SharedPreferences.Editor editor = sharedPref.edit().putInt(name, value); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + editor.apply(); + } else { + editor.commit(); + } + } +} diff --git a/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/SpaccWebChromeClient.java b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/SpaccWebChromeClient.java new file mode 100644 index 0000000..34a949b --- /dev/null +++ b/SpaccDotWeb.Android/app/src/main/java/org/eu/spacc/spaccdotweb/android/SpaccWebChromeClient.java @@ -0,0 +1,33 @@ +package org.eu.spacc.spaccdotweb.android; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebView; + +public class SpaccWebChromeClient extends WebChromeClient { + private static final int INPUT_FILE_REQUEST_CODE = 1; + + private final Context context; + + public SpaccWebChromeClient(Context context) { + super(); + this.context = context; + } + + // TODO: This only opens a file selector but then doesn't do anything + // TODO: Android < 5 support + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback