|
|
|
@ -21,9 +21,6 @@ import android.provider.MediaStore;
|
|
|
|
|
import android.provider.Settings.Secure;
|
|
|
|
|
import android.util.Base64;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
|
|
import androidx.core.app.NotificationCompat;
|
|
|
|
|
|
|
|
|
|
import com.jens.automation2.location.LocationProvider;
|
|
|
|
|
import com.jens.automation2.receivers.PhoneStatusListener;
|
|
|
|
@ -47,11 +44,14 @@ import org.xml.sax.SAXException;
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.BufferedWriter;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.FileWriter;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
import java.io.StringReader;
|
|
|
|
|
import java.lang.Thread.UncaughtExceptionHandler;
|
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
@ -81,6 +81,8 @@ import javax.xml.parsers.DocumentBuilder;
|
|
|
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
|
|
|
import javax.xml.parsers.ParserConfigurationException;
|
|
|
|
|
|
|
|
|
|
import androidx.core.app.NotificationCompat;
|
|
|
|
|
|
|
|
|
|
import static com.jens.automation2.AutomationService.NOTIFICATION_CHANNEL_ID;
|
|
|
|
|
import static com.jens.automation2.AutomationService.channelName;
|
|
|
|
|
|
|
|
|
@ -313,55 +315,74 @@ public class Miscellaneous extends Service
|
|
|
|
|
{
|
|
|
|
|
if(writeableFolderStringCache == null)
|
|
|
|
|
{
|
|
|
|
|
if(!ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, Miscellaneous.getAnyContext()))
|
|
|
|
|
{
|
|
|
|
|
// Use the app-specific folder as new default.
|
|
|
|
|
// Use the app-specific folder as new default.
|
|
|
|
|
writeableFolderStringCache = Miscellaneous.getAnyContext().getFilesDir().getAbsolutePath();
|
|
|
|
|
|
|
|
|
|
writeableFolderStringCache = Miscellaneous.getAnyContext().getFilesDir().getAbsolutePath();
|
|
|
|
|
return writeableFolderStringCache;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//TODO: We have the storage permission, probably because it's an old installation. Files should be migrated to app-specific folder.
|
|
|
|
|
String testPath = null;
|
|
|
|
|
File folder = null;
|
|
|
|
|
File newConfigFile = new File(writeableFolderStringCache + "/" + XmlFileInterface.settingsFileName);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
migration:
|
|
|
|
|
if (!newConfigFile.exists())
|
|
|
|
|
{
|
|
|
|
|
if (ActivityPermissions.havePermission(ActivityPermissions.writeExternalStoragePermissionName, Miscellaneous.getAnyContext()))
|
|
|
|
|
{
|
|
|
|
|
String[] foldersToTestArray = new String[]
|
|
|
|
|
{
|
|
|
|
|
Environment.getExternalStorageDirectory().getAbsolutePath(),
|
|
|
|
|
"/storage/emulated/0",
|
|
|
|
|
"/HWUserData",
|
|
|
|
|
"/mnt/sdcard"
|
|
|
|
|
};
|
|
|
|
|
// We have the storage permission, probably because it's an old installation. Files should be migrated to app-specific folder.
|
|
|
|
|
|
|
|
|
|
for (String f : foldersToTestArray)
|
|
|
|
|
String testPath = null;
|
|
|
|
|
File folder = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (testFolder(f))
|
|
|
|
|
String[] foldersToTestArray = new String[]
|
|
|
|
|
{
|
|
|
|
|
Environment.getExternalStorageDirectory().getAbsolutePath(),
|
|
|
|
|
"/storage/emulated/0",
|
|
|
|
|
"/HWUserData",
|
|
|
|
|
"/mnt/sdcard"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (String f : foldersToTestArray)
|
|
|
|
|
{
|
|
|
|
|
String pathToUse = f + "/" + Settings.folderName;
|
|
|
|
|
Miscellaneous.logEvent("i", "Path", "Using " + pathToUse + " to store settings and log.", 2);
|
|
|
|
|
// if (testFolder(f))
|
|
|
|
|
// {
|
|
|
|
|
String pathToUse = f + "/" + Settings.folderName;
|
|
|
|
|
|
|
|
|
|
// Toast.makeText(getAnyContext(), "Using " + pathToUse + " to store settings and log.", Toast.LENGTH_LONG).show();
|
|
|
|
|
return pathToUse;
|
|
|
|
|
// Migrate existing files
|
|
|
|
|
File oldDirectory = new File(pathToUse);
|
|
|
|
|
File newDirectory = new File(writeableFolderStringCache);
|
|
|
|
|
File oldConfigFilePath = new File(pathToUse + "/" + XmlFileInterface.settingsFileName);
|
|
|
|
|
if (oldConfigFilePath.exists() && oldConfigFilePath.canWrite())
|
|
|
|
|
{
|
|
|
|
|
Miscellaneous.logEvent("i", "Path", "Found old path " + pathToUse + " for settings and logs. Migrating old files to new directory.", 2);
|
|
|
|
|
|
|
|
|
|
for (File fileToBeMoved : oldDirectory.listFiles())
|
|
|
|
|
{
|
|
|
|
|
File dstFile = new File(writeableFolderStringCache + "/" + fileToBeMoved.getName());
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
For some stupid reason Android's file.moveTo can't move files between
|
|
|
|
|
mount points. That's why we have to copy it and delete the src if successful.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if(copyFileUsingStream(fileToBeMoved, dstFile))
|
|
|
|
|
fileToBeMoved.delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String message = String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.filesHaveBeenMovedTo), newDirectory.getAbsolutePath());
|
|
|
|
|
Miscellaneous.writeStringToFile(oldDirectory.getAbsolutePath() + "/readme.txt", message);
|
|
|
|
|
break migration;
|
|
|
|
|
}
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Miscellaneous.logEvent("e", "getWritableFolder", folder.getAbsolutePath() + " does not exist and could not be created.", 3);
|
|
|
|
|
} catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Log.w("getWritableFolder", folder + " not writable.");
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Log.w("getWritableFolder", folder + " not writable.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do not change to logEvent() - we can't write
|
|
|
|
|
Toast.makeText(getAnyContext(), "No writable folder could be found.", Toast.LENGTH_LONG).show();
|
|
|
|
|
Log.e("getWritableFolder", "No writable folder could be found.");
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return writeableFolderStringCache;
|
|
|
|
|
|
|
|
|
|
return writeableFolderStringCache;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected final static String logFileName = "Automation_logfile.txt";
|
|
|
|
@ -1047,4 +1068,32 @@ public class Miscellaneous extends Service
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean copyFileUsingStream(File source, File dest) throws IOException
|
|
|
|
|
{
|
|
|
|
|
boolean returnValue = false;
|
|
|
|
|
|
|
|
|
|
InputStream is = null;
|
|
|
|
|
OutputStream os = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
is = new FileInputStream(source);
|
|
|
|
|
os = new FileOutputStream(dest);
|
|
|
|
|
byte[] buffer = new byte[1024];
|
|
|
|
|
int length;
|
|
|
|
|
while ((length = is.read(buffer)) > 0)
|
|
|
|
|
{
|
|
|
|
|
os.write(buffer, 0, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
returnValue = true;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
is.close();
|
|
|
|
|
os.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
|
}
|
|
|
|
|
}
|