Pārlūkot izejas kodu

Better scroll on new messages & Kotlin

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 5 gadi atpakaļ
vecāks
revīzija
362042e27e

+ 2 - 2
app/build.gradle

@@ -160,7 +160,7 @@ dependencies {
 
     implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
 
-    implementation 'androidx.biometric:biometric:1.0.0-alpha04'
+    implementation 'androidx.biometric:biometric:1.0.0-beta01'
     implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
 
     implementation 'androidx.multidex:multidex:2.0.1'
@@ -212,7 +212,7 @@ dependencies {
     implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
     implementation 'org.apache.commons:commons-lang3:3.9'
     implementation 'com.github.wooplr:Spotlight:1.3'
-    implementation('com.github.mario:chatkit:a7c4f3c9ea', {
+    implementation('com.github.mario:chatkit:a183142049', {
         exclude group: 'com.facebook.fresco'
     })
 

+ 0 - 155
app/src/main/java/com/nextcloud/talk/activities/BaseActivity.java

@@ -1,155 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.nextcloud.talk.activities;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.WindowManager;
-import android.webkit.SslErrorHandler;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import autodagger.AutoInjector;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.events.CertificateEvent;
-import com.nextcloud.talk.utils.SecurityUtils;
-import com.nextcloud.talk.utils.preferences.AppPreferences;
-import com.nextcloud.talk.utils.ssl.MagicTrustManager;
-import com.yarolegovich.lovelydialog.LovelyStandardDialog;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import javax.inject.Inject;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.text.DateFormat;
-import java.util.List;
-
-@AutoInjector(NextcloudTalkApplication.class)
-public class BaseActivity extends AppCompatActivity {
-    private static final String TAG = "BaseActivity";
-
-    @Inject
-    EventBus eventBus;
-
-    @Inject
-    AppPreferences appPreferences;
-
-    @Inject
-    Context context;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (appPreferences.getIsScreenSecured()) {
-            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
-        } else {
-            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
-        }
-
-        if (appPreferences.getIsScreenLocked()) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-                SecurityUtils.createKey(appPreferences.getScreenLockTimeout());
-            }
-        }
-    }
-
-    public void showCertificateDialog(X509Certificate cert, MagicTrustManager magicTrustManager,
-                                      @Nullable SslErrorHandler sslErrorHandler) {
-        DateFormat formatter = DateFormat.getDateInstance(DateFormat.LONG);
-        String validFrom = formatter.format(cert.getNotBefore());
-        String validUntil = formatter.format(cert.getNotAfter());
-
-        String issuedBy = cert.getIssuerDN().toString();
-        String issuedFor;
-
-        try {
-            if (cert.getSubjectAlternativeNames() != null) {
-                StringBuilder stringBuilder = new StringBuilder();
-                for (Object o : cert.getSubjectAlternativeNames()) {
-                    List list = (List) o;
-                    int type = (Integer) list.get(0);
-                    if (type == 2) {
-                        String name = (String) list.get(1);
-                        stringBuilder.append("[").append(type).append("]").append(name).append(" ");
-                    }
-                }
-                issuedFor = stringBuilder.toString();
-            } else {
-                issuedFor = cert.getSubjectDN().getName();
-            }
-
-            @SuppressLint("StringFormatMatches") String dialogText = String.format(getResources()
-                            .getString(R.string.nc_certificate_dialog_text),
-                    issuedBy, issuedFor, validFrom, validUntil);
-
-            new LovelyStandardDialog(this)
-                    .setTopColorRes(R.color.nc_darkRed)
-                    .setNegativeButtonColorRes(R.color.nc_darkRed)
-                    .setPositiveButtonColorRes(R.color.colorPrimaryDark)
-                    .setIcon(R.drawable.ic_security_white_24dp)
-                    .setTitle(R.string.nc_certificate_dialog_title)
-                    .setMessage(dialogText)
-                    .setPositiveButton(R.string.nc_yes, v -> {
-                        magicTrustManager.addCertInTrustStore(cert);
-                        if (sslErrorHandler != null) {
-                            sslErrorHandler.proceed();
-                        }
-                    })
-                    .setNegativeButton(R.string.nc_no, view1 -> {
-                        if (sslErrorHandler != null) {
-                            sslErrorHandler.cancel();
-                        }
-                    })
-                    .show();
-
-        } catch (CertificateParsingException e) {
-            Log.d(TAG, "Failed to parse the certificate");
-        }
-    }
-
-    @Subscribe(threadMode = ThreadMode.MAIN)
-    public void onMessageEvent(CertificateEvent event) {
-        showCertificateDialog(event.getX509Certificate(), event.getMagicTrustManager(), event.getSslErrorHandler());
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        eventBus.register(this);
-    }
-
-    @Override
-    public void onStop() {
-        super.onStop();
-        eventBus.unregister(this);
-    }
-}

+ 148 - 0
app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt

@@ -0,0 +1,148 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.activities
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import android.view.WindowManager
+import android.webkit.SslErrorHandler
+import androidx.appcompat.app.AppCompatActivity
+import autodagger.AutoInjector
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.events.CertificateEvent
+import com.nextcloud.talk.utils.SecurityUtils
+import com.nextcloud.talk.utils.preferences.AppPreferences
+import com.nextcloud.talk.utils.ssl.MagicTrustManager
+import com.yarolegovich.lovelydialog.LovelyStandardDialog
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.security.cert.CertificateParsingException
+import java.security.cert.X509Certificate
+import java.text.DateFormat
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+open class BaseActivity : AppCompatActivity() {
+
+    @Inject
+    lateinit var eventBus: EventBus
+
+    @Inject
+    lateinit var appPreferences: AppPreferences
+
+    @Inject
+    lateinit var context: Context
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+        super.onCreate(savedInstanceState)
+    }
+
+    public override fun onResume() {
+        super.onResume()
+        if (appPreferences.isScreenSecured) {
+            window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
+        } else {
+            window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
+        }
+
+        if (appPreferences.isScreenLocked) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                SecurityUtils.createKey(appPreferences.screenLockTimeout)
+            }
+        }
+    }
+
+    fun showCertificateDialog(cert: X509Certificate, magicTrustManager: MagicTrustManager,
+                              sslErrorHandler: SslErrorHandler?) {
+        val formatter = DateFormat.getDateInstance(DateFormat.LONG)
+        val validFrom = formatter.format(cert.notBefore)
+        val validUntil = formatter.format(cert.notAfter)
+
+        val issuedBy = cert.issuerDN.toString()
+        val issuedFor: String
+
+        try {
+            if (cert.subjectAlternativeNames != null) {
+                val stringBuilder = StringBuilder()
+                for (o in cert.subjectAlternativeNames) {
+                    val list = o as List<*>
+                    val type = list[0] as Int
+                    if (type == 2) {
+                        val name = list[1] as String
+                        stringBuilder.append("[").append(type).append("]").append(name).append(" ")
+                    }
+                }
+                issuedFor = stringBuilder.toString()
+            } else {
+                issuedFor = cert.subjectDN.name
+            }
+
+            @SuppressLint("StringFormatMatches") val dialogText = String.format(resources
+                    .getString(R.string.nc_certificate_dialog_text),
+                    issuedBy, issuedFor, validFrom, validUntil)
+
+            LovelyStandardDialog(this)
+                    .setTopColorRes(R.color.nc_darkRed)
+                    .setNegativeButtonColorRes(R.color.nc_darkRed)
+                    .setPositiveButtonColorRes(R.color.colorPrimaryDark)
+                    .setIcon(R.drawable.ic_security_white_24dp)
+                    .setTitle(R.string.nc_certificate_dialog_title)
+                    .setMessage(dialogText)
+                    .setPositiveButton(R.string.nc_yes) { v ->
+                        magicTrustManager.addCertInTrustStore(cert)
+                        sslErrorHandler?.proceed()
+                    }
+                    .setNegativeButton(R.string.nc_no) { view1 ->
+                        sslErrorHandler?.cancel()
+                    }
+                    .show()
+
+        } catch (e: CertificateParsingException) {
+            Log.d(TAG, "Failed to parse the certificate")
+        }
+
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    fun onMessageEvent(event: CertificateEvent) {
+        showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
+    }
+
+    public override fun onStart() {
+        super.onStart()
+        eventBus.register(this)
+    }
+
+    public override fun onStop() {
+        super.onStop()
+        eventBus.unregister(this)
+    }
+
+    companion object {
+        private val TAG = "BaseActivity"
+    }
+}

