diff --git a/.gitignore b/.gitignore
index 39fb081..5561991 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,10 @@
*.iml
.gradle
+.idea
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
-.externalNativeBuild
+.externalNativeBuild
\ No newline at end of file
diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
deleted file mode 100644
index e3206c4..0000000
--- a/.idea/assetWizardSettings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
deleted file mode 100644
index 8bc5559..0000000
Binary files a/.idea/caches/build_file_checksums.ser and /dev/null differ
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 30aa626..0000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 96cc43e..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index e7bedf3..0000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 019957e..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 635999d..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 2da5b66..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 148e79f..4a5447f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,19 +1,22 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+}
android {
- compileSdkVersion 27
+ compileSdkVersion 34
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "org.phenoapps.verify"
minSdkVersion 16
- targetSdkVersion 27
+ targetSdkVersion 34
versionCode 2
versionName "1.1"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
multiDexEnabled = true
vectorDrawables.useSupportLibrary = true
}
+ namespace "org.phenoapps.verify"
buildTypes {
release {
shrinkResources false
@@ -41,17 +44,17 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
- androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
- implementation 'com.android.support:appcompat-v7:27.1.1'
- implementation 'com.android.support:design:27.1.1'
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
- implementation 'com.android.support:support-v4:27.1.1'
- implementation 'com.android.support:support-vector-drawable:27.1.1'
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.10.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'com.github.apl-devs:appintro:v4.2.0'
- testImplementation 'junit:junit:4.12'
+ testImplementation 'junit:junit:4.13.2'
implementation files('libs/poi-3.12-android-a.jar')
implementation files('libs/poi-ooxml-schemas-3.12-20150511-a.jar')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e6fcf4b..b290ec8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,9 +2,9 @@
-
+
+ android:windowSoftInputMode="adjustPan"
+ android:exported="true">
-
+
+ android:name="org.phenoapps.verify.ScanActivity"
+ android:exported="true"/>
-
-
+
-
diff --git a/app/src/main/java/org/phenoapps/verify/CompareActivity.kt b/app/src/main/java/org/phenoapps/verify/CompareActivity.kt
index 775d565..1a066d8 100644
--- a/app/src/main/java/org/phenoapps/verify/CompareActivity.kt
+++ b/app/src/main/java/org/phenoapps/verify/CompareActivity.kt
@@ -2,8 +2,8 @@ package org.phenoapps.verify
import android.app.Activity
import android.os.Bundle
-import android.support.v7.app.AlertDialog
-import android.support.v7.app.AppCompatActivity
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
import android.text.Editable
import android.text.TextWatcher
import android.util.LayoutDirection
diff --git a/app/src/main/java/org/phenoapps/verify/IntroActivity.java b/app/src/main/java/org/phenoapps/verify/IntroActivity.java
index 0622a82..e2be2a5 100644
--- a/app/src/main/java/org/phenoapps/verify/IntroActivity.java
+++ b/app/src/main/java/org/phenoapps/verify/IntroActivity.java
@@ -2,8 +2,8 @@
import android.graphics.Color;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
import com.github.paolorotolo.appintro.AppIntro2;
import com.github.paolorotolo.appintro.AppIntroFragment;
diff --git a/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java b/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java
index 189da69..249f417 100644
--- a/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java
+++ b/app/src/main/java/org/phenoapps/verify/LoaderDBActivity.java
@@ -1,24 +1,16 @@
package org.phenoapps.verify;
-import android.content.ContentUris;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
-import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
-import android.provider.DocumentsContract;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
@@ -43,8 +35,7 @@
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Iterator;
-
-import org.phenoapps.verify.R;
+import java.util.Objects;
public class LoaderDBActivity extends AppCompatActivity {
@@ -53,7 +44,6 @@ public class LoaderDBActivity extends AppCompatActivity {
private Uri mFileUri;
private String mDelimiter;
private String mFileExtension;
- private String mFilePath;
private String mFileName;
private Workbook mCurrentWorkbook;
@@ -105,7 +95,12 @@ protected void onCreate(Bundle savedInstanceState) {
mFileUri = getIntent().getData();
- int lastSlash = mFileUri.getPath().lastIndexOf('/');
+ if (mFileUri == null ){
+ Toast.makeText(this, "There was a problem reading this file", Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ int lastSlash = Objects.requireNonNull(mFileUri.getPath()).lastIndexOf('/');
if (lastSlash != -1) {
mFileName = mFileUri.getPath().substring(lastSlash + 1);
} else mFileName = "";
@@ -135,16 +130,17 @@ private void parseHeaders(Uri data) {
try {
//query file path type
- mFilePath = getPath(mFileUri);
- int lastDot = mFileUri.toString().lastIndexOf(".");
+// mFilePath = getPath(LoaderDBActivity.this ,mFileUri);
+ String mFilePath = UriHandler.getPath(LoaderDBActivity.this, mFileUri);
+ int lastDot = mFilePath.lastIndexOf("."); // changed from mFileUri to mFilePath due to the files in download folder have URI without extension
if (lastDot == -1) {
Toast.makeText(this, "Imported file must have an extension. (e.g: .csv, .tsv)", Toast.LENGTH_LONG).show();
finish();
}
- mFileExtension = mFileUri.toString().substring(lastDot + 1);
+ mFileExtension = mFilePath.substring(lastDot + 1);
StringBuilder header = new StringBuilder();
//xls library support
@@ -531,59 +527,4 @@ public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
}
-
-
- //based on https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
- public String getPath(Uri uri) {
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-
- if (DocumentsContract.isDocumentUri(LoaderDBActivity.this, uri)) {
-
- if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
- final String[] doc = DocumentsContract.getDocumentId(uri).split(":");
- final String documentType = doc[0];
-
- if ("primary".equalsIgnoreCase(documentType)) {
- return Environment.getExternalStorageDirectory() + "/" + doc[1];
- }
- }
- else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
- final String id = DocumentsContract.getDocumentId(uri);
- if (!id.isEmpty()) {
- if (id.startsWith("raw:")) {
- return id.replaceFirst("raw:", "");
- }
- }
- final Uri contentUri = ContentUris.withAppendedId(
- Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
- return getDataColumn(LoaderDBActivity.this, contentUri, null, null);
- }
- }
- else if ("file".equalsIgnoreCase(uri.getScheme())) {
- return uri.getPath();
- } else if ("com.estrongs.files".equals(uri.getAuthority())) {
- return uri.getPath();
- }
- }
- return null;
- }
-
- public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
-
- Cursor cursor = null;
- final String column = "_data";
- final String[] projection = { column };
- try {
- cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
- if (cursor != null && cursor.moveToFirst()) {
- final int index = cursor.getColumnIndexOrThrow(column);
- return cursor.getString(index);
- }
- } finally {
- if (cursor != null)
- cursor.close();
- }
- return null;
- }
}
diff --git a/app/src/main/java/org/phenoapps/verify/MainActivity.java b/app/src/main/java/org/phenoapps/verify/MainActivity.java
index 4a26fab..c9d424b 100644
--- a/app/src/main/java/org/phenoapps/verify/MainActivity.java
+++ b/app/src/main/java/org/phenoapps/verify/MainActivity.java
@@ -11,22 +11,20 @@
import android.database.sqlite.SQLiteStatement;
import android.media.MediaPlayer;
import android.media.MediaScannerConnection;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
-import android.os.Parcelable;
+import android.os.storage.StorageManager;
import android.preference.PreferenceManager;
-import android.provider.MediaStore;
-import android.support.annotation.NonNull;
-import android.support.design.widget.NavigationView;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
+
+import androidx.annotation.NonNull;
+import com.google.android.material.navigation.NavigationView;
+import androidx.core.app.ActivityCompat;
+import androidx.core.view.GravityCompat;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import android.text.InputType;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
@@ -40,9 +38,9 @@
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
-import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
@@ -51,15 +49,12 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Locale;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.phenoapps.verify.R;
public class MainActivity extends AppCompatActivity {
@@ -563,78 +558,168 @@ private synchronized void askUserExportFileName() {
if (lastDot != -1) {
mFileName = mFileName.substring(0, lastDot);
}
- input.setText(mFileName + "_" + sdf.format(c.getTime()));
+ input.setText("Verify_"+ sdf.format(c.getTime()));
input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input);
- builder.setPositiveButton("Export", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String value = input.getText().toString();
- if (!value.isEmpty()) {
- if (isExternalStorageWritable()) {
- try {
- File verifyDirectory = new File(Environment.getExternalStorageDirectory().getPath() + "/Verify");
- final File output = new File(verifyDirectory, value + ".csv");
- final FileOutputStream fstream = new FileOutputStream(output);
- final SQLiteDatabase db = mDbHelper.getReadableDatabase();
- final String table = IdEntryContract.IdEntry.TABLE_NAME;
- final Cursor cursor = db.query(table, null, null, null, null, null, null);
- //final Cursor cursor = db.rawQuery("SElECT * FROM VERIFY", null);
-
- //first write header line
- final String[] headers = cursor.getColumnNames();
+ builder.setPositiveButton("Export", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int which) {
+ String value = input.getText().toString();
+ mFileName = value;
+ final Intent i;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ i = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ i.setType("*/*");
+ i.putExtra(Intent.EXTRA_TITLE, value+".csv");
+ startActivityForResult(Intent.createChooser(i, "Choose folder to export file."), VerifyConstants.PICK_CUSTOM_DEST);
+ }else{
+ writeToExportPath();
+ }
+ }
+ });
+ builder.show();
+ }
+
+ public void writeToExportPath(){
+ String value = mFileName;
+
+ if (!value.isEmpty()) {
+ if (isExternalStorageWritable()) {
+ try {
+ File verifyDirectory = new File(Environment.getExternalStorageDirectory().getPath() + "/Verify");
+ final File output = new File(verifyDirectory, value + ".csv");
+ final FileOutputStream fstream = new FileOutputStream(output);
+ final SQLiteDatabase db = mDbHelper.getReadableDatabase();
+ final String table = IdEntryContract.IdEntry.TABLE_NAME;
+ final Cursor cursor = db.query(table, null, null, null, null, null, null);
+ //final Cursor cursor = db.rawQuery("SElECT * FROM VERIFY", null);
+
+ //first write header line
+ final String[] headers = cursor.getColumnNames();
+ for (int i = 0; i < headers.length; i++) {
+ if (i != 0) fstream.write(",".getBytes());
+ fstream.write(headers[i].getBytes());
+ }
+ fstream.write(line_separator.getBytes());
+ //populate text file with current database values
+ if (cursor.moveToFirst()) {
+ do {
for (int i = 0; i < headers.length; i++) {
if (i != 0) fstream.write(",".getBytes());
- fstream.write(headers[i].getBytes());
+ final String val = cursor.getString(
+ cursor.getColumnIndexOrThrow(headers[i])
+ );
+ if (val == null) fstream.write("null".getBytes());
+ else fstream.write(val.getBytes());
}
fstream.write(line_separator.getBytes());
- //populate text file with current database values
- if (cursor.moveToFirst()) {
- do {
- for (int i = 0; i < headers.length; i++) {
- if (i != 0) fstream.write(",".getBytes());
- final String val = cursor.getString(
- cursor.getColumnIndexOrThrow(headers[i])
- );
- if (val == null) fstream.write("null".getBytes());
- else fstream.write(val.getBytes());
- }
- fstream.write(line_separator.getBytes());
- } while (cursor.moveToNext());
- }
+ } while (cursor.moveToNext());
+ }
- cursor.close();
- fstream.flush();
- fstream.close();
- scanFile(MainActivity.this, output);
+ cursor.close();
+ fstream.flush();
+ fstream.close();
+ scanFile(MainActivity.this, output);
/*MediaScannerConnection.scanFile(MainActivity.this, new String[] {output.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
Log.v("scan complete", path);
}
});*/
- } catch (SQLiteException e) {
- e.printStackTrace();
- Toast.makeText(MainActivity.this, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException io) {
- io.printStackTrace();
- }
- } else {
- Toast.makeText(MainActivity.this,
- "External storage not writable.", Toast.LENGTH_SHORT).show();
- }
- } else {
- Toast.makeText(MainActivity.this,
- "Must enter a file name.", Toast.LENGTH_SHORT).show();
+ }catch (NullPointerException npe){
+ npe.printStackTrace();
+ Toast.makeText(this, "Error in opening the Specified file", Toast.LENGTH_LONG).show();
+ }
+ catch (SQLiteException e) {
+ e.printStackTrace();
+ Toast.makeText(MainActivity.this, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException io) {
+ io.printStackTrace();
}
+ } else {
+ Toast.makeText(MainActivity.this,
+ "External storage not writable.", Toast.LENGTH_SHORT).show();
}
- });
+ } else {
+ Toast.makeText(MainActivity.this,
+ "Must enter a file name.", Toast.LENGTH_SHORT).show();
+ }
+ }
- builder.show();
+ public void writeToExportPath(Uri uri){
+
+ String value = mFileName;
+
+ if (uri == null){
+ Toast.makeText(this, "Unable to open the Specified file", Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ if (!value.isEmpty()) {
+ if (isExternalStorageWritable()) {
+ try {
+ final File output = new File(uri.getPath());
+ final OutputStream fstream = getContentResolver().openOutputStream(uri);
+ final SQLiteDatabase db = mDbHelper.getReadableDatabase();
+ final String table = IdEntryContract.IdEntry.TABLE_NAME;
+ final Cursor cursor = db.query(table, null, null, null, null, null, null);
+ //final Cursor cursor = db.rawQuery("SElECT * FROM VERIFY", null);
+
+ //first write header line
+ final String[] headers = cursor.getColumnNames();
+ for (int i = 0; i < headers.length; i++) {
+ if (i != 0) fstream.write(",".getBytes());
+ fstream.write(headers[i].getBytes());
+ }
+ fstream.write(line_separator.getBytes());
+ //populate text file with current database values
+ if (cursor.moveToFirst()) {
+ do {
+ for (int i = 0; i < headers.length; i++) {
+ if (i != 0) fstream.write(",".getBytes());
+ final String val = cursor.getString(
+ cursor.getColumnIndexOrThrow(headers[i])
+ );
+ if (val == null) fstream.write("null".getBytes());
+ else fstream.write(val.getBytes());
+ }
+ fstream.write(line_separator.getBytes());
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ fstream.flush();
+ fstream.close();
+ scanFile(MainActivity.this, output);
+ /*MediaScannerConnection.scanFile(MainActivity.this, new String[] {output.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() {
+ @Override
+ public void onScanCompleted(String path, Uri uri) {
+ Log.v("scan complete", path);
+ }
+ });*/
+ }catch (NullPointerException npe){
+ npe.printStackTrace();
+ Toast.makeText(this, "Error in opening the Specified file", Toast.LENGTH_LONG).show();
+ }
+ catch (SQLiteException e) {
+ e.printStackTrace();
+ Toast.makeText(MainActivity.this, "Error exporting file, is your table empty?", Toast.LENGTH_SHORT).show();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException io) {
+ io.printStackTrace();
+ }
+ } else {
+ Toast.makeText(MainActivity.this,
+ "External storage not writable.", Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ Toast.makeText(MainActivity.this,
+ "Must enter a file name.", Toast.LENGTH_SHORT).show();
+ }
}
//returns index of table with identifier = id, returns -1 if not found
@@ -728,30 +813,30 @@ final public boolean onCreateOptionsMenu(Menu m) {
@Override
final public boolean onOptionsItemSelected(MenuItem item) {
-
- DrawerLayout dl = (DrawerLayout) findViewById(org.phenoapps.verify.R.id.drawer_layout);
+ DrawerLayout dl = (DrawerLayout) findViewById(R.id.drawer_layout);
+ int actionCamera = R.id.action_camera;
+ int actionCompare = R.id.action_compare;
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
- switch (item.getItemId()) {
- case android.R.id.home:
- dl.openDrawer(GravityCompat.START);
- break;
- case org.phenoapps.verify.R.id.action_camera:
- final Intent cameraIntent = new Intent(this, ScanActivity.class);
- startActivityForResult(cameraIntent, VerifyConstants.CAMERA_INTENT_REQ);
- break;
- case R.id.action_compare:
- final Intent compareIntent = new Intent(MainActivity.this, CompareActivity.class);
- runOnUiThread(new Runnable() {
- @Override public void run() {
- startActivity(compareIntent);
- }
- });
- break;
- default:
- return super.onOptionsItemSelected(item);
+ if (item.getItemId() == android.R.id.home){
+ dl.openDrawer(GravityCompat.START);
+ }
+ else if(item.getItemId() == actionCamera){
+ final Intent cameraIntent = new Intent(this, ScanActivity.class);
+ startActivityForResult(cameraIntent, VerifyConstants.CAMERA_INTENT_REQ);
+ }
+ else if(item.getItemId() == actionCompare){
+ final Intent compareIntent = new Intent(MainActivity.this, CompareActivity.class);
+ runOnUiThread(new Runnable() {
+ @Override public void run() {
+ startActivity(compareIntent);
+ }
+ });
+ }
+ else{
+ return super.onOptionsItemSelected(item);
}
return true;
}
@@ -765,6 +850,9 @@ final protected void onActivityResult(int requestCode, int resultCode, Intent in
if (intent != null) {
switch (requestCode) {
+ case VerifyConstants.PICK_CUSTOM_DEST:
+ writeToExportPath(intent.getData());
+ break;
case VerifyConstants.DEFAULT_CONTENT_REQ:
Intent i = new Intent(this, LoaderDBActivity.class);
i.setData(intent.getData());
@@ -878,37 +966,75 @@ public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
}
private void selectDrawerItem(MenuItem menuItem) {
- switch (menuItem.getItemId()) {
-
- case org.phenoapps.verify.R.id.nav_import:
- final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
- final int scanMode = Integer.valueOf(sharedPref.getString(SettingsActivity.SCAN_MODE_LIST, "-1"));
-
- final Intent i = new Intent(Intent.ACTION_GET_CONTENT);
- i.setType("*/*");
- startActivityForResult(Intent.createChooser(i, "Choose file to import."), VerifyConstants.DEFAULT_CONTENT_REQ);
-
- break;
- case org.phenoapps.verify.R.id.nav_settings:
- final Intent settingsIntent = new Intent(this, SettingsActivity.class);
- startActivityForResult(settingsIntent, VerifyConstants.SETTINGS_INTENT_REQ);
- break;
- case org.phenoapps.verify.R.id.nav_export:
- askUserExportFileName();
- break;
- case org.phenoapps.verify.R.id.nav_about:
- showAboutDialog();
- break;
- case org.phenoapps.verify.R.id.nav_intro:
- final Intent intro_intent = new Intent(MainActivity.this, IntroActivity.class);
- runOnUiThread(new Runnable() {
- @Override public void run() {
- startActivity(intro_intent);
- }
- });
- break;
- }
+ int itemId = menuItem.getItemId();
+ // constants like id in R class are no longer final, thus can't use switch here
+
+ if (itemId == R.id.nav_import){
+ final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
+ final int scanMode = Integer.valueOf(sharedPref.getString(SettingsActivity.SCAN_MODE_LIST, "-1"));
+ final Intent i;
+ File verifyDirectory = new File(getExternalFilesDir(null), "/Verify");
+
+ File[] files = verifyDirectory.listFiles();
+
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Select files from?");
+ builder.setPositiveButton("Storage",
+ new DialogInterface.OnClickListener()
+ {
+ public void onClick(DialogInterface dialog, int id)
+ {
+ Intent i;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ i = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ }else{
+ i = new Intent(Intent.ACTION_GET_CONTENT);
+ }
+ i.setType("*/*");
+ startActivityForResult(Intent.createChooser(i, "Choose file to import."), VerifyConstants.DEFAULT_CONTENT_REQ);
+ }
+ });
+
+ builder.setNegativeButton("Verify Directory",
+ new DialogInterface.OnClickListener()
+ {
+ public void onClick(DialogInterface dialog, int id)
+ {
+
+ AlertDialog.Builder fileBuilder = new AlertDialog.Builder(MainActivity.this);
+ fileBuilder.setTitle("Select the sample file");
+ final int[] checkedItem = {-1};
+ String[] listItems = verifyDirectory.list();
+ fileBuilder.setSingleChoiceItems(listItems, checkedItem[0],(fileDialog, which) -> {
+ checkedItem[0] = which;
+ Intent i = new Intent(MainActivity.this, LoaderDBActivity.class);
+ i.setData(Uri.fromFile(files[which]));
+ startActivityForResult(i, VerifyConstants.LOADER_INTENT_REQ);
+ fileDialog.dismiss();
+ });
+
+ fileBuilder.show();
+
+ }
+ });
+ builder.show();
+ } else if (itemId == R.id.nav_settings) {
+ final Intent settingsIntent = new Intent(this, SettingsActivity.class);
+ startActivityForResult(settingsIntent, VerifyConstants.SETTINGS_INTENT_REQ);
+ } else if (itemId == R.id.nav_export) {
+ askUserExportFileName();
+ } else if (itemId == R.id.nav_about) {
+ showAboutDialog();
+ } else if (itemId == R.id.nav_intro) {
+ final Intent intro_intent = new Intent(MainActivity.this, IntroActivity.class);
+ runOnUiThread(new Runnable() {
+ @Override public void run() {
+ startActivity(intro_intent);
+ }
+ });
+ }
DrawerLayout dl = (DrawerLayout) findViewById(org.phenoapps.verify.R.id.drawer_layout);
dl.closeDrawers();
}
@@ -1042,6 +1168,7 @@ final public void onDestroy() {
@Override
public void onRequestPermissionsResult(int resultCode, String[] permissions, int[] granted) {
+ super.onRequestPermissionsResult(resultCode, permissions, granted);
boolean externalWriteAccept = false;
if (resultCode == VerifyConstants.PERM_REQ) {
for (int i = 0; i < permissions.length; i++) {
@@ -1051,7 +1178,9 @@ public void onRequestPermissionsResult(int resultCode, String[] permissions, int
}
}
if (externalWriteAccept && isExternalStorageWritable()) {
- File verifyDirectory = new File(Environment.getExternalStorageDirectory().getPath() + "/Verify");
+
+ File verifyDirectory = new File(getExternalFilesDir(null), "/Verify");
+
if (!verifyDirectory.isDirectory()) {
final boolean makeDirsSuccess = verifyDirectory.mkdirs();
if (!makeDirsSuccess) Log.d("Verify Make Directory", "failed");
diff --git a/app/src/main/java/org/phenoapps/verify/ScanActivity.java b/app/src/main/java/org/phenoapps/verify/ScanActivity.java
index fe10476..fc05790 100644
--- a/app/src/main/java/org/phenoapps/verify/ScanActivity.java
+++ b/app/src/main/java/org/phenoapps/verify/ScanActivity.java
@@ -3,7 +3,7 @@
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.widget.ImageView;
diff --git a/app/src/main/java/org/phenoapps/verify/SettingsActivity.java b/app/src/main/java/org/phenoapps/verify/SettingsActivity.java
index 4379f06..fb5a18f 100644
--- a/app/src/main/java/org/phenoapps/verify/SettingsActivity.java
+++ b/app/src/main/java/org/phenoapps/verify/SettingsActivity.java
@@ -1,9 +1,8 @@
package org.phenoapps.verify;
-import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.Preference;
-import android.support.v7.app.AppCompatActivity;
+
+import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
public class SettingsActivity extends AppCompatActivity {
diff --git a/app/src/main/java/org/phenoapps/verify/UriHandler.java b/app/src/main/java/org/phenoapps/verify/UriHandler.java
new file mode 100644
index 0000000..51c7d5f
--- /dev/null
+++ b/app/src/main/java/org/phenoapps/verify/UriHandler.java
@@ -0,0 +1,261 @@
+package org.phenoapps.verify;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.OpenableColumns;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+
+
+public class UriHandler {
+
+ /**
+ * Resolve the file name from the content Uri.
+ * @param context
+ * @param uri
+ * @return
+ */
+ public static String getFileName(@NonNull Context context, Uri uri) {
+ String mimeType = context.getContentResolver().getType(uri);
+ String fileName = null;
+
+ if (mimeType == null && context != null) {
+ String path = getPath(context, uri);
+ if (path == null) {
+ fileName = getName(uri.toString());
+ } else {
+ File file = new File(path);
+ fileName = file.getName();
+ }
+ } else {
+ Cursor returnCursor = context.getContentResolver().query(uri, null,
+ null, null, null);
+ if (returnCursor != null) {
+ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ returnCursor.moveToFirst();
+ fileName = returnCursor.getString(nameIndex);
+ returnCursor.close();
+ }
+ }
+
+ return fileName;
+ }
+//test
+ /**
+ * Returns the effective file name from the provided Uri.
+ * @param fileName
+ * @return
+ */
+ public static String getName(String fileName) {
+ if (fileName == null) {
+ return null;
+ }
+ int index = fileName.lastIndexOf('/');
+ return fileName.substring(index + 1);
+ }
+
+ /**
+ * Returns the documents directory in the storage.
+ * @param context
+ * @return
+ */
+ public static File getDocumentCacheDir(@NonNull Context context) {
+ File dir = new File(context.getCacheDir(), "documents");
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ return dir;
+ }
+
+ /**
+ * Generates new file in the specified cached directory.
+ * @param name
+ * @param directory
+ * @return
+ */
+ public static File generateFileName(@Nullable String name, File directory) {
+ if (name == null) {
+ return null;
+ }
+
+ File file = new File(directory, name);
+
+ if (file.exists()) {
+ String fileName = name;
+ String extension = "";
+ int dotIndex = name.lastIndexOf('.');
+ if (dotIndex > 0) {
+ fileName = name.substring(0, dotIndex);
+ extension = name.substring(dotIndex);
+ }
+
+ int index = 0;
+
+ while (file.exists()) {
+ index++;
+ name = fileName + '(' + index + ')' + extension;
+ file = new File(directory, name);
+ }
+ }
+
+ try {
+ if (!file.createNewFile()) {
+ return null;
+ }
+ } catch (IOException e) {
+ return null;
+ }
+
+ return file;
+ }
+
+ /**
+ * creates a locally cached file for content from any cloud provider.
+ * @param context
+ * @param uri
+ * @param destinationPath
+ */
+
+ private static void saveFileFromUri(Context context, Uri uri, String destinationPath) {
+ InputStream uriInputStream = null;
+ BufferedOutputStream bufferStream = null;
+ try {
+ uriInputStream = context.getContentResolver().openInputStream(uri);
+ bufferStream = new BufferedOutputStream(new FileOutputStream(destinationPath, false));
+ byte[] buf = new byte[1024];
+ uriInputStream.read(buf);
+ do {
+ bufferStream.write(buf);
+ } while (uriInputStream.read(buf) != -1);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (uriInputStream != null) uriInputStream.close();
+ if (bufferStream != null) bufferStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {column};
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+ /**
+ * The utility method helps to resolve the local path of a file from a content Uri.
+ * @param context
+ * @param uri
+ * @return
+ */
+ public static String getLocalPath(final Context context, Uri uri) {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ if (DocumentsContract.isDocumentUri(context, uri)) {
+
+ if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
+ final String[] doc = DocumentsContract.getDocumentId(uri).split(":");
+ final String documentType = doc[0];
+
+ if ("primary".equalsIgnoreCase(documentType)) {
+ return Environment.getExternalStorageDirectory() + "/" + doc[1];
+ }
+ } else if ("com.android.providers.media.documents".equals(uri.getAuthority()) ||
+ "com.google.android.apps.docs.storage".equals(uri.getAuthority()) ||
+ "com.microsoft.skydrive.content.StorageAccessProvider".equals(uri.getAuthority())) {
+ String fileName = getFileName(context, uri);
+ File cacheDir = getDocumentCacheDir(context);
+ File file = generateFileName(fileName, cacheDir);
+ String destinationPath = null;
+ if (file != null) {
+ destinationPath = file.getAbsolutePath();
+ saveFileFromUri(context, uri, destinationPath);
+ }
+ return destinationPath;
+ } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
+ final String id = DocumentsContract.getDocumentId(uri);
+ if (!id.isEmpty()) {
+ if (id.startsWith("raw:")) {
+ return id.replaceFirst("raw:", "");
+ }
+ }
+ String[] contentUriPrefixesToTry = new String[]{
+ "content://downloads/public_downloads",
+ "content://downloads/my_downloads",
+ "content://downloads/all_downloads"
+ };
+
+ for (String contentUriPrefix : contentUriPrefixesToTry) {
+ try {
+ Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
+ String path = getDataColumn(context, contentUri, null, null);
+ if (path != null) {
+ return path;
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ String fileName = getFileName(context, uri);
+ File cacheDir = getDocumentCacheDir(context);
+ File file = generateFileName(fileName, cacheDir);
+ String destinationPath = null;
+ if (file != null) {
+ destinationPath = file.getAbsolutePath();
+ saveFileFromUri(context, uri, destinationPath);
+ }
+ return destinationPath;
+ }
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ } else if ("com.estrongs.files".equals(uri.getAuthority())) {
+ return uri.getPath();
+ }
+ }
+ return null;
+ }
+
+
+// All the class methods implemented in reference to https://github.com/coltoscosmin/FileUtils/blob/master/FileUtils.java#L290
+
+ /**
+ *
+ * @param context the context from which the utility method is called in
+ * @param uri uri of the file to access
+ * @return path of the file to be accessed
+ */
+ public static String getPath(final Context context, final Uri uri) {
+ String absolutePath = getLocalPath(context, uri);
+ return absolutePath != null ? absolutePath : uri.toString();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/verify/VerifyConstants.java b/app/src/main/java/org/phenoapps/verify/VerifyConstants.java
index ed8b26f..cfc395c 100644
--- a/app/src/main/java/org/phenoapps/verify/VerifyConstants.java
+++ b/app/src/main/java/org/phenoapps/verify/VerifyConstants.java
@@ -15,6 +15,7 @@ class VerifyConstants {
final static int CAMERA_INTENT_REQ = 102;
final static int SETTINGS_INTENT_REQ = 103;
final static int DEFAULT_CONTENT_REQ = 104;
+ final static int PICK_CUSTOM_DEST = 105;
//extras
final static String CSV_URI = "org.phenoapps.verify.CSV_URI";
diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml
index 4521506..08a56bf 100644
--- a/app/src/main/res/layout-land/activity_main.xml
+++ b/app/src/main/res/layout-land/activity_main.xml
@@ -1,12 +1,12 @@
-
-
@@ -95,9 +95,9 @@
-
+
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-xlarge/activity_main.xml b/app/src/main/res/layout-xlarge/activity_main.xml
index 8f633d7..bf2bde7 100644
--- a/app/src/main/res/layout-xlarge/activity_main.xml
+++ b/app/src/main/res/layout-xlarge/activity_main.xml
@@ -1,12 +1,12 @@
-
-
@@ -95,9 +95,9 @@
-
+
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_compare.xml b/app/src/main/res/layout/activity_compare.xml
index 967befc..671eaa7 100644
--- a/app/src/main/res/layout/activity_compare.xml
+++ b/app/src/main/res/layout/activity_compare.xml
@@ -1,5 +1,5 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_load_file.xml b/app/src/main/res/layout/activity_load_file.xml
index 001c50e..e95c962 100644
--- a/app/src/main/res/layout/activity_load_file.xml
+++ b/app/src/main/res/layout/activity_load_file.xml
@@ -1,5 +1,5 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index e42af5f..6ed3db9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,12 +1,12 @@
-
-
@@ -110,9 +110,9 @@
-
+
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index b8ba6dd..6e1c615 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,13 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.10'
+ ext {
+ agp_version = '8.1.2'
+ }
+ ext.kotlin_version = '1.7.10'
repositories {
jcenter()
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath "com.android.tools.build:gradle:$agp_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
diff --git a/gradle.properties b/gradle.properties
index aac7c9b..9e6fce1 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -9,6 +9,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
+android.enableJetifier=true
+android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 6ca4f69..5d952ef 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Dec 05 14:30:29 CST 2018
+#Sat Nov 04 04:43:19 IST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip