Manuel Fuhr 54d5c5e943 Reformat files using Android Studio
android-studio/bin/format.sh -m '*.java' -r brouter-routing-app

To rebase active branches on top of the new master just rebase your
branch onto the commit prior to the reformatting and format every commit
of your branch using (<commit> should be replaced by this commit)

git rebase \
        --strategy-option=theirs \
        --onto <commit> \
        --exec 'format.sh -m "*.java" -r brouter-routing-app' \
        --exec 'git commit --all --no-edit --amend' \
        <commit>~

To ignore this mass edit during git blame see `.git-blame-ignore-revs`
2021-11-20 16:50:23 +01:00

488 lines
14 KiB
Java

package btools.routingapp;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.net.TrafficStats;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import btools.mapaccess.PhysicalFile;
import btools.mapaccess.Rd5DiffManager;
import btools.mapaccess.Rd5DiffTool;
import btools.util.ProgressListener;
public class DownloadService extends Service implements ProgressListener {
private static final boolean DEBUG = false;
private ServerConfig mServerConfig;
private NotificationHelper mNotificationHelper;
private List<String> mUrlList;
private String baseDir;
private volatile String newDownloadAction = "";
private volatile String currentDownloadOperation = "";
private long availableSize;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private NotificationManager mNM;
String downloadUrl;
public static boolean serviceState = false;
private boolean bIsDownloading;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
bIsDownloading = true;
downloadFiles();
stopForeground(true);
stopSelf(msg.arg1);
mNotificationHelper.stopNotification();
}
}
@Override
public void onCreate() {
if (DEBUG) Log.d("SERVICE", "onCreate");
serviceState = true;
mServerConfig = new ServerConfig(getApplicationContext());
HandlerThread thread = new HandlerThread("ServiceStartArguments", 1);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
availableSize = -1;
try {
availableSize = BInstallerActivity.getAvailableSpace(baseDir);
//StatFs stat = new StatFs(baseDir);
//availableSize = (long)stat.getAvailableBlocksLong()*stat.getBlockSizeLong();
} catch (Exception e) { /* ignore */ }
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d("SERVICE", "onStartCommand");
mNotificationHelper = new NotificationHelper(this);
Bundle extra = intent.getExtras();
if (extra != null) {
String dir = extra.getString("dir");
List<String> urlparts = extra.getStringArrayList("urlparts");
mUrlList = urlparts;
baseDir = dir;
}
mNotificationHelper.startNotification(this);
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d("SERVICE", "onDestroy");
serviceState = false;
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void downloadFiles() {
// first check lookup table and profiles
String result = checkScripts();
if (result != null) {
if (DEBUG) Log.d("BR", "error: " + result);
bIsDownloading = false;
updateProgress("finished ");
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
return;
}
int count = 1;
int size = mUrlList.size();
for (String part : mUrlList) {
String url = mServerConfig.getSegmentUrl() + part + ".rd5";
if (DEBUG) Log.d("BR", "downlaod " + url);
result = download(count, size, url);
if (result != null) {
if (DEBUG) Log.d("BR", "" + result);
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
break;
} else {
updateProgress("Download " + part + " " + count + "/" + size + " finshed");
}
count++;
}
bIsDownloading = false;
updateProgress("finished ");
}
public void updateProgress(String progress) {
if (!newDownloadAction.equals(progress)) {
if (DEBUG) Log.d("BR", "up " + progress);
Intent intent = new Intent(BInstallerActivity.DOWNLOAD_ACTION);
intent.putExtra("txt", progress);
intent.putExtra("ready", bIsDownloading);
sendBroadcast(intent);
;
newDownloadAction = progress;
mNotificationHelper.progressUpdate(newDownloadAction);
}
}
private String download(int counter, int size, String surl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
File fname = null;
File tmp_file = null;
try {
try {
TrafficStats.setThreadStatsTag(1);
int slidx = surl.lastIndexOf("segments4/");
String name = surl.substring(slidx + 10);
String surlBase = surl.substring(0, slidx + 10);
fname = new File(baseDir, "segments4/" + name);
boolean delta = true;
// if (!targetFile.getParentFile().exists()) targetFile.getParentFile().mkdirs();
if (fname.exists()) {
updateProgress("Calculating local checksum..");
// first check for a delta file
String md5 = Rd5DiffManager.getMD5(fname);
String surlDelta = surlBase + "diff/" + name.replace(".rd5", "/" + md5 + ".df5");
URL urlDelta = new URL(surlDelta);
connection = (HttpURLConnection) urlDelta.openConnection();
connection.setConnectTimeout(5000);
connection.connect();
// 404 kind of expected here, means there's no delta file
if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
connection = null;
} else {
updateProgress("Connecting.." + surlDelta);
}
}
if (connection == null) {
updateProgress("Connecting.." + name);
delta = false;
URL url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.connect();
}
updateProgress("Connecting.." + counter + "/" + size);
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
long currentDownloadSize = fileLength;
if (availableSize >= 0 && fileLength > availableSize) return "not enough space on sd-card";
currentDownloadOperation = delta ? "Updating" : "Loading";
updateProgress(currentDownloadOperation);
// download the file
input = connection.getInputStream();
tmp_file = new File(fname.getAbsolutePath() + (delta ? "_diff" : "_tmp"));
output = new FileOutputStream(tmp_file);
byte[] data = new byte[4096];
long total = 0;
long t0 = System.currentTimeMillis();
int count;
while ((count = input.read(data)) != -1) {
if (isCanceled()) {
return "Download canceled!";
}
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
{
int pct = (int) (total * 100 / fileLength);
updateProgress("Progress " + counter + "/" + size + " .. " + pct + "%");
} else {
updateProgress("Progress (unnown size)");
}
output.write(data, 0, count);
// enforce < 2 Mbit/s
long dt = t0 + total / 524 - System.currentTimeMillis();
if (dt > 0) {
try {
Thread.sleep(dt);
} catch (InterruptedException ie) {
}
}
}
output.close();
output = null;
if (delta) {
updateProgress("Applying delta..");
File diffFile = tmp_file;
tmp_file = new File(fname + "_tmp");
Rd5DiffTool.recoverFromDelta(fname, diffFile, tmp_file, this);
diffFile.delete();
}
if (isCanceled()) {
return "Canceled!";
}
if (tmp_file != null) {
updateProgress("Verifying integrity..");
String check_result = PhysicalFile.checkFileIntegrity(tmp_file);
if (check_result != null) {
if (check_result.startsWith("version old lookups.dat")) {
}
return check_result;
}
if (fname.exists()) fname.delete();
if (!tmp_file.renameTo(fname)) {
return "Could not rename to " + fname.getAbsolutePath();
}
}
return null;
} catch (Exception e) {
//e.printStackTrace(); ;
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
} finally {
if (tmp_file != null) tmp_file.delete(); // just to be sure
}
}
private String checkScripts() {
String[] sa = mServerConfig.getLookups();
for (String f : sa) {
if (f.length() > 0) {
File file = new File(baseDir + "profiles2", f);
checkOrDownloadLookup(f, file);
}
}
sa = mServerConfig.getProfiles();
for (String f : sa) {
if (f.length() > 0) {
File file = new File(baseDir + "profiles2", f);
if (file.exists()) {
String result = checkOrDownloadScript(f, file);
if (result != null) {
return result;
}
}
}
}
return null;
}
private String checkOrDownloadLookup(String fileName, File f) {
String url = mServerConfig.getLookupUrl() + fileName;
return downloadScript(url, f);
}
private String checkOrDownloadScript(String fileName, File f) {
String url = mServerConfig.getProfilesUrl() + fileName;
return downloadScript(url, f);
}
private String downloadScript(String surl, File f) {
long size = 0L;
if (f.exists()) {
size = f.length();
}
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
File tmp_file = null;
File targetFile = f;
try {
try {
TrafficStats.setThreadStatsTag(1);
URL url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
return null;
}
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage() + " " + f.getName();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
long fileLength = (long) connection.getContentLength();
if (DEBUG) Log.d("BR", "file size " + size + " == " + fileLength + " " + f.getName());
if (fileLength != size) {
long currentDownloadSize = fileLength;
if (availableSize >= 0 && fileLength > availableSize)
return "not enough space on sd-card";
currentDownloadOperation = "Updating";
// download the file
input = connection.getInputStream();
tmp_file = new File(f.getAbsolutePath() + "_tmp");
output = new FileOutputStream(tmp_file);
byte data[] = new byte[4096];
long total = 0;
long t0 = System.currentTimeMillis();
int count;
while ((count = input.read(data)) != -1) {
if (isCanceled()) {
return "Download canceled!";
}
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
{
int pct = (int) (total * 100 / fileLength);
updateProgress("Progress " + pct + "%");
} else {
updateProgress("Progress (unnown size)");
}
output.write(data, 0, count);
// enforce < 2 Mbit/s
long dt = t0 + total / 524 - System.currentTimeMillis();
if (dt > 0) {
try {
Thread.sleep(dt);
} catch (InterruptedException ie) {
}
}
}
output.close();
output = null;
}
if (isCanceled()) {
return "Canceled!";
}
if (tmp_file != null) {
f.delete();
if (!tmp_file.renameTo(f)) {
return "Could not rename to " + f.getName();
}
if (DEBUG) Log.d("BR", "update " + f.getName());
}
return null;
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
} finally {
if (tmp_file != null) tmp_file.delete(); // just to be sure
}
}
public boolean isCanceled() {
return BInstallerView.downloadCanceled;
}
}