+ 0 - 100
app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.java

@@ -1,100 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.nextcloud.talk.activities;
-
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import autodagger.AutoInjector;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.bluelinelabs.conductor.Conductor;
-import com.bluelinelabs.conductor.Router;
-import com.bluelinelabs.conductor.RouterTransaction;
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.controllers.CallController;
-import com.nextcloud.talk.controllers.CallNotificationController;
-import com.nextcloud.talk.events.ConfigurationChangeEvent;
-import com.nextcloud.talk.utils.bundle.BundleKeys;
-import org.greenrobot.eventbus.EventBus;
-
-import javax.inject.Inject;
-
-@AutoInjector(NextcloudTalkApplication.class)
-public class MagicCallActivity extends BaseActivity {
-    private static final String TAG = "MagicCallActivity";
-
-    @Inject
-    EventBus eventBus;
-
-    @BindView(R.id.controller_container)
-    ViewGroup container;
-
-    private Router router;
-
-    private static int getSystemUiVisibility() {
-        int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
-        flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-        return flags;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
-
-        requestWindowFeature(Window.FEATURE_NO_TITLE);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
-                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
-                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
-                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
-        getWindow().getDecorView().setSystemUiVisibility(getSystemUiVisibility());
-
-        setContentView(R.layout.activity_magic_call);
-
-        ButterKnife.bind(this);
-        router = Conductor.attachRouter(this, container, savedInstanceState);
-        router.setPopsLastView(false);
-
-        if (!router.hasRootController()) {
-            if (getIntent().getBooleanExtra(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL(), false)) {
-                router.setRoot(RouterTransaction.with(new CallNotificationController(getIntent().getExtras()))
-                        .pushChangeHandler(new HorizontalChangeHandler())
-                        .popChangeHandler(new HorizontalChangeHandler()));
-            } else {
-                router.setRoot(RouterTransaction.with(new CallController(getIntent().getExtras()))
-                        .pushChangeHandler(new HorizontalChangeHandler())
-                        .popChangeHandler(new HorizontalChangeHandler()));
-            }
-        }
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        eventBus.post(new ConfigurationChangeEvent());
-    }
-}

+ 96 - 0
app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.kt

