From 88fa7a63ceb27258676c0c5ab5ab4afdae00a461 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 18 Feb 2016 13:58:10 +0100 Subject: Workaround broken file manager implementation in Android 6.0 In an ideal world, application developers would read the documentation and realize that the *calling* app needs to ensure that the target app can read the URI (e.g. by GRANT_PERMISSION) but ES file explorer (and from user report the internal file manager of cyanogenmod?!) call OpenVPN for Android with a file:// URI which OpenVPN for Android cannot read without SD card permission. Always to try request SD card permission on file:// urls... --- .../blinkt/openvpn/activities/ConfigConverter.java | 145 +++++++++++++-------- .../de/blinkt/openvpn/activities/FileSelect.java | 11 +- 2 files changed, 98 insertions(+), 58 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/activities/ConfigConverter.java b/main/src/main/java/de/blinkt/openvpn/activities/ConfigConverter.java index 4f698008..d89b6291 100644 --- a/main/src/main/java/de/blinkt/openvpn/activities/ConfigConverter.java +++ b/main/src/main/java/de/blinkt/openvpn/activities/ConfigConverter.java @@ -15,6 +15,7 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; @@ -67,7 +68,8 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, private static final int RESULT_INSTALLPKCS12 = 7; private static final int CHOOSE_FILE_OFFSET = 1000; public static final String VPNPROFILE = "vpnProfile"; - private static final int PERMISSION_REQUEST = 37231; + private static final int PERMISSION_REQUEST_EMBED_FILES = 37231; + private static final int PERMISSION_REQUEST_READ_URL = PERMISSION_REQUEST_EMBED_FILES+1; private VpnProfile mResult; @@ -80,19 +82,20 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, private String mEmbeddedPwFile; private Vector mLogEntries = new Vector<>(); private String mCrlFileName; + private Uri mSourceUri; @Override public void onClick(View v) { if (v.getId() == R.id.fab_save) userActionSaveProfile(); if (v.getId() == R.id.permssion_hint && Build.VERSION.SDK_INT == Build.VERSION_CODES.M) - doRequestSDCardPermission(); + doRequestSDCardPermission(PERMISSION_REQUEST_EMBED_FILES); } @TargetApi(Build.VERSION_CODES.M) - private void doRequestSDCardPermission() { - requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST); + private void doRequestSDCardPermission(int requestCode) { + requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, requestCode); } @Override @@ -108,8 +111,13 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, i++; } - if (requestCode == PERMISSION_REQUEST) + if (requestCode == PERMISSION_REQUEST_EMBED_FILES) embedFiles(null); + + else if (requestCode == PERMISSION_REQUEST_READ_URL) { + if(mSourceUri!=null) + doImportUri(mSourceUri); + } } @Override @@ -163,6 +171,8 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, outState.putIntArray("fileselects", fileselects); outState.putString("pwfile", mEmbeddedPwFile); outState.putString("crlfile", mCrlFileName); + + outState.putParcelable("mSourceUri", mSourceUri); } @Override @@ -597,6 +607,7 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, mAliasName = savedInstanceState.getString("mAliasName"); mEmbeddedPwFile = savedInstanceState.getString("pwfile"); mCrlFileName = savedInstanceState.getString("crlfile"); + mSourceUri = savedInstanceState.getParcelable("mSourceUri"); if (savedInstanceState.containsKey("logentries")) { //noinspection ConstantConditions @@ -616,69 +627,91 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, final android.content.Intent intent = getIntent(); if (intent != null) { - final android.net.Uri data = intent.getData(); - if (data != null) { - //log(R.string.import_experimental); - log(R.string.importing_config, data.toString()); - try { - String possibleName = null; - if ((data.getScheme() != null && data.getScheme().equals("file")) || - (data.getLastPathSegment() != null && - (data.getLastPathSegment().endsWith(".ovpn") || - data.getLastPathSegment().endsWith(".conf"))) - ) { - possibleName = data.getLastPathSegment(); - if (possibleName.lastIndexOf('/') != -1) - possibleName = possibleName.substring(possibleName.lastIndexOf('/') + 1); + doImportIntent(intent); - } + // We parsed the intent, relay on saved instance for restoring + setIntent(null); + } - mPathsegments = data.getPathSegments(); - Cursor cursor = null; - cursor = getContentResolver().query(data, null, null, null, null); + } - try { + private void doImportIntent(Intent intent) { + final Uri data = intent.getData(); + if (data != null) { + mSourceUri = data; + doImportUri(data); + } + } - if (cursor != null && cursor.moveToFirst()) { - int columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + private void doImportUri(Uri data) { + //log(R.string.import_experimental); + log(R.string.importing_config, data.toString()); + try { + String possibleName = null; + if ((data.getScheme() != null && data.getScheme().equals("file")) || + (data.getLastPathSegment() != null && + (data.getLastPathSegment().endsWith(".ovpn") || + data.getLastPathSegment().endsWith(".conf"))) + ) { + possibleName = data.getLastPathSegment(); + if (possibleName.lastIndexOf('/') != -1) + possibleName = possibleName.substring(possibleName.lastIndexOf('/') + 1); - if (columnIndex != -1) { - String displayName = cursor.getString(columnIndex); - if (displayName != null) - possibleName = displayName; - } - columnIndex = cursor.getColumnIndex("mime_type"); - if (columnIndex != -1) { - log("Opening Mime TYPE: " + cursor.getString(columnIndex)); - } - } - } finally { - if (cursor != null) - cursor.close(); - } - if (possibleName != null) { - possibleName = possibleName.replace(".ovpn", ""); - possibleName = possibleName.replace(".conf", ""); + } + + mPathsegments = data.getPathSegments(); + + Cursor cursor = null; + cursor = getContentResolver().query(data, null, null, null, null); + + try { + + if (cursor != null && cursor.moveToFirst()) { + int columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + + if (columnIndex != -1) { + String displayName = cursor.getString(columnIndex); + if (displayName != null) + possibleName = displayName; } - try { - InputStream is = getContentResolver().openInputStream(data); - doImport(is, possibleName); - } catch (NetworkOnMainThreadException nom) { - throw new RuntimeException("Network on Main: + " + data); + columnIndex = cursor.getColumnIndex("mime_type"); + if (columnIndex != -1) { + log("Opening Mime TYPE: " + cursor.getString(columnIndex)); } - - } catch (FileNotFoundException e) { - log(R.string.import_content_resolve_error); - } catch (SecurityException se) { - log(R.string.import_content_resolve_error + ":" + se.getLocalizedMessage()); } + } finally { + if (cursor != null) + cursor.close(); + } + if (possibleName != null) { + possibleName = possibleName.replace(".ovpn", ""); + possibleName = possibleName.replace(".conf", ""); + } + try { + InputStream is = getContentResolver().openInputStream(data); + doImport(is, possibleName); + } catch (NetworkOnMainThreadException nom) { + throw new RuntimeException("Network on Main: + " + data); } - // We parsed the intent, relay on saved instance for restoring - setIntent(null); + } catch (FileNotFoundException | SecurityException se) { + log(R.string.import_content_resolve_error + ":" + se.getLocalizedMessage()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + checkMarschmallowFileImportError(data); } + } + @TargetApi(Build.VERSION_CODES.M) + private void checkMarschmallowFileImportError(Uri data) { + // Permission already granted, not the source of the error + if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) + return; + + // We got a file:/// URL and have no permission to read it. Technically an error of the calling app since + // it makes an assumption about other apps being able to read the url but well ... + if (data !=null && "file".equals(data.getScheme())) + doRequestSDCardPermission(PERMISSION_REQUEST_READ_URL); } @@ -686,8 +719,6 @@ public class ConfigConverter extends BaseActivity implements FileSelectCallback, @Override protected void onStart() { super.onStart(); - - } private void log(String logmessage) { diff --git a/main/src/main/java/de/blinkt/openvpn/activities/FileSelect.java b/main/src/main/java/de/blinkt/openvpn/activities/FileSelect.java index a3301399..b0b94e66 100644 --- a/main/src/main/java/de/blinkt/openvpn/activities/FileSelect.java +++ b/main/src/main/java/de/blinkt/openvpn/activities/FileSelect.java @@ -27,6 +27,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.util.Base64; +import android.widget.Toast; import de.blinkt.openvpn.R; import de.blinkt.openvpn.VpnProfile; @@ -100,10 +101,18 @@ public class FileSelect extends BaseActivity { private void checkPermission() { if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST); - } } + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + if (grantResults[0] == PackageManager.PERMISSION_DENIED) { + setResult(RESULT_CANCELED); + finish(); + } + } public boolean showClear() { if(mData == null || mData.equals("")) -- cgit v1.2.3