Merge branch 'master' of https://github.com/Fenisu/Conversations into Fenisu-master

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/Config.java                             |  2 
src/main/java/eu/siacs/conversations/persistance/FileBackend.java            | 38 
src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java |  2 
src/main/java/eu/siacs/conversations/services/ExportLogsService.java         |  2 
src/main/java/eu/siacs/conversations/ui/ConversationActivity.java            | 13 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java            |  3 
src/main/java/eu/siacs/conversations/ui/SettingsActivity.java                | 74 
src/main/java/eu/siacs/conversations/ui/SettingsFragment.java                | 12 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java          | 10 
src/main/res/values/strings.xml                                              |  4 
src/main/res/xml/file_paths.xml                                              |  3 
src/main/res/xml/preferences.xml                                             | 11 
12 files changed, 150 insertions(+), 24 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/Config.java πŸ”—

@@ -97,6 +97,8 @@ public final class Config {
 
 	public static final boolean X509_VERIFICATION = false; //use x509 certificates to verify OMEMO keys
 
+	public static final boolean ONLY_INTERNAL_STORAGE = true; //use internal storage instead of sdcard to save attachments
+
 	public static final boolean IGNORE_ID_REWRITE_IN_MUC = true;
 
 	public static final boolean PARSE_REAL_JID_FROM_MUC_MAM = false; //dangerous if server doesn’t filter

src/main/java/eu/siacs/conversations/persistance/FileBackend.java πŸ”—

@@ -152,14 +152,26 @@ public class FileBackend {
 		return true;
 	}
 
-	public static String getConversationsFileDirectory() {
-		return  Environment.getExternalStorageDirectory().getAbsolutePath()+"/Conversations/";
+	public String getConversationsFileDirectory() {
+		if (Config.ONLY_INTERNAL_STORAGE) {
+			return mXmppConnectionService.getFilesDir().getAbsolutePath() + "/Files/";
+		} else {
+			return Environment.getExternalStorageDirectory().getAbsolutePath() + "/Conversations/";
+		}
+	}
+
+	public String getConversationsImageDirectory() {
+		if (Config.ONLY_INTERNAL_STORAGE) {
+			return mXmppConnectionService.getFilesDir().getAbsolutePath()+"/Pictures/";
+		} else {
+			return Environment.getExternalStoragePublicDirectory(
+					Environment.DIRECTORY_PICTURES).getAbsolutePath()
+					+ "/Conversations/";
+		}
 	}
 
-	public static String getConversationsImageDirectory() {
-		return Environment.getExternalStoragePublicDirectory(
-				Environment.DIRECTORY_PICTURES).getAbsolutePath()
-			+ "/Conversations/";
+	public static String getConversationsLogsDirectory() {
+		return  Environment.getExternalStorageDirectory().getAbsolutePath()+"/Conversations/";
 	}
 
 	public Bitmap resize(Bitmap originalBitmap, int size) {
@@ -451,9 +463,14 @@ public class FileBackend {
 	}
 
 	public Uri getTakePhotoUri() {
-		File file = new File(getTakePhotoPath()+"IMG_" + this.IMAGE_DATE_FORMAT.format(new Date()) + ".jpg");
+		File file;
+		if (Config.ONLY_INTERNAL_STORAGE) {
+			file = new File(mXmppConnectionService.getCacheDir().getAbsolutePath(), "Camera/IMG_" + this.IMAGE_DATE_FORMAT.format(new Date()) + ".jpg");
+		} else {
+			file = new File(getTakePhotoPath() + "IMG_" + this.IMAGE_DATE_FORMAT.format(new Date()) + ".jpg");
+		}
 		file.getParentFile().mkdirs();
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || Config.ONLY_INTERNAL_STORAGE) {
 			return getUriForFile(mXmppConnectionService,file);
 		} else {
 			return Uri.fromFile(file);
@@ -466,7 +483,7 @@ public class FileBackend {
 	}
 
 	public static Uri getIndexableTakePhotoUri(Uri original) {
-		if ("file".equals(original.getScheme())) {
+		if (Config.ONLY_INTERNAL_STORAGE || "file".equals(original.getScheme())) {
 			return original;
 		} else {
 			List<String> segments = original.getPathSegments();
@@ -712,8 +729,7 @@ public class FileBackend {
 	}
 
 	public Uri getJingleFileUri(Message message) {
-		File file = getFile(message);
-		return Uri.parse("file://" + file.getAbsolutePath());
+		return getUriForFile(mXmppConnectionService,getFile(message));
 	}
 
 	public void updateFileParams(Message message) {

src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java πŸ”—

@@ -55,7 +55,7 @@ public class AbstractConnectionManager {
 	}
 
 	public boolean hasStoragePermission() {
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+		if (!Config.ONLY_INTERNAL_STORAGE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 			return mXmppConnectionService.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
 		} else {
 			return true;

src/main/java/eu/siacs/conversations/services/ExportLogsService.java πŸ”—

@@ -26,7 +26,7 @@ import eu.siacs.conversations.xmpp.jid.Jid;
 public class ExportLogsService extends Service {
 
 	private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
-	private static final String DIRECTORY_STRING_FORMAT = FileBackend.getConversationsFileDirectory() + "/logs/%s";
+	private static final String DIRECTORY_STRING_FORMAT = FileBackend.getConversationsLogsDirectory() + "/logs/%s";
 	private static final String MESSAGE_STRING_FORMAT = "(%s) %s: %s\n";
 	private static final int NOTIFICATION_ID = 1;
 	private static AtomicBoolean running = new AtomicBoolean(false);

src/main/java/eu/siacs/conversations/ui/ConversationActivity.java πŸ”—

@@ -497,6 +497,7 @@ public class ConversationActivity extends XmppActivity
 					case ATTACHMENT_CHOICE_TAKE_PHOTO:
 						Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
 						intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+						intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 						intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
 						intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
 						mPendingImageUris.clear();
@@ -551,7 +552,7 @@ public class ConversationActivity extends XmppActivity
 
 	public void attachFile(final int attachmentChoice) {
 		if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) {
-			if (!hasStoragePermission(attachmentChoice)) {
+			if (!Config.ONLY_INTERNAL_STORAGE && !hasStoragePermission(attachmentChoice)) {
 				return;
 			}
 		}
@@ -648,7 +649,7 @@ public class ConversationActivity extends XmppActivity
 	}
 
 	public void startDownloadable(Message message) {
-		if (!hasStoragePermission(ConversationActivity.REQUEST_START_DOWNLOAD)) {
+		if (!Config.ONLY_INTERNAL_STORAGE && !hasStoragePermission(ConversationActivity.REQUEST_START_DOWNLOAD)) {
 			this.mPendingDownloadableMessage = message;
 			return;
 		}
@@ -1417,9 +1418,11 @@ public class ConversationActivity extends XmppActivity
 						attachImageToConversation(getSelectedConversation(), uri);
 						mPendingImageUris.clear();
 					}
-					Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
-					intent.setData(uri);
-					sendBroadcast(intent);
+					if (!Config.ONLY_INTERNAL_STORAGE) {
+						Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+						intent.setData(uri);
+						sendBroadcast(intent);
+					}
 				} else {
 					mPendingImageUris.clear();
 				}

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java πŸ”—

@@ -654,8 +654,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
 			shareIntent.setType("text/plain");
 		} else {
 			shareIntent.putExtra(Intent.EXTRA_STREAM,
-					activity.xmppConnectionService.getFileBackend()
-							.getJingleFileUri(message));
+					activity.xmppConnectionService.getFileBackend().getJingleFileUri(message));
 			shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 			String mime = message.getMimeType();
 			if (mime == null) {

src/main/java/eu/siacs/conversations/ui/SettingsActivity.java πŸ”—

@@ -7,6 +7,7 @@ import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.preference.ListPreference;
@@ -14,8 +15,10 @@ import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceManager;
 import android.preference.PreferenceScreen;
+import android.util.Log;
 import android.widget.Toast;
 
+import java.io.File;
 import java.security.KeyStoreException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -162,6 +165,26 @@ public class SettingsActivity extends XmppActivity implements
 			}
 		});
 
+		if (Config.ONLY_INTERNAL_STORAGE) {
+			final Preference cleanCachePreference = mSettingsFragment.findPreference("clean_cache");
+			cleanCachePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+				@Override
+				public boolean onPreferenceClick(Preference preference) {
+					cleanCache();
+					return true;
+				}
+			});
+
+			final Preference cleanPrivateStoragePreference = mSettingsFragment.findPreference("clean_private_storage");
+			cleanPrivateStoragePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+				@Override
+				public boolean onPreferenceClick(Preference preference) {
+					cleanPrivateStorage();
+					return true;
+				}
+			});
+		}
+
 		final Preference deleteOmemoPreference = mSettingsFragment.findPreference("delete_omemo_identities");
 		deleteOmemoPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
 			@Override
@@ -172,6 +195,57 @@ public class SettingsActivity extends XmppActivity implements
 		});
 	}
 
+	private void cleanCache() {
+		Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+		intent.setData(Uri.parse("package:" + getPackageName()));
+		startActivity(intent);
+	}
+
+	private void cleanPrivateStorage() {
+		cleanPrivatePictures();
+		cleanPrivateFiles();
+	}
+
+	private void cleanPrivatePictures() {
+		try {
+			File dir = new File(getFilesDir().getAbsolutePath(), "/Pictures/");
+			File[] array = dir.listFiles();
+			if (array != null) {
+				for (int b = 0; b < array.length; b++) {
+					String name = array[b].getName().toLowerCase();
+					if (name.equals(".nomedia")) {
+						continue;
+					}
+					if (array[b].isFile()) {
+						array[b].delete();
+					}
+				}
+			}
+		} catch (Throwable e) {
+			Log.e("CleanCache", e.toString());
+		}
+	}
+
+	private void cleanPrivateFiles() {
+		try {
+			File dir = new File(getFilesDir().getAbsolutePath(), "/Files/");
+			File[] array = dir.listFiles();
+			if (array != null) {
+				for (int b = 0; b < array.length; b++) {
+					String name = array[b].getName().toLowerCase();
+					if (name.equals(".nomedia")) {
+						continue;
+					}
+					if (array[b].isFile()) {
+						array[b].delete();
+					}
+				}
+			}
+		} catch (Throwable e) {
+			Log.e("CleanCache", e.toString());
+		}
+	}
+
 	private void deleteOmemoIdentities() {
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		builder.setTitle(R.string.pref_delete_omemo_identities);

src/main/java/eu/siacs/conversations/ui/SettingsFragment.java πŸ”—

@@ -3,6 +3,7 @@ package eu.siacs.conversations.ui;
 import android.app.Dialog;
 import android.os.Bundle;
 import android.preference.Preference;
+import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
 import android.view.View;
@@ -11,6 +12,7 @@ import android.view.ViewParent;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 
 public class SettingsFragment extends PreferenceFragment {
@@ -52,6 +54,16 @@ public class SettingsFragment extends PreferenceFragment {
 
 		// Load the preferences from an XML resource
 		addPreferencesFromResource(R.xml.preferences);
+
+		// Remove from standard preferences if the flag ONLY_INTERNAL_STORAGE is not true
+		if (!Config.ONLY_INTERNAL_STORAGE) {
+			PreferenceCategory mCategory = (PreferenceCategory) findPreference("security_options");
+			Preference mPref1 = findPreference("clean_cache");
+			Preference mPref2 = findPreference("clean_private_storage");
+			mCategory.removePreference(mPref1);
+			mCategory.removePreference(mPref2);
+		}
+
 	}
 
 	@Override

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java πŸ”—

@@ -709,12 +709,16 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
 			mime = "*/*";
 		}
 		Uri uri;
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || Config.ONLY_INTERNAL_STORAGE) {
 			try {
 				uri = FileBackend.getUriForFile(activity, file);
 			} catch (IllegalArgumentException e) {
-				Toast.makeText(activity,activity.getString(R.string.no_permission_to_access_x,file.getAbsolutePath()), Toast.LENGTH_SHORT).show();
-				return;
+				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+					Toast.makeText(activity, activity.getString(R.string.no_permission_to_access_x, file.getAbsolutePath()), Toast.LENGTH_SHORT).show();
+					return;
+				} else {
+					uri = Uri.fromFile(file);
+				}
 			}
 			openIntent.setDataAndType(uri, mime);
 			openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

src/main/res/values/strings.xml πŸ”—

@@ -715,4 +715,8 @@
 	<string name="blindly_trusted_omemo_keys">Blindly trusted OMEMO keys</string>
 	<string name="not_trusted">Untrusted</string>
 	<string name="invalid_barcode">Invalid 2D barcode</string>
+	<string name="pref_clean_cache_summary">Clean cache folder (used by Camera Application)</string>
+	<string name="pref_clean_cache">Clean cache</string>
+	<string name="pref_clean_private_storage">Clean private storage</string>
+	<string name="pref_clean_private_storage_summary">Clean private storage where files are kept (They can be re-downloaded from the server)</string>
 </resources>

src/main/res/xml/file_paths.xml πŸ”—

@@ -1,4 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <paths>
     <external-path name="external" path="/"/>
+    <files-path path="Pictures/" name="pics" />
+    <files-path path="Files/" name="files" />
+    <cache-path path="Camera/" name="cam" />
 </paths>

src/main/res/xml/preferences.xml πŸ”—

@@ -163,7 +163,8 @@
             android:key="expert"
             android:summary="@string/pref_expert_options_summary"
             android:title="@string/pref_expert_options">
-            <PreferenceCategory android:title="@string/pref_security_settings">
+            <PreferenceCategory android:title="@string/pref_security_settings"
+                android:key="security_options">
                 <CheckBoxPreference
                     android:defaultValue="true"
                     android:key="btbv"
@@ -188,6 +189,14 @@
                     android:key="allow_message_correction"
                     android:title="@string/pref_allow_message_correction"
                     android:summary="@string/pref_allow_message_correction_summary"/>
+                <Preference
+                    android:key="clean_cache"
+                    android:summary="@string/pref_clean_cache_summary"
+                    android:title="@string/pref_clean_cache"/>
+                <Preference
+                    android:key="clean_private_storage"
+                    android:summary="@string/pref_clean_private_storage_summary"
+                    android:title="@string/pref_clean_private_storage"/>
                 <Preference
                     android:key="delete_omemo_identities"
                     android:title="@string/pref_delete_omemo_identities"