@@ -0,0 +1,96 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.activities
+
+import android.content.res.Configuration
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import autodagger.AutoInjector
+import butterknife.BindView
+import butterknife.ButterKnife
+import com.bluelinelabs.conductor.Conductor
+import com.bluelinelabs.conductor.Router
+import com.bluelinelabs.conductor.RouterTransaction
+import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.controllers.CallController
+import com.nextcloud.talk.controllers.CallNotificationController
+import com.nextcloud.talk.events.ConfigurationChangeEvent
+import com.nextcloud.talk.utils.bundle.BundleKeys
+
+@AutoInjector(NextcloudTalkApplication::class)
+class MagicCallActivity : BaseActivity() {
+
+    @BindView(R.id.controller_container)
+    lateinit var container: ViewGroup
+
+    private var router: Router? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+
+        requestWindowFeature(Window.FEATURE_NO_TITLE)
+        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN or
+                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
+                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
+        window.decorView.systemUiVisibility = systemUiVisibility
+
+        setContentView(R.layout.activity_magic_call)
+
+        ButterKnife.bind(this)
+        router = Conductor.attachRouter(this, container, savedInstanceState)
+        router!!.setPopsLastView(false)
+
+        if (!router!!.hasRootController()) {
+            if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
+                router!!.setRoot(RouterTransaction.with(CallNotificationController(intent.extras))
+                        .pushChangeHandler(HorizontalChangeHandler())
+                        .popChangeHandler(HorizontalChangeHandler()))
+            } else {
+                router!!.setRoot(RouterTransaction.with(CallController(intent.extras))
+                        .pushChangeHandler(HorizontalChangeHandler())
+                        .popChangeHandler(HorizontalChangeHandler()))
+            }
+        }
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        eventBus.post(ConfigurationChangeEvent())
+    }
+
+    companion object {
+        private val TAG = "MagicCallActivity"
+
+        private val systemUiVisibility: Int
+            get() {
+                var flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
+                flags = flags or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                return flags
+            }
+    }
+}

+ 0 - 175
app/src/main/java/com/nextcloud/talk/activities/MainActivity.java

@@ -1,175 +0,0 @@
-/*
- *
- *   Nextcloud Talk application
- *
- *   @author Mario Danic
- *   Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package com.nextcloud.talk.activities;
-
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import androidx.annotation.RequiresApi;
-import androidx.appcompat.widget.Toolbar;
-import autodagger.AutoInjector;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.bluelinelabs.conductor.Conductor;
-import com.bluelinelabs.conductor.Router;
-import com.bluelinelabs.conductor.RouterTransaction;
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
-import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
-import com.google.android.material.appbar.MaterialToolbar;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.controllers.CallNotificationController;
-import com.nextcloud.talk.controllers.ConversationsListController;
-import com.nextcloud.talk.controllers.LockedController;
-import com.nextcloud.talk.controllers.ServerSelectionController;
-import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
-import com.nextcloud.talk.utils.ConductorRemapping;
-import com.nextcloud.talk.utils.SecurityUtils;
-import com.nextcloud.talk.utils.bundle.BundleKeys;
-import com.nextcloud.talk.utils.database.user.UserUtils;
-import io.requery.Persistable;
-import io.requery.android.sqlcipher.SqlCipherDatabaseSource;
-import io.requery.reactivex.ReactiveEntityStore;
-
-import javax.inject.Inject;
-
-@AutoInjector(NextcloudTalkApplication.class)
-public final class MainActivity extends BaseActivity implements ActionBarProvider {
-    private static final String TAG = "MainActivity";
-
-    @BindView(R.id.toolbar)
-    MaterialToolbar toolbar;
-    @BindView(R.id.controller_container)
-    ViewGroup container;
-
-    @Inject
-    UserUtils userUtils;
-    @Inject
-    ReactiveEntityStore<Persistable> dataStore;
-    @Inject
-    SqlCipherDatabaseSource sqlCipherDatabaseSource;
-
-    private Router router;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.activity_main);
-
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
-        ButterKnife.bind(this);
-
-        setSupportActionBar(toolbar);
-
-        router = Conductor.attachRouter(this, container, savedInstanceState);
-
-        boolean hasDb = true;
-
-        try {
-            sqlCipherDatabaseSource.getWritableDatabase();
-        } catch (Exception exception) {
-            hasDb = false;
-        }
-
-        if (getIntent().hasExtra(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL())) {
-            if (!router.hasRootController()) {
-                router.setRoot(RouterTransaction.with(new ConversationsListController())
-                        .pushChangeHandler(new HorizontalChangeHandler())
-                        .popChangeHandler(new HorizontalChangeHandler()));
-            }
-            onNewIntent(getIntent());
-        } else if (!router.hasRootController()) {
-            if (hasDb) {
-                if (userUtils.anyUserExists()) {
-                    router.setRoot(RouterTransaction.with(new ConversationsListController())
-                            .pushChangeHandler(new HorizontalChangeHandler())
-                            .popChangeHandler(new HorizontalChangeHandler()));
-                } else {
-                    router.setRoot(RouterTransaction.with(new ServerSelectionController())
-                            .pushChangeHandler(new HorizontalChangeHandler())
-                            .popChangeHandler(new HorizontalChangeHandler()));
-                }
-            } else {
-                router.setRoot(RouterTransaction.with(new ServerSelectionController())
-                        .pushChangeHandler(new HorizontalChangeHandler())
-                        .popChangeHandler(new HorizontalChangeHandler()));
-
-            }
-        }
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            checkIfWeAreSecure();
-        }
-    }
-
-
-    @RequiresApi(api = Build.VERSION_CODES.M)
-    public void checkIfWeAreSecure() {
-        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
-        if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) {
-            if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
-                if (router != null && router.getControllerWithTag(LockedController.TAG) == null) {
-                    router.pushController(RouterTransaction.with(new LockedController())
-                            .pushChangeHandler(new VerticalChangeHandler())
-                            .popChangeHandler(new VerticalChangeHandler())
-                            .tag(LockedController.TAG));
-                }
-            }
-        }
-    }
-
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-
-        if (intent.hasExtra(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL())) {
-            if (intent.getBooleanExtra(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL(), false)) {
-                router.pushController(RouterTransaction.with(new CallNotificationController(intent.getExtras()))
-                        .pushChangeHandler(new HorizontalChangeHandler())
-                        .popChangeHandler(new HorizontalChangeHandler()));
-            } else {
-                ConductorRemapping.INSTANCE.remapChatController(router, intent.getLongExtra(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1),
-                        intent.getStringExtra(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()), intent.getExtras(), false);
-                ;
-            }
-        }
-    }
-
-    @Override
-    public void onBackPressed() {
-        if (router.getControllerWithTag(LockedController.TAG) != null) {
-            return;
-        }
-
-        if (!router.handleBack()) {
-            super.onBackPressed();
-        }
-    }
-}

+ 171 - 0
app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt

@@ -0,0 +1,171 @@
+/*
+ *
+ *   Nextcloud Talk application
+ *
+ *   @author Mario Danic
+ *   Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.activities
+
+import android.app.KeyguardManager
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.annotation.RequiresApi
+import autodagger.AutoInjector
+import butterknife.BindView
+import butterknife.ButterKnife
+import com.bluelinelabs.conductor.Conductor
+import com.bluelinelabs.conductor.Router
+import com.bluelinelabs.conductor.RouterTransaction
+import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
+import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
+import com.google.android.material.appbar.MaterialToolbar
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.controllers.CallNotificationController
+import com.nextcloud.talk.controllers.ConversationsListController
+import com.nextcloud.talk.controllers.LockedController
+import com.nextcloud.talk.controllers.ServerSelectionController
+import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
+import com.nextcloud.talk.utils.ConductorRemapping
+import com.nextcloud.talk.utils.SecurityUtils
+import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.nextcloud.talk.utils.database.user.UserUtils
+import io.requery.Persistable
+import io.requery.android.sqlcipher.SqlCipherDatabaseSource
+import io.requery.reactivex.ReactiveEntityStore
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class MainActivity : BaseActivity(), ActionBarProvider {
+
+    @BindView(R.id.toolbar)
+    lateinit var toolbar: MaterialToolbar
+    @BindView(R.id.controller_container)
+    lateinit var container: ViewGroup
+
+    @Inject
+    lateinit var userUtils: UserUtils
+    @Inject
+    lateinit var dataStore: ReactiveEntityStore<Persistable>
+    @Inject
+    lateinit var sqlCipherDatabaseSource: SqlCipherDatabaseSource
+
+    private var router: Router? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        setContentView(R.layout.activity_main)
+
+        NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+        ButterKnife.bind(this)
+
+        setSupportActionBar(toolbar)
+
+        router = Conductor.attachRouter(this, container, savedInstanceState)
+
+        var hasDb = true
+
+        try {
+            sqlCipherDatabaseSource.writableDatabase
+        } catch (exception: Exception) {
+            hasDb = false
+        }
+
+        if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
+            if (!router!!.hasRootController()) {
+                router!!.setRoot(RouterTransaction.with(ConversationsListController())
+                        .pushChangeHandler(HorizontalChangeHandler())
+                        .popChangeHandler(HorizontalChangeHandler()))
+            }
+            onNewIntent(intent)
+        } else if (!router!!.hasRootController()) {
+            if (hasDb) {
+                if (userUtils.anyUserExists()) {
+                    router!!.setRoot(RouterTransaction.with(ConversationsListController())
+                            .pushChangeHandler(HorizontalChangeHandler())
+                            .popChangeHandler(HorizontalChangeHandler()))
+                } else {
+                    router!!.setRoot(RouterTransaction.with(ServerSelectionController())
+                            .pushChangeHandler(HorizontalChangeHandler())
+                            .popChangeHandler(HorizontalChangeHandler()))
+                }
+            } else {
+                router!!.setRoot(RouterTransaction.with(ServerSelectionController())
+                        .pushChangeHandler(HorizontalChangeHandler())
+                        .popChangeHandler(HorizontalChangeHandler()))
+
+            }
+        }
+    }
+
+    override fun onStart() {
+        super.onStart()
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            checkIfWeAreSecure()
+        }
+    }
+
+
+    @RequiresApi(api = Build.VERSION_CODES.M)
+    fun checkIfWeAreSecure() {
+        val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+        if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
+            if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
+                if (router != null && router!!.getControllerWithTag(LockedController.TAG) == null) {
+                    router!!.pushController(RouterTransaction.with(LockedController())
+                            .pushChangeHandler(VerticalChangeHandler())
+                            .popChangeHandler(VerticalChangeHandler())
+                            .tag(LockedController.TAG))
+                }
+            }
+        }
+    }
+
+
+    override fun onNewIntent(intent: Intent) {
+        super.onNewIntent(intent)
+
+        if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
+            if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
+                router!!.pushController(RouterTransaction.with(CallNotificationController(intent.extras))
+                        .pushChangeHandler(HorizontalChangeHandler())
+                        .popChangeHandler(HorizontalChangeHandler()))
+            } else {
+                ConductorRemapping.remapChatController(router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
+                        intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false)
+            }
+        }
+    }
+
+    override fun onBackPressed() {
+        if (router!!.getControllerWithTag(LockedController.TAG) != null) {
+            return
+        }
+
+        if (!router!!.handleBack()) {
+            super.onBackPressed()
+        }
+    }
+
+    companion object {
+        private val TAG = "MainActivity"
+    }
+}

+ 2 - 2
app/src/main/java/com/nextcloud/talk/controllers/CallController.java

@@ -1118,9 +1118,9 @@ public class CallController extends BaseController {
                             }
 
                             if (!conversationUser.hasSpreedFeatureCapability("no-ping") && !TextUtils.isEmpty(roomId)) {
-                                NotificationUtils.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomId);
+                                NotificationUtils.INSTANCE.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomId);
                             } else if (!TextUtils.isEmpty(roomToken)) {
-                                NotificationUtils.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomToken);
+                                NotificationUtils.INSTANCE.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomToken);
                             }
 
                             if (!hasExternalSignalingServer) {

+ 6 - 3
app/src/main/java/com/nextcloud/talk/controllers/ChatController.java

@@ -701,9 +701,9 @@ public class ChatController extends BaseController implements MessagesListAdapte
 
     private void cancelNotificationsForCurrentConversation() {
         if (!conversationUser.hasSpreedFeatureCapability("no-ping") && !TextUtils.isEmpty(roomId)) {
-            NotificationUtils.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomId);
+            NotificationUtils.INSTANCE.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomId);
         } else if (!TextUtils.isEmpty(roomToken)) {
-            NotificationUtils.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomToken);
+            NotificationUtils.INSTANCE.cancelExistingNotificationsForRoom(getApplicationContext(), conversationUser, roomToken);
         }
     }
 
@@ -1160,7 +1160,6 @@ public class ChatController extends BaseController implements MessagesListAdapte
                     unreadChatMessage.setTimestamp(chatMessageList.get(0).getTimestamp());
                     unreadChatMessage.setMessage(context.getString(R.string.nc_new_messages));
                     adapter.addToStart(unreadChatMessage, false);
-                    layoutManager.scrollToPosition(chatMessageList.size() - 1);
                 }
 
                 for (int i = 0; i < chatMessageList.size(); i++) {
@@ -1200,6 +1199,10 @@ public class ChatController extends BaseController implements MessagesListAdapte
 
                 }
 
+                if (shouldAddNewMessagesNotice && adapter != null) {
+                    layoutManager.scrollToPositionWithOffset(adapter.getMessagePositionByIdInReverse("-1"), messagesListView.getHeight() / 2);
+                }
+
                 String xChatLastGivenHeader;
                 if (response.headers().size() > 0 && !TextUtils.isEmpty((xChatLastGivenHeader = response.headers().get
                         ("X-Chat-Last-Given")))) {

+ 0 - 62
app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.java

@@ -1,62 +0,0 @@
-/**
- * Nextcloud Talk application
- *
- * @author BlueLine Labs, Inc.
- * Copyright (C) 2016 BlueLine Labs, Inc.
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.nextcloud.talk.controllers.base;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import androidx.annotation.NonNull;
-import butterknife.ButterKnife;
-import butterknife.Unbinder;
-import com.bluelinelabs.conductor.Controller;
-
-public abstract class ButterKnifeController extends Controller {
-
-    private Unbinder unbinder;
-
-    public ButterKnifeController() {
-    }
-
-    public ButterKnifeController(Bundle args) {
-        super(args);
-    }
-
-    protected abstract View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container);
-
-    @NonNull
-    @Override
-    protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
-        View view = inflateView(inflater, container);
-        unbinder = ButterKnife.bind(this, view);
-        onViewBound(view);
-        return view;
-    }
-
-    protected void onViewBound(@NonNull View view) {
-    }
-
-    @Override
-    protected void onDestroyView(@NonNull View view) {
-        super.onDestroyView(view);
-        unbinder.unbind();
-        unbinder = null;
-    }
-
-}

+ 57 - 0
app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt

@@ -0,0 +1,57 @@
+/**
+ * Nextcloud Talk application
+ *
+ * @author BlueLine Labs, Inc.
+ * Copyright (C) 2016 BlueLine Labs, Inc.
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.nextcloud.talk.controllers.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import butterknife.ButterKnife
+import butterknife.Unbinder
+import com.bluelinelabs.conductor.Controller
+
+abstract class ButterKnifeController : Controller {
+
+    private var unbinder: Unbinder? = null
+
+    constructor() {}
+
+    constructor(args: Bundle) : super(args) {}
+
+    protected abstract fun inflateView(inflater: LayoutInflater, container: ViewGroup): View
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
+        val view = inflateView(inflater, container)
+        unbinder = ButterKnife.bind(this, view)
+        onViewBound(view)
+        return view
+    }
+
+    protected open fun onViewBound(view: View) {}
+
+    override fun onDestroyView(view: View) {
+        super.onDestroyView(view)
+        unbinder!!.unbind()
+        unbinder = null
+    }
+
+}

+ 9 - 9
app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java

@@ -343,21 +343,21 @@ public class NotificationWorker extends Worker {
                     groupName);*/
 
             if (decryptedPushMessage.getType().equals("chat") || decryptedPushMessage.getType().equals("room")) {
-                NotificationUtils.createNotificationChannel(context,
-                        NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V3, context.getResources()
+                NotificationUtils.INSTANCE.createNotificationChannel(context,
+                        NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_MESSAGES_V3(), context.getResources()
                                 .getString(R.string.nc_notification_channel_messages), context.getResources()
                                 .getString(R.string.nc_notification_channel_messages), true,
                         NotificationManager.IMPORTANCE_HIGH);
 
-                notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V3);
+                notificationBuilder.setChannelId(NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_MESSAGES_V3());
             } else {
-                NotificationUtils.createNotificationChannel(context,
-                        NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V3, context.getResources()
+                NotificationUtils.INSTANCE.createNotificationChannel(context,
+                        NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_CALLS_V3(), context.getResources()
                                 .getString(R.string.nc_notification_channel_calls), context.getResources()
                                 .getString(R.string.nc_notification_channel_calls_description), true,
                         NotificationManager.IMPORTANCE_HIGH);
 
-                notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V3);
+                notificationBuilder.setChannelId(NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_CALLS_V3());
             }
 
         } else {
@@ -380,7 +380,7 @@ public class NotificationWorker extends Worker {
         crc32.update(stringForCrc.getBytes());
 
         StatusBarNotification activeStatusBarNotification =
-                NotificationUtils.findNotificationForRoom(context,
+                NotificationUtils.INSTANCE.findNotificationForRoom(context,
                         signatureVerification.getUserEntity(), decryptedPushMessage.getId());
 
         int notificationId;
@@ -562,9 +562,9 @@ public class NotificationWorker extends Worker {
 
                     decryptedPushMessage.setTimestamp(System.currentTimeMillis());
                     if (decryptedPushMessage.isDelete()) {
-                        NotificationUtils.cancelExistingNotificationWithId(context, signatureVerification.getUserEntity(), decryptedPushMessage.getNotificationId());
+                        NotificationUtils.INSTANCE.cancelExistingNotificationWithId(context, signatureVerification.getUserEntity(), decryptedPushMessage.getNotificationId());
                     } else if (decryptedPushMessage.isDeleteAll()) {
-                        NotificationUtils.cancelAllNotificationsForAccount(context, signatureVerification.getUserEntity());
+                        NotificationUtils.INSTANCE.cancelAllNotificationsForAccount(context, signatureVerification.getUserEntity());
                     } else {
                         credentials = ApiUtils.getCredentials(signatureVerification.getUserEntity().getUsername(),
                                 signatureVerification.getUserEntity().getToken());

+ 0 - 89
app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.java

@@ -1,89 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.nextcloud.talk.receivers;
-
-import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.util.Log;
-import autodagger.AutoInjector;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.utils.NotificationUtils;
-import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.preferences.AppPreferences;
-
-import javax.inject.Inject;
-
-@AutoInjector(NextcloudTalkApplication.class)
-public class PackageReplacedReceiver extends BroadcastReceiver {
-    private static final String TAG = "PackageReplacedReceiver";
-
-    @Inject
-    UserUtils userUtils;
-
-    @Inject
-    AppPreferences appPreferences;
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
-
-        if (intent != null && intent.getAction() != null &&
-                intent.getAction().equals("android.intent.action.MY_PACKAGE_REPLACED")) {
-            try {
-                PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
-                if (packageInfo.versionCode > 43 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                    NotificationManager notificationManager =
-                            (NotificationManager) context.getSystemService(Context
-                                    .NOTIFICATION_SERVICE);
-
-                    if (notificationManager != null) {
-                        if (!appPreferences.getIsNotificationChannelUpgradedToV2()) {
-                            for (NotificationChannelGroup notificationChannelGroup : notificationManager
-                                    .getNotificationChannelGroups()) {
-                                notificationManager.deleteNotificationChannelGroup(notificationChannelGroup.getId());
-                            }
-
-                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS);
-                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES);
-
-                            appPreferences.setNotificationChannelIsUpgradedToV2(true);
-                        }
-
-                        if ((!appPreferences.getIsNotificationChannelUpgradedToV3()) && packageInfo.versionCode > 51) {
-                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V2);
-                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V2);
-                            appPreferences.setNotificationChannelIsUpgradedToV3(true);
-                        }
-                    }
-
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG, "Failed to fetch package info");
-            }
-        }
-    }
-}

