Remove DownloadService
This commit is contained in:
parent
ecc4def40c
commit
3a2c109ded
4 changed files with 0 additions and 417 deletions
|
@ -91,11 +91,6 @@
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:process=":brouter_service" />
|
android:process=":brouter_service" />
|
||||||
<service
|
|
||||||
android:name="btools.routingapp.DownloadService"
|
|
||||||
android:enabled="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="Download Service" />
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -35,7 +35,6 @@ import btools.router.RoutingHelper;
|
||||||
|
|
||||||
public class BInstallerActivity extends AppCompatActivity {
|
public class BInstallerActivity extends AppCompatActivity {
|
||||||
|
|
||||||
public static final String DOWNLOAD_ACTION = "btools.routingapp.download";
|
|
||||||
private static final int DIALOG_CONFIRM_DELETE_ID = 1;
|
private static final int DIALOG_CONFIRM_DELETE_ID = 1;
|
||||||
public static boolean downloadCanceled = false;
|
public static boolean downloadCanceled = false;
|
||||||
private File mBaseDir;
|
private File mBaseDir;
|
||||||
|
|
|
@ -1,277 +0,0 @@
|
||||||
package btools.routingapp;
|
|
||||||
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Intent;
|
|
||||||
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 String PROFILES_DIR = "profiles2/";
|
|
||||||
private static final String SEGMENTS_DIR = "segments4/";
|
|
||||||
private static final String SEGMENT_DIFF_SUFFIX = ".df5";
|
|
||||||
private static final String SEGMENT_SUFFIX = ".rd5";
|
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
public static boolean serviceState = false;
|
|
||||||
private ServerConfig mServerConfig;
|
|
||||||
private NotificationHelper mNotificationHelper;
|
|
||||||
private List<String> mSegmentNames;
|
|
||||||
private String baseDir;
|
|
||||||
private volatile String lastProgress = "";
|
|
||||||
private ServiceHandler mServiceHandler;
|
|
||||||
private boolean bIsDownloading;
|
|
||||||
private int mSegmentIndex;
|
|
||||||
private int mSegmentCount;
|
|
||||||
|
|
||||||
@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
|
|
||||||
Looper serviceLooper = thread.getLooper();
|
|
||||||
mServiceHandler = new ServiceHandler(serviceLooper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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");
|
|
||||||
mSegmentNames = extra.getStringArrayList("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() {
|
|
||||||
try {
|
|
||||||
mSegmentIndex = 0;
|
|
||||||
downloadLookupAndProfiles();
|
|
||||||
|
|
||||||
mSegmentIndex = 1;
|
|
||||||
mSegmentCount = mSegmentNames.size();
|
|
||||||
for (String segmentName : mSegmentNames) {
|
|
||||||
downloadSegment(mServerConfig.getSegmentUrl(), segmentName + SEGMENT_SUFFIX);
|
|
||||||
mSegmentIndex++;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
updateProgress("canceled");
|
|
||||||
} finally {
|
|
||||||
bIsDownloading = false;
|
|
||||||
updateProgress("finished");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateProgress(String progress) {
|
|
||||||
if (!lastProgress.equals(progress)) {
|
|
||||||
if (mSegmentIndex > 0) {
|
|
||||||
progress = mSegmentIndex + "/" + mSegmentCount + " " + 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);
|
|
||||||
mNotificationHelper.progressUpdate(progress);
|
|
||||||
lastProgress = progress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void downloadLookupAndProfiles() throws IOException, InterruptedException {
|
|
||||||
String[] lookups = mServerConfig.getLookups();
|
|
||||||
for (String fileName : lookups) {
|
|
||||||
if (fileName.length() > 0) {
|
|
||||||
File lookupFile = new File(baseDir, PROFILES_DIR + fileName);
|
|
||||||
String lookupLocation = mServerConfig.getLookupUrl() + fileName;
|
|
||||||
URL lookupUrl = new URL(lookupLocation);
|
|
||||||
downloadFile(lookupUrl, lookupFile, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] profiles = mServerConfig.getProfiles();
|
|
||||||
for (String fileName : profiles) {
|
|
||||||
if (fileName.length() > 0) {
|
|
||||||
File profileFile = new File(baseDir, PROFILES_DIR + fileName);
|
|
||||||
if (profileFile.exists()) {
|
|
||||||
String profileLocation = mServerConfig.getProfilesUrl() + fileName;
|
|
||||||
URL profileUrl = new URL(profileLocation);
|
|
||||||
downloadFile(profileUrl, profileFile, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void downloadSegment(String segmentBaseUrl, String segmentName) throws IOException, InterruptedException {
|
|
||||||
File segmentFile = new File(baseDir, SEGMENTS_DIR + segmentName);
|
|
||||||
File segmentFileTemp = new File(segmentFile.getAbsolutePath() + "_tmp");
|
|
||||||
try {
|
|
||||||
if (segmentFile.exists()) {
|
|
||||||
updateProgress("Calculating local checksum...");
|
|
||||||
String md5 = Rd5DiffManager.getMD5(segmentFile);
|
|
||||||
String segmentDeltaLocation = segmentBaseUrl + "diff/" + segmentName.replace(SEGMENT_SUFFIX, "/" + md5 + SEGMENT_DIFF_SUFFIX);
|
|
||||||
URL segmentDeltaUrl = new URL(segmentDeltaLocation);
|
|
||||||
if (httpFileExists(segmentDeltaUrl)) {
|
|
||||||
File segmentDeltaFile = new File(segmentFile.getAbsolutePath() + "_diff");
|
|
||||||
try {
|
|
||||||
downloadFile(segmentDeltaUrl, segmentDeltaFile, true);
|
|
||||||
updateProgress("Applying delta...");
|
|
||||||
Rd5DiffTool.recoverFromDelta(segmentFile, segmentDeltaFile, segmentFileTemp, this);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IOException("Failed to download & apply delta update", e);
|
|
||||||
} finally {
|
|
||||||
segmentDeltaFile.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!segmentFileTemp.exists()) {
|
|
||||||
URL segmentUrl = new URL(segmentBaseUrl + segmentName);
|
|
||||||
downloadFile(segmentUrl, segmentFileTemp, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalFile.checkFileIntegrity(segmentFileTemp);
|
|
||||||
if (segmentFile.exists()) {
|
|
||||||
if (!segmentFile.delete()) {
|
|
||||||
throw new IOException("Failed to delete existing " + segmentFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!segmentFileTemp.renameTo(segmentFile)) {
|
|
||||||
throw new IOException("Failed to write " + segmentFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
segmentFileTemp.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean httpFileExists(URL downloadUrl) throws IOException {
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
|
||||||
connection.setConnectTimeout(5000);
|
|
||||||
connection.setRequestMethod("HEAD");
|
|
||||||
connection.connect();
|
|
||||||
|
|
||||||
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void downloadFile(URL downloadUrl, File outputFile, boolean limitDownloadSpeed) throws IOException, InterruptedException {
|
|
||||||
// For all those small files the progress reporting is really noisy
|
|
||||||
boolean reportDownloadProgress = limitDownloadSpeed;
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
|
||||||
connection.setConnectTimeout(5000);
|
|
||||||
connection.connect();
|
|
||||||
|
|
||||||
if (reportDownloadProgress) updateProgress("Connecting...");
|
|
||||||
|
|
||||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
|
||||||
throw new IOException("HTTP Request failed");
|
|
||||||
}
|
|
||||||
int fileLength = connection.getContentLength();
|
|
||||||
if (reportDownloadProgress) updateProgress("Loading");
|
|
||||||
|
|
||||||
try (
|
|
||||||
InputStream input = connection.getInputStream();
|
|
||||||
OutputStream output = new FileOutputStream(outputFile)
|
|
||||||
) {
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
long total = 0;
|
|
||||||
long t0 = System.currentTimeMillis();
|
|
||||||
int count;
|
|
||||||
while ((count = input.read(buffer)) != -1) {
|
|
||||||
if (isCanceled()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
total += count;
|
|
||||||
// publishing the progress....
|
|
||||||
if (fileLength > 0) // only if total length is known
|
|
||||||
{
|
|
||||||
int pct = (int) (total * 100 / fileLength);
|
|
||||||
if (reportDownloadProgress) updateProgress("Progress " + pct + "%");
|
|
||||||
} else {
|
|
||||||
if (reportDownloadProgress) updateProgress("Progress (unknown size)");
|
|
||||||
}
|
|
||||||
output.write(buffer, 0, count);
|
|
||||||
|
|
||||||
if (limitDownloadSpeed) {
|
|
||||||
// enforce < 16 Mbit/s
|
|
||||||
long dt = t0 + total / 2096 - System.currentTimeMillis();
|
|
||||||
if (dt > 0) {
|
|
||||||
Thread.sleep(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCanceled() {
|
|
||||||
return BInstallerActivity.downloadCanceled;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
package btools.routingapp;
|
|
||||||
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.AudioAttributes;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
|
|
||||||
|
|
||||||
import static android.content.Context.NOTIFICATION_SERVICE;
|
|
||||||
|
|
||||||
public class NotificationHelper {
|
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
|
|
||||||
public static String BRouterNotificationChannel1 = "brouter_channel_01";
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private int NOTIFICATION_ID = 111;
|
|
||||||
private Notification mNotification;
|
|
||||||
private NotificationManager mNotificationManager;
|
|
||||||
private PendingIntent mContentIntent;
|
|
||||||
private CharSequence mContentTitle;
|
|
||||||
|
|
||||||
public NotificationHelper(Context context) {
|
|
||||||
if (DEBUG) Log.d("NH", "init ");
|
|
||||||
mContext = context;
|
|
||||||
createNotificationChannels();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startNotification(Service service) {
|
|
||||||
if (DEBUG) Log.d("NH", "startNotification ");
|
|
||||||
|
|
||||||
mNotification = createNotification("BRouter Download", "Download some files");
|
|
||||||
|
|
||||||
if (service != null) service.startForeground(NOTIFICATION_ID, mNotification);
|
|
||||||
|
|
||||||
mNotificationManager.notify(NOTIFICATION_ID, mNotification);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void progressUpdate(String text) {
|
|
||||||
mNotification = createNotification("BRouter Download", text);
|
|
||||||
mNotification.flags = Notification.FLAG_NO_CLEAR |
|
|
||||||
Notification.FLAG_ONGOING_EVENT;
|
|
||||||
|
|
||||||
mNotificationManager.notify(NOTIFICATION_ID, mNotification);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Notification createNotification(String title, String desc) {
|
|
||||||
|
|
||||||
Intent resultIntent = new Intent(mContext, BInstallerActivity.class);
|
|
||||||
|
|
||||||
Intent notificationIntent = new Intent();
|
|
||||||
mContentIntent = PendingIntent.getActivity(mContext, 0, resultIntent, PendingIntent.FLAG_IMMUTABLE);
|
|
||||||
|
|
||||||
mNotificationManager = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
|
|
||||||
|
|
||||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, BRouterNotificationChannel1);
|
|
||||||
builder.setSmallIcon(android.R.drawable.stat_sys_download)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(desc)
|
|
||||||
.setTicker(desc)
|
|
||||||
.setOngoing(true)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setOnlyAlertOnce(true)
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
|
||||||
.setContentIntent(mContentIntent);
|
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
|
|
||||||
builder.setSmallIcon(android.R.drawable.stat_sys_download)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(desc)
|
|
||||||
.setOnlyAlertOnce(true)
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
|
||||||
.setContentIntent(mContentIntent);
|
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create notification channels
|
|
||||||
*/
|
|
||||||
public void createNotificationChannels() {
|
|
||||||
if (DEBUG) Log.d("NH", "createNotificationChannels ");
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
|
|
||||||
NotificationManager sNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
// Sound channel
|
|
||||||
CharSequence name = "BRouter Download";
|
|
||||||
// The user-visible description of the channel.
|
|
||||||
String description = "BRouter Download Channel"; //getString(R.string.channel_description);
|
|
||||||
|
|
||||||
NotificationChannel channel = new NotificationChannel(BRouterNotificationChannel1, name, NotificationManager.IMPORTANCE_LOW);
|
|
||||||
channel.setDescription(description);
|
|
||||||
AudioAttributes att = new AudioAttributes.Builder()
|
|
||||||
.setUsage(AudioAttributes.USAGE_UNKNOWN)
|
|
||||||
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
|
|
||||||
.build();
|
|
||||||
channel.setSound(null, null);
|
|
||||||
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
|
||||||
|
|
||||||
sNotificationManager.createNotificationChannel(channel);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopNotification() {
|
|
||||||
if (DEBUG) Log.d("NH", "stopNotification ");
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
mNotificationManager.deleteNotificationChannel(BRouterNotificationChannel1);
|
|
||||||
}
|
|
||||||
mNotificationManager.cancel(NOTIFICATION_ID);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue