From 6e0db8691c2a2cc0d0e22aba2c8da07d5cceae37 Mon Sep 17 00:00:00 2001 From: afischerdev Date: Tue, 3 Aug 2021 12:49:33 +0200 Subject: [PATCH] android 11 part 2 --- brouter-routing-app/build.gradle | 2 +- .../src/main/AndroidManifest.xml | 16 +- .../src/main/assets/segments4.zip | Bin 583 -> 1050 bytes .../src/main/assets/serverconfig.txt | 16 + .../src/main/ic_launcher-playstore.png | Bin 0 -> 23640 bytes brouter-routing-app/src/main/icon_brouter.svg | 1 + .../btools/routingapp/BInstallerActivity.java | 40 ++ .../btools/routingapp/BInstallerView.java | 283 ++------- .../java/btools/routingapp/BRouterView.java | 85 ++- .../btools/routingapp/DownloadService.java | 544 ++++++++++++++++++ .../btools/routingapp/NotificationHelper.java | 135 +++++ .../res/drawable/ic_launcher_background.xml | 40 ++ .../res/drawable/ic_launcher_foreground.xml | 24 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2381 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4640 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1611 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2912 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3198 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6487 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5170 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10184 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 7125 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 14674 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 26 files changed, 966 insertions(+), 232 deletions(-) create mode 100644 brouter-routing-app/src/main/assets/serverconfig.txt create mode 100644 brouter-routing-app/src/main/ic_launcher-playstore.png create mode 100644 brouter-routing-app/src/main/icon_brouter.svg create mode 100644 brouter-routing-app/src/main/java/btools/routingapp/DownloadService.java create mode 100644 brouter-routing-app/src/main/java/btools/routingapp/NotificationHelper.java create mode 100644 brouter-routing-app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 brouter-routing-app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 brouter-routing-app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 brouter-routing-app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 brouter-routing-app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 brouter-routing-app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 brouter-routing-app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 brouter-routing-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 brouter-routing-app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 brouter-routing-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 brouter-routing-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 brouter-routing-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/brouter-routing-app/build.gradle b/brouter-routing-app/build.gradle index 677ed19..5ec912e 100644 --- a/brouter-routing-app/build.gradle +++ b/brouter-routing-app/build.gradle @@ -71,7 +71,7 @@ android { dependencies { - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation project(':brouter-mapaccess') implementation project(':brouter-core') diff --git a/brouter-routing-app/src/main/AndroidManifest.xml b/brouter-routing-app/src/main/AndroidManifest.xml index f5d4713..90eee53 100644 --- a/brouter-routing-app/src/main/AndroidManifest.xml +++ b/brouter-routing-app/src/main/AndroidManifest.xml @@ -8,14 +8,17 @@ + + android:allowBackup="false"> + android:exported="true" + android:screenOrientation="unspecified" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> @@ -24,6 +27,8 @@ + \ No newline at end of file diff --git a/brouter-routing-app/src/main/assets/segments4.zip b/brouter-routing-app/src/main/assets/segments4.zip index dd1813970152b69e578c516b405d4c57d4ce4ac8..c7671fd2a293f68ffffab99965995089f6e3a3c1 100644 GIT binary patch literal 1050 zcmWIWW@Zs#U|`^2kP7-8v}j$}EhR<=(w&0mzlf}KQ zbLOZ1Tx~12=Y+*lf05q-^D|yqUcLDFRZQkrIVPuNyAC^*oz>La88)-=OhxsMU3Tkg zBE|O`|9&0bd~3o)@8$1eHXe@IcEC?jM|#!DKKCkasWUykPKW!>T0c(J>&iRN?wMjf zh5e$_`G2mNGS~OtY^u(f^Fl=G{FTXzayLmTRsKJB@1*yHzQ5Xk*#qF=$uZsEy)Vov z?*K47+nE^{1VQ0hl3$dVo{9+2(n$yNZX58ly=VQ!=Te;6c;wi&m~x2?<~K5zH%!fN zU!f}{a`#HUeNf>Xxm~k$C(8f-zr3uU-&#Y&!hOooeN|GM#X39{o-W~RPi*X*EU(o( zkF%mfAn;>?tH_kK?{8YWZ(1b(A!uS;7uO9<&NIRK62b2l3d=o={#?sknz?{UgGKhd zrP;MNf9osT1jTnGgw2;eH>0{}+5a%duaET_i&HPP^PaJA=xlEgk}b2G{88NbUV-xd z>&z?NRPcPs7y@~tu?3G2HqSX_ZlpGLPA>z&@I#tA^P|xmHc;6w-LmMq`#pXAk zeLKBr)xqQKx}Pu4x^r^PpPX4`+?Q6D#ZTXQR43X0EpOeg&%0|)w|*WY6syZM(rms6WX#m-WrQ3zIaa&6T}gYxU*9m84o% z-NRl6&(~sWZtchUVGBOf`u|FH*X6^st>W@Q7pkO>Hn M0%?0-YGq&m08G5Ixc~qF literal 583 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 literal 0 HcmV?d00001 diff --git a/brouter-routing-app/src/main/icon_brouter.svg b/brouter-routing-app/src/main/icon_brouter.svg new file mode 100644 index 0000000..1f9f5dd --- /dev/null +++ b/brouter-routing-app/src/main/icon_brouter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java b/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java index 52c2c98..8a1c93f 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BInstallerActivity.java @@ -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); } diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BInstallerView.java b/brouter-routing-app/src/main/java/btools/routingapp/BInstallerView.java index 7c707dd..debd00d 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BInstallerView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BInstallerView.java @@ -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 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 downloadList) { + ArrayList 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 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 -} +} diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java index 5c7c13e..18e71f0 100644 --- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java +++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java @@ -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() { diff --git a/brouter-routing-app/src/main/java/btools/routingapp/DownloadService.java b/brouter-routing-app/src/main/java/btools/routingapp/DownloadService.java new file mode 100644 index 0000000..b026a20 --- /dev/null +++ b/brouter-routing-app/src/main/java/btools/routingapp/DownloadService.java @@ -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 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 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; + } + +} diff --git a/brouter-routing-app/src/main/java/btools/routingapp/NotificationHelper.java b/brouter-routing-app/src/main/java/btools/routingapp/NotificationHelper.java new file mode 100644 index 0000000..ddbf4a1 --- /dev/null +++ b/brouter-routing-app/src/main/java/btools/routingapp/NotificationHelper.java @@ -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); + } +} \ No newline at end of file diff --git a/brouter-routing-app/src/main/res/drawable/ic_launcher_background.xml b/brouter-routing-app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..7c8c867 --- /dev/null +++ b/brouter-routing-app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + diff --git a/brouter-routing-app/src/main/res/drawable/ic_launcher_foreground.xml b/brouter-routing-app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2393404 --- /dev/null +++ b/brouter-routing-app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/brouter-routing-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/brouter-routing-app/src/main/res/mipmap-hdpi/ic_launcher.png b/brouter-routing-app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..cea3d79bb1f11cb00ee92c833f82827707c8bf3f GIT binary patch literal 2381 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 JPDHLkV1m~O^9}$2 literal 0 HcmV?d00001 diff --git a/brouter-routing-app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/brouter-routing-app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..1266e2a8d7f58516bb2e2d9287e726ebe6f7a694 GIT binary patch literal 2912 zcmV-m3!n6fP)(KasV(<}Y^^s0M(I+e0VuXx&{RXyv~DStuWGrq$*YC~+XjnKzi z5rR|Cp6Mv}DEIa1l`=x|IRW%&6&8cGA#KrzPA7X$s*hnSEY8_;Ur$3ouU7e!5ow*W zpWvm1=r#a{_$H$hIhojp~s=dvgU8B;TL{nJv!FrC@)NKO-0h54t;RU)0s*uN86>6=B?y zPSsrJd{UXiU;>1=8+95!eSb7>|HUWsMK-2j9NJnc+X*$wQF6y-)1&RIJt9b2qYXz2 zLlK~q<$$;IT;ATzc08G#N|Bur2nP%$lF*>2D+m&DqJ^|{MiYEyP36q4JX<>>w)Ybd=(KmHs215~m%cr-qBX9rNJX?{C zIp8di=m1$&_5mShqot`^QzJuTOJbj4C<2mioClX_V|n|~J)etg%z<%gR2A2bc$Ety z`3*v)Dw|J?o}~vkn@I6QT5SAncfL!wWz$O?3s-hDg%SBhF}**cCa~Z1E;(ake6z&?XLU#U;=cS8jvT3Lwdk^zEdLsuLccvQYHIA<+JFBGY-6f zoSZ~QUAN+2g9&JpXVSP8b|@0y=R)6C#D&7u(?|F^oQ0_EpFl~}VQ4D84{fzsBJD%i@1=AoY zz?0Tta<*2d!QLew!fLL5`$Btixe*_uQAlp6H*J@3bR#Hp<3u*50wN>B=u%2cV*KR~ z$%*gTU;;2S82S7&KF~o%3XjE1048xwb^;}jp-~wZ0@r=lz(za6Q5r+(PhRVxyQ9X) zFNREQQY7zNcISKPFyaKXHdp-P&!>(#@&W<_zns$9AsaA>ammaN^Wi&DWM8B2P4|Ij zMG+`6VE^{wOH`_W@mp916bQ%M;2C{|17+H_#bCJI^^bq8pi(tZvM{ zD&Z99yQBr+Z;dQpO*oII%(+96l~PfZJg|ULUO>?g{?OfOI0j1z!1qXkpRKHGps31* zO^$|T6>*G&5^i+DKA3%JbO7CJOgSJo+{lUxQ!)tWcPV%7C^53A;874~gdeCx#|fc; zl1oSEhz%q_nSGtwW{_M^lVrws_b!EjD|eXtl!Vf??~Y0eD86`*hO7zsemqKaYii*^ zV(dxeY;=@}jy|)LH2M!3OC9Ef0&oY`afxV7Ky%qcYKsYt$&T+j)iMa(yM?!Rx1R)+ z`424*R-tB(47 z-jAX>2X=luo7!Ve1Z;5ubwk;p0vM-?(hL>hIvEM`+*ux^Cf_-RF(ws8Mgrna^6!Pq zs3ih$bxBLOKyPEL-Nj>mpd(2;fPj87`u$yG))V5QF?_6yu9fV1ws`U4S*^|GPiP~P zE2U8gkt9Qc%~fgSRyCcDBmzgaI_oB_V>yr=yagHxZqauP%@rx&@8(R&VK7BC=Az5l8Xf z^QM67`&Mwmb)HCozN_v9t~{+x<-Y|59oUWB5)%`pKWwqWiLg$*6BC7NE>0gVVYqQs zTt7~o3lV#08ys*V*(5%M*- zZ1#7O{U-iea#5*W)^b$qj?np;Q03AVhyPN`_P3s4O zmfSCBJB>-5f&5Dxz~n~>ImiV$S@dxi3zrW#Rde!k9+Yx3L8nx>GQA0~u)#jF((jZL z4s(%<*|;}XxE*>7fn$2=&8$vxK%*iINhLaJ3Zma9Xrz(P;8$chLXqz2(Ij z8k`MWpkFD^AyZ>-XhX*cbLW}+8{lB%hp?B6(o>=wn%juGgdqBWd_a93?6Z3+vLRpTGyg>dl7Q|$cz7Q@umvq2Dh=G82o0BL>vef+Su4ETd`uPn}>(1Cjy`G9oBI+Xp3#= ztx9w-dz%Gk1Xl`@aHF|AVY7q(|6w8re8zV;%A@fng>8l-&i@ZiUCR`LiRy9y0000< KMNUMnLSTZKXm@D< literal 0 HcmV?d00001 diff --git a/brouter-routing-app/src/main/res/mipmap-xhdpi/ic_launcher.png b/brouter-routing-app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f71fcae781936761956fa4ca24a2579650e40d6e GIT binary patch literal 3198 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 literal 0 HcmV?d00001 diff --git a/brouter-routing-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/brouter-routing-app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..9648664356229d2ac9016684e87d43cd3f5967db GIT binary patch literal 6487 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 V*}F?mVlR+HU;Ca`t%iNX{{Seovr+&6 literal 0 HcmV?d00001 diff --git a/brouter-routing-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/brouter-routing-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..9ba382b763200fc3e49551cd4e29341f67ac2670 GIT binary patch literal 10184 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 d#N#VwKE_`gI&!74xZ^s2ysXO8av76=e*rl(T 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