+ 91 - 0
app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.kt

@@ -0,0 +1,91 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.receivers
+
+import android.app.NotificationChannelGroup
+import android.app.NotificationManager
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.os.Build
+import android.util.Log
+import autodagger.AutoInjector
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.utils.NotificationUtils
+import com.nextcloud.talk.utils.database.user.UserUtils
+import com.nextcloud.talk.utils.preferences.AppPreferences
+
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class PackageReplacedReceiver : BroadcastReceiver() {
+
+    @Inject
+    lateinit var userUtils: UserUtils
+
+    @Inject
+    lateinit var appPreferences: AppPreferences
+
+    override fun onReceive(context: Context, intent: Intent?) {
+        NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+
+        if (intent != null && intent.action != null &&
+                intent.action == "android.intent.action.MY_PACKAGE_REPLACED") {
+            try {
+                val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
+                if (packageInfo.versionCode > 43 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                    val notificationManager = context.getSystemService(Context
+                            .NOTIFICATION_SERVICE) as NotificationManager
+
+                    if (notificationManager != null) {
+                        if (!appPreferences!!.isNotificationChannelUpgradedToV2) {
+                            for (notificationChannelGroup in notificationManager
+                                    .notificationChannelGroups) {
+                                notificationManager.deleteNotificationChannelGroup(notificationChannelGroup.id)
+                            }
+
+                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS)
+                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES)
+
+                            appPreferences!!.setNotificationChannelIsUpgradedToV2(true)
+                        }
+
+                        if (!appPreferences!!.isNotificationChannelUpgradedToV3 && packageInfo.versionCode > 51) {
+                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V2)
+                            notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V2)
+                            appPreferences!!.setNotificationChannelIsUpgradedToV3(true)
+                        }
+                    }
+
+                }
+            } catch (e: PackageManager.NameNotFoundException) {
+                Log.e(TAG, "Failed to fetch package info")
+            }
+
+        }
+    }
+
+    companion object {
+        private val TAG = "PackageReplacedReceiver"
+    }
+}

