android 11 part 2

This commit is contained in:
afischerdev 2021-08-03 12:49:33 +02:00
parent 47171e6f44
commit 6e0db8691c
26 changed files with 966 additions and 232 deletions

View file

@ -6,20 +6,42 @@ import java.util.Set;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;
public class BInstallerActivity extends Activity implements OnInitListener {
public static final String DOWNLOAD_ACTION = "btools.routingapp.download";
private static final int DIALOG_CONFIRM_DELETE_ID = 1;
private BInstallerView mBInstallerView;
private PowerManager mPowerManager;
private WakeLock mWakeLock;
private DownloadReceiver myReceiver;
public class DownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("txt")) {
String txt = intent.getStringExtra("txt");
boolean ready = intent.getBooleanExtra("ready", false);
mBInstallerView.setState(txt, ready);
}
}
}
/** Called when the activity is first created. */
@Override
@ -51,6 +73,12 @@ public class BInstallerActivity extends Activity implements OnInitListener {
*/
mWakeLock.acquire();
IntentFilter filter = new IntentFilter();
filter.addAction(DOWNLOAD_ACTION);
myReceiver = new DownloadReceiver();
registerReceiver(myReceiver, filter);
// Start the download manager
mBInstallerView.startInstaller();
}
@ -58,6 +86,18 @@ public class BInstallerActivity extends Activity implements OnInitListener {
@Override
protected void onPause() {
super.onPause();
super.onPause();
mWakeLock.release();
}
@Override
public void onDestroy() {
super.onDestroy();
if (myReceiver != null) unregisterReceiver(myReceiver);
System.exit(0);
}

View file

@ -7,10 +7,12 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Locale;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@ -23,6 +25,7 @@ import android.os.PowerManager;
import android.os.StatFs;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
@ -63,7 +66,7 @@ public class BInstallerView extends View
private File baseDir;
private boolean isDownloading = false;
private volatile boolean downloadCanceled = false;
public static boolean downloadCanceled = false;
private long currentDownloadSize;
private String currentDownloadFile = "";
@ -78,6 +81,9 @@ public class BInstallerView extends View
Paint pnt_1 = new Paint();
Paint pnt_2 = new Paint();
Paint paint = new Paint();
Activity mActivity;
protected String baseNameForTile( int tileIndex )
{
@ -133,6 +139,7 @@ public class BInstallerView extends View
int tidx_min = -1;
int min_size = Integer.MAX_VALUE;
ArrayList<Integer> downloadList = new ArrayList<>();
// prepare download list
for( int ix=0; ix<72; ix++ )
{
@ -142,6 +149,7 @@ public class BInstallerView extends View
if ( ( tileStatus[tidx] & MASK_SELECTED_RD5 ) != 0 )
{
int tilesize = BInstallerSizes.getRd5Size(tidx);
downloadList.add(tidx);
if ( tilesize > 0 && tilesize < min_size )
{
tidx_min = tidx;
@ -150,29 +158,39 @@ public class BInstallerView extends View
}
}
}
if ( tidx_min != -1 )
{
tileStatus[tidx_min] ^= tileStatus[tidx_min] & MASK_SELECTED_RD5;
startDownload( tidx_min );
if (downloadList.size()>0) {
isDownloading = true;
downloadAll(downloadList);
for (Integer i : downloadList) {
tileStatus[i.intValue()] ^= tileStatus[i.intValue()] & MASK_SELECTED_RD5;
}
downloadList.clear();
}
}
private void startDownload( int tileIndex )
{
String namebase = baseNameForTile( tileIndex );
String baseurl = "http://brouter.de/brouter/segments4/";
currentDownloadFile = namebase + ".rd5";
currentDownloadOperation = "Checking";
String url = baseurl + currentDownloadFile;
isDownloading = true;
downloadCanceled = false;
currentDownloadSize = 0;
downloadAction = "Connecting... ";
final DownloadTask downloadTask = new DownloadTask(getContext());
downloadTask.execute( url );
private void downloadAll(ArrayList<Integer> downloadList) {
ArrayList<String> urlparts = new ArrayList<>();
for (Integer i: downloadList) {
urlparts.add(baseNameForTile( i.intValue() ));
}
currentDownloadOperation = "Start download ...";
downloadAction = "";
downloadCanceled = false;
isDownloading = true;
//final DownloadBackground downloadTask = new DownloadBackground(getContext(), urlparts, baseDir);
//downloadTask.execute( );
Intent intent = new Intent(mActivity, DownloadService.class);
intent.putExtra("dir", baseDir.getAbsolutePath()+"/brouter/");
intent.putExtra("urlparts", urlparts);
mActivity.startService(intent);
deleteRawTracks(); // invalidate raw-tracks after data update
}
public void downloadDone( boolean success )
{
isDownloading = false;
@ -184,6 +202,16 @@ public class BInstallerView extends View
invalidate();
}
public void setState(String txt, boolean b) {
currentDownloadOperation = txt;
downloadAction = "";
isDownloading = b;
if (!b) {
scanExistingFiles();
}
invalidate();
}
private int tileIndex( float x, float y )
{
int ix = (int)(72.f * x / bmp.getWidth());
@ -300,6 +328,7 @@ public class BInstallerView extends View
public BInstallerView(Context context) {
super(context);
mActivity = (Activity) context;
DisplayMetrics metrics = new DisplayMetrics();
((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
@ -314,10 +343,15 @@ public class BInstallerView extends View
imgw = (int)(imgwOrig / scaleOrig);
imgh = (int)(imghOrig / scaleOrig);
totalSize = 0;
rd5Tiles = 0;
delTiles = 0;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w,h,oldw,oldh);
}
private void toast( String msg )
@ -390,10 +424,11 @@ public class BInstallerView extends View
{
String sizeHint = currentDownloadSize > 0 ? " (" + ((currentDownloadSize + mb-1)/mb) + " MB)" : "";
paint.setTextSize(30);
canvas.drawText( currentDownloadOperation + " " + currentDownloadFile + sizeHint, 30, (imgh/3)*2-30, paint);
canvas.drawText( currentDownloadOperation, 30, (imgh/3)*2-30, paint);
// canvas.drawText( currentDownloadOperation + " " + currentDownloadFile + sizeHint, 30, (imgh/3)*2-30, paint);
canvas.drawText( downloadAction, 30, (imgh/3)*2, paint);
}
if ( !tilesVisible )
if ( !tilesVisible && !isDownloading)
{
paint.setTextSize(35);
canvas.drawText( "Touch region to zoom in!", 30, (imgh/3)*2, paint);
@ -655,209 +690,7 @@ float tx, ty;
return true;
}
// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> implements ProgressListener {
private Context context;
private PowerManager.WakeLock mWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
@Override
public void updateProgress( String progress )
{
newDownloadAction = progress;
publishProgress( 0 );
}
@Override
public boolean isCanceled()
{
return isDownloadCanceled();
}
@Override
protected String doInBackground(String... sUrls)
{
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
String surl = sUrls[0];
File fname = null;
File tmp_file = null;
try
{
try
{
int slidx = surl.lastIndexOf( "segments4/" );
String name = surl.substring( slidx+10 );
String surlBase = surl.substring( 0, slidx+10 );
fname = new File (baseDir, "brouter/segments4/" + name);
boolean delta = true;
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);
updateProgress( "Connecting.." );
connection = (HttpURLConnection) urlDelta.openConnection();
connection.connect();
// 404 kind of expected here, means there's no delta file
if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND )
{
connection = null;
}
}
if ( connection == null )
{
delta = false;
URL url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
}
// 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();
currentDownloadSize = fileLength;
if ( availableSize >= 0 && fileLength > availableSize ) return "not enough space on sd-card";
currentDownloadOperation = delta ? "Updating" : "Loading";
// 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 (isDownloadCanceled()) {
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 ( delta )
{
updateProgress( "Applying delta.." );
File diffFile = tmp_file;
tmp_file = new File( fname + "_tmp" );
Rd5DiffTool.recoverFromDelta( fname, diffFile, tmp_file, this );
diffFile.delete();
}
if (isDownloadCanceled())
{
return "Canceled!";
}
if ( tmp_file != null )
{
updateProgress( "Verifying integrity.." );
String check_result = PhysicalFile.checkFileIntegrity( tmp_file );
if ( check_result != null ) return check_result;
if ( !tmp_file.renameTo( fname ) )
{
return "Could not rename to " + fname.getAbsolutePath();
}
deleteRawTracks(); // invalidate raw-tracks after data update
}
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
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
mWakeLock.acquire();
}
@Override
protected void onProgressUpdate(Integer... progress) {
if ( !newDownloadAction.equals( downloadAction ) )
{
downloadAction = newDownloadAction;
invalidate();
}
}
@Override
protected void onPostExecute(String result) {
mWakeLock.release();
downloadDone( result == null );
if (result != null)
Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
else
Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
}
} // download task
}
}

View file

@ -4,12 +4,14 @@ 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.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@ -76,7 +78,9 @@ public class BRouterView extends View
private String profileName;
private String sourceHint;
private boolean waitingForSelection = false;
private boolean waitingForMigration = false;
private String rawTrackPath;
private String oldMigrationPath;
private boolean needsViaSelection;
private boolean needsNogoSelection;
@ -124,8 +128,18 @@ public class BRouterView extends View
File brd = new File( baseDir, "brouter" );
if ( brd.isDirectory() )
{
startSetup( baseDir, false );
return;
if (brd.getAbsolutePath().contains("/Android/data/")) {
String message = "(previous basedir " + baseDir + " has to migrate )" ;
( (BRouterActivity) getContext() ).selectBasedir( getStorageDirectories(), guessBaseDir(), message );
waitingForSelection = true;
waitingForMigration = true;
oldMigrationPath = brd.getAbsolutePath();
return;
} else {
startSetup( baseDir, false );
return;
}
}
}
String message = baseDir == null ? "(no basedir configured previously)" : "(previous basedir " + baseDir
@ -202,6 +216,12 @@ public class BRouterView extends View
File inputDir = new File (basedir, "/import");
assertDirectoryExists( "input directory", inputDir, null, version );
// new init is done move old files
if (waitingForMigration) {
moveFolders(oldMigrationPath, basedir + "/brouter");
waitingForMigration = false;
}
int deviceLevel = android.os.Build.VERSION.SDK_INT;
int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
canAccessSdCard = deviceLevel < 23 || targetSdkVersion == 10;
@ -320,6 +340,67 @@ public class BRouterView extends View
waitingForSelection = true;
}
private void moveFolders(String oldMigrationPath, String basedir) {
File oldDir = new File(oldMigrationPath);
File[] oldFiles = oldDir.listFiles();
for (File f: oldFiles) {
if (f.isDirectory()) {
int index = f.getAbsolutePath().lastIndexOf("/");
String tmpdir = basedir + f.getAbsolutePath().substring(index);
moveFolders(f.getAbsolutePath(), tmpdir);
} else {
if ( ! f.getName().startsWith("v1.6")) {
moveFile(oldMigrationPath, f.getName(), basedir);
}
}
}
}
private void moveFile(String inputPath, String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists())
{
dir.mkdirs();
}
in = new FileInputStream(inputPath + "/" + inputFile);
out = new FileOutputStream(outputPath + "/" + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
in = null;
// write the output file
out.flush();
out.close();
out = null;
// delete the original file
new File(inputPath + "/" + inputFile).delete();
}
catch (FileNotFoundException fnfe1) {
Log.e("tag", fnfe1.getMessage());
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
public boolean hasUpToDateLookups()
{

View file

@ -0,0 +1,544 @@
package btools.routingapp;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.net.TrafficStats;
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.os.StatFs;
import android.util.Log;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
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;
String segmenturl = "https://brouter.de/brouter/segments4/";
String lookupurl = "https://brouter.de/brouter/segments4/";
String profilesurl = "https://brouter.de/brouter/segments4/";
String checkLookup = "lookups.dat";
String checkProfiles = "";
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;
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
{
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;
File configFile = new File (dir, "segments4/serverconfig.txt");
if ( configFile.exists() ) {
try {
BufferedReader br = new BufferedReader( new FileReader( configFile ) );
for ( ;; )
{
String line = br.readLine();
if ( line == null ) break;
if ( line.trim().startsWith( "segment_url=" ) ) {
segmenturl = line.substring(12);
}
else if ( line.trim().startsWith( "lookup_url=" ) ) {
lookupurl = line.substring(11);
}
else if ( line.trim().startsWith( "profiles_url=" ) ) {
profilesurl = line.substring(13);
}
else if ( line.trim().startsWith( "check_lookup=" ) ) {
checkLookup = line.substring(13);
}
else if ( line.trim().startsWith( "check_profiles=" ) ) {
checkProfiles = line.substring(15);
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
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 prifles
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 = segmenturl + 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.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.." + surl );
delta = false;
URL url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
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 ( !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 = checkLookup.split(",");
for (String f: sa) {
if (f.length()>0) {
File file = new File(baseDir + "profiles2", f);
checkOrDownloadLookup(f, file);
}
}
sa = checkProfiles.split(",");
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 = lookupurl + fileName;
return downloadScript(url, f);
}
private String checkOrDownloadScript(String fileName, File f) {
String url = profilesurl + 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);
if ( connection == null )
{
URL url = new URL(surl);
connection = (HttpURLConnection) url.openConnection();
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;
}
}

View file

@ -0,0 +1,135 @@
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);
}
}