show notification when backup is done

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/ExportBackupService.java | 59 
src/main/java/eu/siacs/conversations/utils/Compatibility.java          | 18 
src/main/res/values/strings.xml                                        |  4 
3 files changed, 78 insertions(+), 3 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/ExportBackupService.java 🔗

@@ -2,12 +2,14 @@ package eu.siacs.conversations.services;
 
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
 import android.os.IBinder;
 import android.support.v4.app.NotificationCompat;
 import android.util.Log;
@@ -55,6 +57,32 @@ public class ExportBackupService extends Service {
     private List<Account> mAccounts;
     private NotificationManager notificationManager;
 
+    private static List<Intent> getPossibleFileOpenIntents(final Context context, final String path) {
+
+        //http://www.openintents.org/action/android-intent-action-view/file-directory
+        //do not use 'vnd.android.document/directory' since this will trigger system file manager
+        Intent openIntent = new Intent(Intent.ACTION_VIEW);
+        openIntent.addCategory(Intent.CATEGORY_DEFAULT);
+        if (Compatibility.runsAndTargetsTwentyFour(context)) {
+            openIntent.setType("resource/folder");
+        } else {
+            openIntent.setDataAndType(Uri.parse("file://"+path),"resource/folder");
+        }
+        openIntent.putExtra("org.openintents.extra.ABSOLUTE_PATH", path);
+
+        Intent amazeIntent = new Intent(Intent.ACTION_VIEW);
+        amazeIntent.setDataAndType(Uri.parse("com.amaze.filemanager:" + path), "resource/folder");
+
+        //will open a file manager at root and user can navigate themselves
+        Intent systemFallBack = new Intent(Intent.ACTION_VIEW);
+        systemFallBack.addCategory(Intent.CATEGORY_DEFAULT);
+        systemFallBack.setData(Uri.parse("content://com.android.externalstorage.documents/root/primary"));
+
+        return Arrays.asList(openIntent, amazeIntent, systemFallBack);
+
+
+    }
+
     private static void accountExport(SQLiteDatabase db, String uuid, PrintWriter writer) {
         final StringBuilder builder = new StringBuilder();
         final Cursor accountCursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", new String[]{uuid}, null, null, null);
@@ -175,9 +203,12 @@ public class ExportBackupService extends Service {
     public int onStartCommand(Intent intent, int flags, int startId) {
         if (running.compareAndSet(false, true)) {
             new Thread(() -> {
-                export();
+                final boolean success = export();
                 stopForeground(true);
                 running.set(false);
+                if (success) {
+                    notifySuccess();
+                }
                 stopSelf();
             }).start();
             return START_STICKY;
@@ -209,7 +240,7 @@ public class ExportBackupService extends Service {
         }
     }
 
-    private void export() {
+    private boolean export() {
         NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
         mBuilder.setContentTitle(getString(R.string.notification_create_backup_title))
                 .setSmallIcon(R.drawable.ic_archive_white_24dp)
@@ -258,11 +289,35 @@ public class ExportBackupService extends Service {
                 Log.d(Config.LOGTAG, "written backup to " + file.getAbsoluteFile());
                 count++;
             }
+            return true;
         } catch (Exception e) {
             Log.d(Config.LOGTAG, "unable to create backup ", e);
+            return false;
         }
     }
 
+    private void notifySuccess() {
+        final String path = FileBackend.getBackupDirectory(this);
+
+        PendingIntent pendingIntent = null;
+
+        for (Intent intent : getPossibleFileOpenIntents(this, path)) {
+            if (intent.resolveActivityInfo(getPackageManager(), 0) != null) {
+                pendingIntent = PendingIntent.getActivity(this, 189, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+                break;
+            }
+        }
+
+        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
+        mBuilder.setContentTitle(getString(R.string.notification_backup_created_title))
+                .setContentText(getString(R.string.notification_backup_created_subtitle, path))
+                .setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.notification_backup_created_subtitle, FileBackend.getBackupDirectory(this))))
+                .setAutoCancel(true)
+                .setContentIntent(pendingIntent)
+                .setSmallIcon(R.drawable.ic_archive_white_24dp);
+        notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
+    }
+
     @Override
     public IBinder onBind(Intent intent) {
         return null;

src/main/java/eu/siacs/conversations/utils/Compatibility.java 🔗

@@ -42,6 +42,10 @@ public class Compatibility {
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
     }
 
+    public static boolean runsTwentyFour() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
+    }
+
     public static boolean twentyEight() {
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
     }
@@ -64,10 +68,24 @@ public class Compatibility {
         }
     }
 
+    private static boolean targetsTwentyFour(Context context) {
+        try {
+            final PackageManager packageManager = context.getPackageManager();
+            final ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
+            return applicationInfo == null || applicationInfo.targetSdkVersion >= 24;
+        } catch (PackageManager.NameNotFoundException | RuntimeException e) {
+            return true; //when in doubt…
+        }
+    }
+
     public static boolean runsAndTargetsTwentySix(Context context) {
         return runsTwentySix() && targetsTwentySix(context);
     }
 
+    public static boolean runsAndTargetsTwentyFour(Context context) {
+        return runsTwentyFour() && targetsTwentyFour(context);
+    }
+
     public static boolean keepForegroundService(Context context) {
         return runsAndTargetsTwentySix(context) || getBooleanPreference(context, SettingsActivity.KEEP_FOREGROUND_SERVICE, R.bool.enable_foreground_service);
     }

src/main/res/values/strings.xml 🔗

@@ -317,8 +317,10 @@
     <string name="pref_keep_foreground_service">Keep service in foreground</string>
     <string name="pref_keep_foreground_service_summary">Prevents the operating system from killing your connection</string>
     <string name="pref_create_backup">Create backup</string>
-    <string name="pref_create_backup_summary">Write backup files to %s</string>
+    <string name="pref_create_backup_summary">Backup files will be stored in %s</string>
     <string name="notification_create_backup_title">Creating backup files</string>
+    <string name="notification_backup_created_title">Your backup has been created</string>
+    <string name="notification_backup_created_subtitle">The backup files have been stored in %s</string>
     <string name="restoring_backup">Restoring backup</string>
     <string name="notification_restored_backup_title">Your backup has been restored</string>
     <string name="notification_restored_backup_subtitle">Do not forget to enable the account.</string>