+ 0 - 185
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java

@@ -1,185 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.nextcloud.talk.utils;
-
-import android.annotation.TargetApi;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.os.Build;
-import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
-
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.models.database.UserEntity;
-import com.nextcloud.talk.utils.bundle.BundleKeys;
-
-import java.util.zip.CRC32;
-
-public class NotificationUtils {
-    public static final String NOTIFICATION_CHANNEL_CALLS = "NOTIFICATION_CHANNEL_CALLS";
-    public static final String NOTIFICATION_CHANNEL_MESSAGES = "NOTIFICATION_CHANNEL_MESSAGES";
-    public static final String NOTIFICATION_CHANNEL_CALLS_V2 = "NOTIFICATION_CHANNEL_CALLS_V2";
-    public static final String NOTIFICATION_CHANNEL_MESSAGES_V2 = "NOTIFICATION_CHANNEL_MESSAGES_V2";
-    public static final String NOTIFICATION_CHANNEL_MESSAGES_V3 = "NOTIFICATION_CHANNEL_MESSAGES_V3";
-    public static final String NOTIFICATION_CHANNEL_CALLS_V3 = "NOTIFICATION_CHANNEL_CALLS_V3";
-
-    @TargetApi(Build.VERSION_CODES.O)
-    public static void createNotificationChannel(Context context,
-                                                 String channelId, String channelName,
-                                                 String channelDescription, boolean enableLights,
-                                                 int importance) {
-
-        NotificationManager notificationManager =
-                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O
-                && notificationManager.getNotificationChannel(channelId) == null) {
-
-            NotificationChannel channel = new NotificationChannel(channelId, channelName,
-                    importance);
-
-            channel.setDescription(channelDescription);
-            channel.enableLights(enableLights);
-            channel.setLightColor(R.color.colorPrimary);
-            channel.setSound(null, null);
-
-            notificationManager.createNotificationChannel(channel);
-        }
-    }
-
-    @TargetApi(Build.VERSION_CODES.O)
-    public static void createNotificationChannelGroup(Context context,
-                                                      String groupId, CharSequence groupName) {
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
-            NotificationManager notificationManager =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-            NotificationChannelGroup notificationChannelGroup = new NotificationChannelGroup(groupId, groupName);
-            if (!notificationManager.getNotificationChannelGroups().contains(notificationChannelGroup)) {
-                notificationManager.createNotificationChannelGroup(notificationChannelGroup);
-            }
-        }
-    }
-
-    public static void cancelAllNotificationsForAccount(Context context, UserEntity conversationUser) {
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M && conversationUser.getId() != -1 &&
-                context != null) {
-
-            NotificationManager notificationManager =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-            if (notificationManager != null) {
-                StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications();
-                Notification notification;
-                for (StatusBarNotification statusBarNotification : statusBarNotifications) {
-                    notification = statusBarNotification.getNotification();
-
-                    if (notification != null && !notification.extras.isEmpty()) {
-                        if (conversationUser.getId() == notification.extras.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID())) {
-                            notificationManager.cancel(statusBarNotification.getId());
-                        }
-                    }
-                }
-            }
-        }
-
-    }
-
-    public static void cancelExistingNotificationWithId(Context context, UserEntity conversationUser, long notificationId) {
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M && conversationUser.getId() != -1 &&
-                context != null) {
-
-            NotificationManager notificationManager =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-            if (notificationManager != null) {
-                StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications();
-                Notification notification;
-                for (StatusBarNotification statusBarNotification : statusBarNotifications) {
-                    notification = statusBarNotification.getNotification();
-
-                    if (notification != null && !notification.extras.isEmpty()) {
-                        if (conversationUser.getId() == notification.extras.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID()) &&
-                                notificationId == notification.extras.getLong(BundleKeys.INSTANCE.getKEY_NOTIFICATION_ID())) {
-                            notificationManager.cancel(statusBarNotification.getId());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public static StatusBarNotification findNotificationForRoom(Context context,
-                                                       UserEntity conversationUser,
-                                                       String roomTokenOrId) {
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M && conversationUser.getId() != -1 &&
-                context != null) {
-
-            NotificationManager notificationManager =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-            if (notificationManager != null) {
-                StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications();
-                Notification notification;
-                for (StatusBarNotification statusBarNotification : statusBarNotifications) {
-                    notification = statusBarNotification.getNotification();
-
-                    if (notification != null && !notification.extras.isEmpty()) {
-                        if (conversationUser.getId() == notification.extras.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID()) &&
-                                roomTokenOrId.equals(statusBarNotification.getNotification().extras.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()))) {
-                            return statusBarNotification;
-                        }
-                    }
-                }
-            }
-        }
-
-        return null;
-    }
-
-    public static void cancelExistingNotificationsForRoom(Context context, UserEntity conversationUser,
-                                                          String roomTokenOrId) {
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M && conversationUser.getId() != -1 &&
-                context != null) {
-
-            NotificationManager notificationManager =
-                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-            if (notificationManager != null) {
-                StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications();
-                Notification notification;
-                for (StatusBarNotification statusBarNotification : statusBarNotifications) {
-                    notification = statusBarNotification.getNotification();
-
-                    if (notification != null && !notification.extras.isEmpty()) {
-                        if (conversationUser.getId() == notification.extras.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID()) &&
-                                roomTokenOrId.equals(statusBarNotification.getNotification().extras.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()))) {
-                            notificationManager.cancel(statusBarNotification.getId());
-                        }
-                    }
-                }
-            }
-        }
-    }
-}

