Merge pull request #364 from zod/essbee-profile-intent

Add intent receiver for profiles

@zod and @EssBee59 
Many thanks for your work.
This commit is contained in:
afischerdev 2021-11-18 10:05:25 +01:00 committed by GitHub
commit 8088b13d63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 337 additions and 52 deletions

View file

@ -16,33 +16,87 @@
android:label="@string/app_name"
android:allowBackup="false"
android:preserveLegacyExternalStorage="true">
<activity android:name=".BRouterActivity"
<activity
android:name=".BRouterActivity"
android:label="@string/app_name"
android:exported="true"
android:screenOrientation="unspecified"
android:screenOrientation="unspecified"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".BInstallerActivity"
<activity
android:name=".BInstallerActivity"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:launchMode="singleTask"
android:exported="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"></activity>
<activity
android:name=".BImportActivity"
android:label="Import Profile"
android:exported="true"
android:theme="@android:style/Theme.NoTitleBar">
<!-- some apps (bluemail) do not recognize the .brf file extention, startactivity+intent is done for attachement with text/plain -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="text/plain" />
</intent-filter>
<!-- general intent to register .brf files -->
<intent-filter
android:label="@string/app_name"
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:host="*" />
<data android:pathPattern=".*\\.brf" />
<data android:pathPattern=".*\\..*\\.brf" />
<data android:pathPattern=".*\\..*\\..*\\.brf" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.brf" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.brf" />
</intent-filter>
<intent-filter
android:label="@string/app_name"
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.brf" />
<data android:pathPattern=".*\\..*\\.brf" />
<data android:pathPattern=".*\\..*\\..*\\.brf" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.brf" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.brf" />
</intent-filter>
</activity>
<service
android:exported="true"
android:name=".BRouterService"
android:enabled="true"
android:process=":brouter_service" />
<service android:name="btools.routingapp.DownloadService"
<service
android:name="btools.routingapp.DownloadService"
android:label="Download Service"
android:icon="@mipmap/ic_launcher"
android:enabled="true"
/>
android:enabled="true" />
</application>
</manifest>

View file

@ -0,0 +1,158 @@
package btools.routingapp;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.text.format.Formatter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class BImportActivity extends Activity {
// profile size is generally < 30 kb, so set max size to 100 kb
private static final int MAX_PROFILE_SIZE = 100000;
private EditText mTextFilename;
private Button mButtonImport;
private String mProfileData;
private EditText mTextProfile;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.import_intent);
mTextFilename = findViewById(R.id.editTextFilename);
mButtonImport = findViewById(R.id.buttonImport);
mButtonImport.setEnabled(false);
mButtonImport.setOnClickListener(view -> importProfile());
mTextProfile = findViewById(R.id.editTextProfile);
Intent intent = getIntent();
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
parseIntent(intent);
}
}
private boolean isBuiltinProfile(String filename) {
String[] builtinProfiles = new ServerConfig(this).getProfiles();
for (String builtinProfile : builtinProfiles) {
if (filename.equals(builtinProfile)) {
return true;
}
}
return false;
}
private boolean isInvalidProfileFilename(String filename) {
return !filename.endsWith(".brf");
}
private void parseIntent(Intent intent) {
if (intent.getData() == null) {
return;
}
StringBuilder resultMessage = new StringBuilder();
Uri dataUri = intent.getData();
// by some apps (bluemail) the file name must be "extracted" from the URI, as example with the following code
// see https://stackoverflow.com/questions/14364091/retrieve-file-path-from-caught-downloadmanager-intent
// URI example ==> dat=content://me.bluemail.mail.attachmentprovider/a2939069-76b5-44e4-8cbd-94485d0fd4ff/cc32b61d-97a6-4871-b67f-945d1d1d43c8/VIEW
String filename = null;
long filesize = 0L;
try (Cursor cursor = this.getContentResolver().query(intent.getData(), new String[]{
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
filesize = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
}
}
// is the file extention ".brf" in the file name
if (filename == null || isInvalidProfileFilename(filename)) {
resultMessage.append("ERROR: File extention must be \".brf\"\n");
displayMessage(resultMessage.toString());
return;
}
if (filesize > MAX_PROFILE_SIZE) {
String errorMessage = String.format("ERROR: File size (%s) exceeds limit (%s)\n",
Formatter.formatFileSize(this, filesize),
Formatter.formatFileSize(this, MAX_PROFILE_SIZE));
displayMessage(errorMessage);
return;
}
try (
InputStream inputStream = getContentResolver().openInputStream(dataUri);
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.getProperty("line.separator"));
line = br.readLine();
}
mProfileData = sb.toString();
} catch (IOException e) {
resultMessage.append(String.format("ERROR: failed to load profile content (%s)", e.getMessage()));
displayMessage(resultMessage.toString());
}
if (!mProfileData.contains("---context:global") || (!mProfileData.contains("---context:way"))) {
resultMessage.append("ERROR: this file is not a valid brouter-profile\n");
displayMessage(resultMessage.toString());
return;
}
mTextFilename.setText(filename);
mTextProfile.setText(mProfileData);
mButtonImport.setEnabled(true);
}
void displayMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
boolean importProfile() {
String filename = mTextFilename.getText().toString();
if (isInvalidProfileFilename(filename)) {
displayMessage("ERROR: File extention must be \".brf\"\n");
return false;
} else if (isBuiltinProfile(filename)) {
displayMessage("ERROR: Built-in profile exists\n");
return false;
}
writeProfile(filename, mProfileData);
return true;
}
void writeProfile(String filename, String profileData) {
File baseDir = ConfigHelper.getBaseDir(this);
try {
File file = new File(baseDir, "brouter/profiles2/" + filename);
FileOutputStream stream = new FileOutputStream(file);
stream.write(profileData.getBytes());
stream.close();
displayMessage("Profile successfully imported");
} catch (IOException e) {
displayMessage(String.format("Profile import failed: %s", e.getMessage()));
}
}
}

View file

@ -11,14 +11,11 @@ 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;
@ -35,11 +32,7 @@ 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/profile2/";
String profilesurl = "https://brouter.de/brouter/profile2/";
String checkLookup = "lookups.dat";
String checkProfiles = "";
private ServerConfig mServerConfig;
private NotificationHelper mNotificationHelper;
private List<String> mUrlList;
@ -78,6 +71,7 @@ public class DownloadService extends Service implements ProgressListener {
public void onCreate() {
if (DEBUG) Log.d("SERVICE", "onCreate");
serviceState = true;
mServerConfig = new ServerConfig(getApplicationContext());
HandlerThread thread = new HandlerThread("ServiceStartArguments", 1);
thread.start();
@ -109,38 +103,6 @@ public class DownloadService extends Service implements ProgressListener {
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);
@ -185,7 +147,7 @@ public class DownloadService extends Service implements ProgressListener {
int count = 1;
int size = mUrlList.size();
for (String part: mUrlList) {
String url = segmenturl + part + ".rd5";
String url = mServerConfig.getSegmentUrl() + part + ".rd5";
if (DEBUG) Log.d("BR", "downlaod " + url);
result = download(count, size, url);
@ -386,7 +348,7 @@ public class DownloadService extends Service implements ProgressListener {
private String checkScripts() {
String[] sa = checkLookup.split(",");
String[] sa = mServerConfig.getLookups();
for (String f: sa) {
if (f.length()>0) {
File file = new File(baseDir + "profiles2", f);
@ -394,7 +356,7 @@ public class DownloadService extends Service implements ProgressListener {
}
}
sa = checkProfiles.split(",");
sa = mServerConfig.getProfiles();
for (String f : sa) {
if (f.length()>0) {
File file = new File(baseDir + "profiles2", f);
@ -410,12 +372,12 @@ public class DownloadService extends Service implements ProgressListener {
}
private String checkOrDownloadLookup(String fileName, File f) {
String url = lookupurl + fileName;
String url = mServerConfig.getLookupUrl() + fileName;
return downloadScript(url, f);
}
private String checkOrDownloadScript(String fileName, File f) {
String url = profilesurl + fileName;
String url = mServerConfig.getProfilesUrl() + fileName;
return downloadScript(url, f);
}

View file

@ -0,0 +1,66 @@
package btools.routingapp;
import android.content.Context;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ServerConfig {
private String mSegmentUrl = "https://brouter.de/brouter/segments4/";
private String mLookupsUrl = "https://brouter.de/brouter/profiles2/";
private String mProfilesUrl = "https://brouter.de/brouter/profiles2/";
private String[] mLookups = new String[]{"lookups.dat"};
private String[] mProfiles = new String[0];
public ServerConfig(Context ctx) {
File configFile = new File(ConfigHelper.getBaseDir(ctx), "/brouter/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=")) {
mSegmentUrl = line.substring(12);
} else if (line.trim().startsWith("lookup_url=")) {
mLookupsUrl = line.substring(11);
} else if (line.trim().startsWith("profiles_url=")) {
mProfilesUrl = line.substring(13);
} else if (line.trim().startsWith("check_lookup=")) {
mLookups = line.substring(13).split(",");
} else if (line.trim().startsWith("check_profiles=")) {
mProfiles = line.substring(15).split(",");
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getSegmentUrl() {
return mSegmentUrl;
}
public String getLookupUrl() {
return mLookupsUrl;
}
public String getProfilesUrl() {
return mProfilesUrl;
}
public String[] getLookups() {
return mLookups;
}
public String[] getProfiles() {
return mProfiles;
}
}

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
tools:context=".BImportActivity">
<Button
android:id="@+id/buttonImport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:text="@string/import_profile"
android:layout_alignParentEnd="true" />
<EditText
android:id="@+id/editTextFilename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:ems="10"
android:hint="@string/profile_filename_example"
android:importantForAutofill="no"
android:inputType="textUri"
android:minHeight="48dp" />
<EditText
android:id="@+id/editTextProfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/buttonImport"
android:layout_below="@id/editTextFilename"
android:ems="8"
android:enabled="false"
android:gravity="start|top"
android:inputType="none"
android:minHeight="48dp"
android:importantForAutofill="no" />
</RelativeLayout>

View file

@ -16,4 +16,6 @@
<resources>
<string name="app_name">BRouter</string>
<string name="import_profile">Import Profile</string>
<string name="profile_filename_example">filename.brf</string>
</resources>