diff --git a/app/src/apkFlavor/AndroidManifest.xml b/app/src/apkFlavor/AndroidManifest.xml index b82e81ff..3994004c 100644 --- a/app/src/apkFlavor/AndroidManifest.xml +++ b/app/src/apkFlavor/AndroidManifest.xml @@ -143,6 +143,8 @@ + + ruleHistoryListViewAdapter; @@ -77,11 +77,7 @@ public class ActivityMainScreen extends ActivityGeneric tvMainScreenNoteLocationImpossibleBlameGoogle = (TextView) findViewById(R.id.tvMainScreenNoteLocationImpossibleBlameGoogle); tvMainScreenNoteNews = (TextView) findViewById(R.id.tvMainScreenNoteNews); tvlockSoundDuration = (TextView)findViewById(R.id.tvlockSoundDuration); - tvFileStoreLocation = (TextView)findViewById(R.id.tvFileStoreLocation); tbLockSound = (ToggleButton) findViewById(R.id.tbLockSound); - bVolumeTest = (Button) findViewById(R.id.bVolumeTest); - bSettingsSetToDefault = (Button) findViewById(R.id.bSettingsSetToDefault); - bShareConfigAndLog = (Button) findViewById(R.id.bShareConfigAndLog); toggleService = (ToggleButton) findViewById(R.id.tbArmMastListener); toggleService.setChecked(AutomationService.isMyServiceRunning(this)); toggleService.setOnCheckedChangeListener(new OnCheckedChangeListener() @@ -136,18 +132,8 @@ public class ActivityMainScreen extends ActivityGeneric @Override public void onClick(View v) { - Intent myIntent = new Intent(ActivityMainScreen.this, ActivitySettings.class); - startActivityForResult(myIntent, 6000); - } - }); - - bVolumeTest.setOnClickListener(new OnClickListener() - { - @Override - public void onClick(View v) - { - Intent intent = new Intent(ActivityMainScreen.this, ActivityVolumeTest.class); - startActivity(intent); + Intent myIntent = new Intent(ActivityMainScreen.this, ActivityMaintenance.class); + startActivity(myIntent); } }); @@ -183,24 +169,6 @@ public class ActivityMainScreen extends ActivityGeneric builder.create().show(); } }); - - bSettingsSetToDefault.setOnClickListener(new OnClickListener() - { - @Override - public void onClick(View v) - { - getDefaultSettingsDialog(ActivityMainScreen.this).show(); - } - }); - - bShareConfigAndLog.setOnClickListener(new OnClickListener() - { - @Override - public void onClick(View v) - { - getShareConfigAndLogDialogue(ActivityMainScreen.this).show(); - } - }); lvRuleHistory.setOnTouchListener(new OnTouchListener() { @@ -264,81 +232,6 @@ public class ActivityMainScreen extends ActivityGeneric return alertDialog; } - private static AlertDialog getDefaultSettingsDialog(final Context context) - { - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); - alertDialogBuilder.setTitle(context.getResources().getString(R.string.areYouSure)); - alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener() - { - @Override - public void onClick(DialogInterface dialog, int which) - { - if (Settings.initializeSettings(context, true)) - Toast.makeText(context, context.getResources().getString(R.string.settingsSetToDefault), Toast.LENGTH_LONG).show(); - } - }); - alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null); - AlertDialog alertDialog = alertDialogBuilder.create(); - - return alertDialog; - } - - AlertDialog getShareConfigAndLogDialogue(final Context context) - { - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); - alertDialogBuilder.setTitle(context.getResources().getString(R.string.shareConfigAndLogFilesWithDev)); - alertDialogBuilder.setMessage(context.getResources().getString(R.string.shareConfigAndLogExplanation)); - alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener() - { - @Override - public void onClick(DialogInterface dialog, int which) - { - File dstZipFile = new File(Miscellaneous.getAnyContext().getCacheDir() + "/" + Settings.zipFileName); - - ArrayList srcFilesList = new ArrayList<>(); - srcFilesList.add(Miscellaneous.getWriteableFolder() + "/" + XmlFileInterface.settingsFileName); - - String logFilePath = Miscellaneous.getWriteableFolder() + "/" + Miscellaneous.logFileName; - if((new File(logFilePath)).exists()) - srcFilesList.add(logFilePath); - - String logFilePathArchive = Miscellaneous.getWriteableFolder() + "/" + Miscellaneous.logFileName + "-old"; - if((new File(logFilePathArchive)).exists()) - srcFilesList.add(logFilePathArchive); - - String[] srcFiles = srcFilesList.toArray(new String[srcFilesList.size()]); - - if(dstZipFile.exists()) - dstZipFile.delete(); - - Miscellaneous.zip(srcFiles, dstZipFile.getAbsolutePath()); - - /* - Without root the zip file in the cache directory is not directly accessible. - But have to route it through this content provider crap. - */ - - String subject = "Automation logs"; - - StringBuilder emailBody = new StringBuilder(); - emailBody.append("Device details" + Miscellaneous.lineSeparator); - emailBody.append("OS version: " + System.getProperty("os.version") + Miscellaneous.lineSeparator); - emailBody.append("API Level: " + android.os.Build.VERSION.SDK + Miscellaneous.lineSeparator); - emailBody.append("Device: " + android.os.Build.DEVICE + Miscellaneous.lineSeparator); - emailBody.append("Model: " + android.os.Build.MODEL + Miscellaneous.lineSeparator); - emailBody.append("Product: " + android.os.Build.PRODUCT); - - Uri uri = Uri.parse("content://com.jens.automation2/" + Settings.zipFileName); - - Miscellaneous.sendEmail(ActivityMainScreen.this, "android-development@gmx.de", "Automation logs", emailBody.toString(), uri); - } - }); - alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null); - AlertDialog alertDialog = alertDialogBuilder.create(); - - return alertDialog; - } - public static ActivityMainScreen getActivityMainScreenInstance() { return activityMainScreenInstance; @@ -515,34 +408,6 @@ public class ActivityMainScreen extends ActivityGeneric Settings.considerDone(Settings.constNewsOptInDone); Settings.writeSettings(Miscellaneous.getAnyContext()); - - String folder = Miscellaneous.getWriteableFolder(); - if(folder != null && folder.length() > 0) - { - activityMainScreenInstance.tvFileStoreLocation.setText(String.format(activityMainScreenInstance.getResources().getString(R.string.filesStoredAt), folder)); - activityMainScreenInstance.tvFileStoreLocation.setOnClickListener(new OnClickListener() - { - @Override - public void onClick(View v) - { - Uri selectedUri = Uri.parse(folder); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(selectedUri, "resource/folder"); - - if (intent.resolveActivityInfo(activityMainScreenInstance.getPackageManager(), 0) != null) - { - activityMainScreenInstance.startActivity(intent); - } - else - { - // if you reach this place, it means there is no any file - // explorer app installed on your device - Toast.makeText(activityMainScreenInstance, activityMainScreenInstance.getResources().getString(R.string.noFileManageInstalled), Toast.LENGTH_LONG).show(); - } - - } - }); - } } } @@ -598,16 +463,6 @@ public class ActivityMainScreen extends ActivityGeneric case ActivityPermissions.requestCodeForPermissions: updateMainScreen(); break; - case 6000: //settings - Settings.readFromPersistentStorage(this); - - if (boundToService && AutomationService.isMyServiceRunning(this)) - myAutomationService.serviceInterface(serviceCommands.reloadSettings); - - if(AutomationService.isMyServiceRunning(ActivityMainScreen.this)) - Toast.makeText(this, getResources().getString(R.string.settingsWillTakeTime), Toast.LENGTH_LONG).show(); - - break; } if (AutomationService.isMyServiceRunning(this)) diff --git a/app/src/main/java/com/jens/automation2/ActivityMaintenance.java b/app/src/main/java/com/jens/automation2/ActivityMaintenance.java new file mode 100644 index 00000000..75c74898 --- /dev/null +++ b/app/src/main/java/com/jens/automation2/ActivityMaintenance.java @@ -0,0 +1,248 @@ +package com.jens.automation2; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.documentfile.provider.DocumentFile; + +import java.io.File; +import java.util.ArrayList; + +public class ActivityMaintenance extends Activity +{ + final static int requestCodeImport = 1001; + final static int requestCodeExport = 1002; + final static int requestCodeMoreSettings = 6000; + + TextView tvFileStoreLocation; + Button bVolumeTest, bMoreSettings, bSettingsSetToDefault, bShareConfigAndLog, bImportConfiguration, bExportConfiguration; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_maintenance); + + bVolumeTest = (Button) findViewById(R.id.bVolumeTest); + bVolumeTest.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Intent intent = new Intent(ActivityMaintenance.this, ActivityVolumeTest.class); + startActivity(intent); + } + }); + + bShareConfigAndLog = (Button) findViewById(R.id.bShareConfigAndLog); + bShareConfigAndLog.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + getShareConfigAndLogDialogue(ActivityMaintenance.this).show(); + } + }); + + bSettingsSetToDefault = (Button) findViewById(R.id.bSettingsSetToDefault); + bSettingsSetToDefault.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + getDefaultSettingsDialog(ActivityMaintenance.this).show(); + } + }); + + Button bMoreSettings = (Button) findViewById(R.id.bMoreSettings); + bMoreSettings.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Intent myIntent = new Intent(ActivityMaintenance.this, ActivitySettings.class); + startActivityForResult(myIntent, requestCodeMoreSettings); + } + }); + + bImportConfiguration = (Button) findViewById(R.id.bImportConfiguration); + bImportConfiguration.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(intent, requestCodeImport); + } + }); + + bExportConfiguration = (Button) findViewById(R.id.bExportConfiguration); + bExportConfiguration.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(intent, requestCodeExport); + } + }); + + tvFileStoreLocation = (TextView)findViewById(R.id.tvFileStoreLocation); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + switch(requestCode) + { + case requestCodeMoreSettings: //settings + Settings.readFromPersistentStorage(this); + + if (AutomationService.isMyServiceRunning(this)) + AutomationService.getInstance().serviceInterface(AutomationService.serviceCommands.reloadSettings); + + if (AutomationService.isMyServiceRunning(ActivityMaintenance.this)) + Toast.makeText(this, getResources().getString(R.string.settingsWillTakeTime), Toast.LENGTH_LONG).show(); + + break; + case requestCodeImport: + if(resultCode == RESULT_OK) + { + Uri uriTree = data.getData(); + DocumentFile directory = DocumentFile.fromTreeUri(this, uriTree); + for(DocumentFile file : directory.listFiles()) + { + if(file.canRead() && file.getName().equals(XmlFileInterface.settingsFileName)) + { + // import rules, locations, etc. + Miscellaneous.copyFileUsingStream(file, Miscellaneous.getWriteableFolder() + "/" + XmlFileInterface.settingsFileName); + } + else if(false && file.canRead() && file.getName().equals(XmlFileInterface.settingsFileName)) + { + // import rules, locations, etc. + } + } + } + break; + } + } + + private static AlertDialog getDefaultSettingsDialog(final Context context) + { + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); + alertDialogBuilder.setTitle(context.getResources().getString(R.string.areYouSure)); + alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + if (Settings.initializeSettings(context, true)) + Toast.makeText(context, context.getResources().getString(R.string.settingsSetToDefault), Toast.LENGTH_LONG).show(); + } + }); + alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null); + AlertDialog alertDialog = alertDialogBuilder.create(); + + return alertDialog; + } + + AlertDialog getShareConfigAndLogDialogue(final Context context) + { + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); + alertDialogBuilder.setTitle(context.getResources().getString(R.string.shareConfigAndLogFilesWithDev)); + alertDialogBuilder.setMessage(context.getResources().getString(R.string.shareConfigAndLogExplanation)); + alertDialogBuilder.setPositiveButton(context.getResources().getString(R.string.yes), new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + File dstZipFile = new File(Miscellaneous.getAnyContext().getCacheDir() + "/" + Settings.zipFileName); + + ArrayList srcFilesList = new ArrayList<>(); + srcFilesList.add(Miscellaneous.getWriteableFolder() + "/" + XmlFileInterface.settingsFileName); + + String logFilePath = Miscellaneous.getWriteableFolder() + "/" + Miscellaneous.logFileName; + if((new File(logFilePath)).exists()) + srcFilesList.add(logFilePath); + + String logFilePathArchive = Miscellaneous.getWriteableFolder() + "/" + Miscellaneous.logFileName + "-old"; + if((new File(logFilePathArchive)).exists()) + srcFilesList.add(logFilePathArchive); + + String[] srcFiles = srcFilesList.toArray(new String[srcFilesList.size()]); + + if(dstZipFile.exists()) + dstZipFile.delete(); + + Miscellaneous.zip(srcFiles, dstZipFile.getAbsolutePath()); + + /* + Without root the zip file in the cache directory is not directly accessible. + But have to route it through this content provider crap. + */ + + String subject = "Automation logs"; + + StringBuilder emailBody = new StringBuilder(); + emailBody.append("Device details" + Miscellaneous.lineSeparator); + emailBody.append("OS version: " + System.getProperty("os.version") + Miscellaneous.lineSeparator); + emailBody.append("API Level: " + android.os.Build.VERSION.SDK + Miscellaneous.lineSeparator); + emailBody.append("Device: " + android.os.Build.DEVICE + Miscellaneous.lineSeparator); + emailBody.append("Model: " + android.os.Build.MODEL + Miscellaneous.lineSeparator); + emailBody.append("Product: " + android.os.Build.PRODUCT); + + Uri uri = Uri.parse("content://com.jens.automation2/" + Settings.zipFileName); + + Miscellaneous.sendEmail(ActivityMaintenance.this, "android-development@gmx.de", "Automation logs", emailBody.toString(), uri); + } + }); + alertDialogBuilder.setNegativeButton(context.getResources().getString(R.string.no), null); + AlertDialog alertDialog = alertDialogBuilder.create(); + + return alertDialog; + } + + @Override + protected void onResume() + { + super.onResume(); + + String folder = Miscellaneous.getWriteableFolder(); + if (folder != null && folder.length() > 0) + { + tvFileStoreLocation.setText(String.format(getResources().getString(R.string.filesStoredAt), folder)); + tvFileStoreLocation.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Uri selectedUri = Uri.parse(folder); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(selectedUri, "resource/folder"); + + if (intent.resolveActivityInfo(getPackageManager(), 0) != null) + { + startActivity(intent); + } + else + { + // if you reach this place, it means there is no any file + // explorer app installed on your device + Toast.makeText(ActivityMaintenance.this, getResources().getString(R.string.noFileManageInstalled), Toast.LENGTH_LONG).show(); + } + + } + }); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/ActivityManageActionStartActivity.java b/app/src/main/java/com/jens/automation2/ActivityManageActionStartActivity.java index 7033e43d..da12ac2c 100644 --- a/app/src/main/java/com/jens/automation2/ActivityManageActionStartActivity.java +++ b/app/src/main/java/com/jens/automation2/ActivityManageActionStartActivity.java @@ -432,34 +432,45 @@ public class ActivityManageActionStartActivity extends Activity private void loadValuesIntoGui() { - boolean selectionByActivity = resultingAction.getParameter1(); - rbStartAppSelectByActivity.setChecked(selectionByActivity); - rbStartAppSelectByAction.setChecked(!selectionByActivity); + boolean selectionByAction = resultingAction.getParameter1(); + rbStartAppSelectByActivity.setChecked(!selectionByAction); + rbStartAppSelectByAction.setChecked(selectionByAction); String[] params = resultingAction.getParameter2().split(";"); int startIndex = -1; - if(selectionByActivity) + if(!selectionByAction) { etPackageName.setText(params[0]); - etActivityOrActionPath.setText(params[1]); + if(params.length > 1) // should not occur, have fault tollerance + { + etActivityOrActionPath.setText(params[1]); - if(params.length >= 2) - startIndex = 2; + if (params.length >= 2) + startIndex = 2; + } } else { - if(params[1].contains("/")) + if(params.length > 1) // should not occur, have fault tollerance { - etActivityOrActionPath.setText(params[0]); - startIndex = 1; + if(params[1].contains("/")) + { + etActivityOrActionPath.setText(params[0]); + startIndex = 1; + } + else + { + etPackageName.setText(params[0]); + etActivityOrActionPath.setText(params[1]); + startIndex = 2; + } } else { - etPackageName.setText(params[0]); - etActivityOrActionPath.setText(params[1]); - startIndex = 2; + etActivityOrActionPath.setText(params[0]); + startIndex = 1; } } @@ -514,7 +525,7 @@ public class ActivityManageActionStartActivity extends Activity if(resultingAction == null) resultingAction = new Action(); - resultingAction.setParameter1(rbStartAppSelectByActivity.isChecked()); + resultingAction.setParameter1(rbStartAppSelectByAction.isChecked()); resultingAction.setAction(Action_Enum.startOtherActivity); diff --git a/app/src/main/java/com/jens/automation2/ActivityTriggerPhoneCall.java b/app/src/main/java/com/jens/automation2/ActivityTriggerPhoneCall.java new file mode 100644 index 00000000..8611bc08 --- /dev/null +++ b/app/src/main/java/com/jens/automation2/ActivityTriggerPhoneCall.java @@ -0,0 +1,16 @@ +package com.jens.automation2; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.annotation.Nullable; + +public class ActivityTriggerPhoneCall extends Activity +{ + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.trigger_phone_call); + } +} diff --git a/app/src/main/java/com/jens/automation2/Miscellaneous.java b/app/src/main/java/com/jens/automation2/Miscellaneous.java index be9013e0..d79d7f9b 100644 --- a/app/src/main/java/com/jens/automation2/Miscellaneous.java +++ b/app/src/main/java/com/jens/automation2/Miscellaneous.java @@ -90,6 +90,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import androidx.core.app.NotificationCompat; +import androidx.documentfile.provider.DocumentFile; import static android.provider.CalendarContract.CalendarCache.URI; import static com.jens.automation2.AutomationService.NOTIFICATION_CHANNEL_ID; @@ -1214,6 +1215,37 @@ public class Miscellaneous extends Service return returnValue; } + public static String copyDocumentFile(String inputPath, String inputFile, Uri treeUri) + { + InputStream in = null; + OutputStream out = null; + String error = null; + DocumentFile pickedDir = DocumentFile.fromTreeUri(getActivity(), treeUri); + String extension = inputFile.substring(inputFile.lastIndexOf(".")+1,inputFile.length()); + + try { + DocumentFile newFile = pickedDir.createFile("audio/"+extension, inputFile); + out = getActivity().getContentResolver().openOutputStream(newFile.getUri()); + in = new FileInputStream(inputPath + inputFile); + + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + in.close(); + // write the output file (You have now copied the file) + out.flush(); + out.close(); + + } catch (FileNotFoundException fnfe1) { + error = fnfe1.getMessage(); + } catch (Exception e) { + error = e.getMessage(); + } + return error; + } + public static boolean googleToBlameForLocation(boolean checkExistingRules) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) diff --git a/app/src/main/res/layout/activity_maintenance.xml b/app/src/main/res/layout/activity_maintenance.xml new file mode 100644 index 00000000..92b30d28 --- /dev/null +++ b/app/src/main/res/layout/activity_maintenance.xml @@ -0,0 +1,59 @@ + + + + + +