+ 162 - 0
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt

@@ -0,0 +1,162 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.utils
+
+import android.annotation.TargetApi
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationChannelGroup
+import android.app.NotificationManager
+import android.content.Context
+import android.os.Build
+import android.service.notification.StatusBarNotification
+import com.nextcloud.talk.R
+import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.utils.bundle.BundleKeys
+
+object NotificationUtils {
+    val NOTIFICATION_CHANNEL_CALLS = "NOTIFICATION_CHANNEL_CALLS"
+    val NOTIFICATION_CHANNEL_MESSAGES = "NOTIFICATION_CHANNEL_MESSAGES"
+    val NOTIFICATION_CHANNEL_CALLS_V2 = "NOTIFICATION_CHANNEL_CALLS_V2"
+    val NOTIFICATION_CHANNEL_MESSAGES_V2 = "NOTIFICATION_CHANNEL_MESSAGES_V2"
+    val NOTIFICATION_CHANNEL_MESSAGES_V3 = "NOTIFICATION_CHANNEL_MESSAGES_V3"
+    val NOTIFICATION_CHANNEL_CALLS_V3 = "NOTIFICATION_CHANNEL_CALLS_V3"
+
+    @TargetApi(Build.VERSION_CODES.O)
+    fun createNotificationChannel(context: Context,
+                                  channelId: String, channelName: String,
+                                  channelDescription: String, enableLights: Boolean,
+                                  importance: Int) {
+
+        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O && notificationManager.getNotificationChannel(channelId) == null) {
+
+            val channel = NotificationChannel(channelId, channelName,
+                    importance)
+
+            channel.description = channelDescription
+            channel.enableLights(enableLights)
+            channel.lightColor = R.color.colorPrimary
+            channel.setSound(null, null)
+
+            notificationManager.createNotificationChannel(channel)
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.O)
+    fun createNotificationChannelGroup(context: Context,
+                                       groupId: String, groupName: CharSequence) {
+        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
+            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+            val notificationChannelGroup = NotificationChannelGroup(groupId, groupName)
+            if (!notificationManager.notificationChannelGroups.contains(notificationChannelGroup)) {
+                notificationManager.createNotificationChannelGroup(notificationChannelGroup)
+            }
+        }
+    }
+
+    fun cancelAllNotificationsForAccount(context: Context?, conversationUser: UserEntity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L && context != null) {
+
+            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+            val statusBarNotifications = notificationManager.activeNotifications
+            var notification: Notification?
+            for (statusBarNotification in statusBarNotifications) {
+                notification = statusBarNotification.notification
+
+                if (notification != null && !notification.extras.isEmpty) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID)) {
+                        notificationManager.cancel(statusBarNotification.id)
+                    }
+                }
+            }
+        }
+
+    }
+
+    fun cancelExistingNotificationWithId(context: Context?, conversationUser: UserEntity, notificationId: Long) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
+                context != null) {
+
+            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+            val statusBarNotifications = notificationManager.activeNotifications
+            var notification: Notification?
+            for (statusBarNotification in statusBarNotifications) {
+                notification = statusBarNotification.notification
+
+                if (notification != null && !notification.extras.isEmpty) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)) {
+                        notificationManager.cancel(statusBarNotification.id)
+                    }
+                }
+            }
+        }
+    }
+
+    fun findNotificationForRoom(context: Context?,
+                                conversationUser: UserEntity,
+                                roomTokenOrId: String): StatusBarNotification? {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
+                context != null) {
+
+            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+            val statusBarNotifications = notificationManager.activeNotifications
+            var notification: Notification?
+            for (statusBarNotification in statusBarNotifications) {
+                notification = statusBarNotification.notification
+
+                if (notification != null && !notification.extras.isEmpty) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
+                        return statusBarNotification
+                    }
+                }
+            }
+        }
+
+        return null
+    }
+
+    fun cancelExistingNotificationsForRoom(context: Context?, conversationUser: UserEntity,
+                                           roomTokenOrId: String) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
+                context != null) {
+
+            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+            val statusBarNotifications = notificationManager.activeNotifications
+            var notification: Notification?
+            for (statusBarNotification in statusBarNotifications) {
+                notification = statusBarNotification.notification
+
+                if (notification != null && !notification.extras.isEmpty) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
+                        notificationManager.cancel(statusBarNotification.id)
+                    }
+                }
+            }
+        }
+    }
+}