Procházet zdrojové kódy

Merge pull request #2891 from nextcloud/refactoring/noid/locationRemoveConductor

Replace Controllers with Activities for location+geocoding
Marcel Hibbe před 2 roky
rodič
revize
9e68be74d6

+ 8 - 0
app/src/main/AndroidManifest.xml

@@ -194,6 +194,14 @@
             android:name=".messagesearch.MessageSearchActivity"
             android:theme="@style/AppTheme" />
 
+        <activity
+            android:name=".location.LocationPickerActivity"
+            android:theme="@style/AppTheme" />
+
+        <activity
+            android:name=".location.GeocodingActivity"
+            android:theme="@style/AppTheme" />
+
         <receiver android:name=".receivers.PackageReplacedReceiver"
             android:exported="false">
             <intent-filter>

+ 4 - 7
app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt

@@ -134,6 +134,7 @@ import com.nextcloud.talk.extensions.loadAvatarOrImagePreview
 import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
 import com.nextcloud.talk.jobs.ShareOperationWorker
 import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
+import com.nextcloud.talk.location.LocationPickerActivity
 import com.nextcloud.talk.messagesearch.MessageSearchActivity
 import com.nextcloud.talk.models.domain.ReactionAddedModel
 import com.nextcloud.talk.models.domain.ReactionDeletedModel
@@ -1767,13 +1768,9 @@ class ChatController(args: Bundle) :
     fun showShareLocationScreen() {
         Log.d(TAG, "showShareLocationScreen")
 
-        val bundle = Bundle()
-        bundle.putString(KEY_ROOM_TOKEN, roomToken)
-        router.pushController(
-            RouterTransaction.with(LocationPickerController(bundle))
-                .pushChangeHandler(HorizontalChangeHandler())
-                .popChangeHandler(HorizontalChangeHandler())
-        )
+        val intent = Intent(activity, LocationPickerActivity::class.java)
+        intent.putExtra(KEY_ROOM_TOKEN, roomToken)
+        activity!!.startActivity(intent)
     }
 
     private fun showConversationInfoScreen() {

+ 101 - 68
app/src/main/java/com/nextcloud/talk/controllers/GeocodingController.kt → app/src/main/java/com/nextcloud/talk/location/GeocodingActivity.kt

@@ -18,32 +18,33 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package com.nextcloud.talk.controllers
+package com.nextcloud.talk.location
 
 import android.app.SearchManager
 import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.ColorDrawable
 import android.os.Build
 import android.os.Bundle
 import android.text.InputType
 import android.util.Log
 import android.view.Menu
-import android.view.MenuInflater
 import android.view.MenuItem
-import android.view.View
 import android.view.inputmethod.EditorInfo
 import android.widget.AdapterView
 import android.widget.Toast
 import androidx.appcompat.widget.SearchView
+import androidx.core.content.res.ResourcesCompat
 import androidx.core.view.MenuItemCompat
 import androidx.preference.PreferenceManager
 import autodagger.AutoInjector
 import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.adapters.GeocodingAdapter
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
-import com.nextcloud.talk.databinding.ControllerGeocodingBinding
+import com.nextcloud.talk.databinding.ActivityGeocodingBinding
+import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import fr.dudie.nominatim.client.TalkJsonNominatimClient
 import fr.dudie.nominatim.model.Address
@@ -57,13 +58,11 @@ import org.osmdroid.config.Configuration
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
-class GeocodingController(args: Bundle) :
-    BaseController(
-        R.layout.controller_geocoding,
-        args
-    ),
+class GeocodingActivity :
+    BaseActivity(),
     SearchView.OnQueryTextListener {
-    private val binding: ControllerGeocodingBinding? by viewBinding(ControllerGeocodingBinding::bind)
+
+    private lateinit var binding: ActivityGeocodingBinding
 
     @Inject
     lateinit var ncApi: NcApi
@@ -71,7 +70,7 @@ class GeocodingController(args: Bundle) :
     @Inject
     lateinit var okHttpClient: OkHttpClient
 
-    var roomToken: String?
+    lateinit var roomToken: String
     var nominatimClient: TalkJsonNominatimClient? = null
 
     var searchItem: MenuItem? = null
@@ -81,52 +80,89 @@ class GeocodingController(args: Bundle) :
     lateinit var adapter: GeocodingAdapter
     private var geocodingResults: List<Address> = ArrayList()
 
-    constructor(args: Bundle, listener: LocationPickerController) : this(args) {
-        targetController = listener
-    }
-
-    init {
-        setHasOptionsMenu(true)
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+
+        binding = ActivityGeocodingBinding.inflate(layoutInflater)
+        setupActionBar()
+        setupSystemColors()
+        setContentView(binding.root)
+
         Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
-        query = args.getString(BundleKeys.KEY_GEOCODING_QUERY)
-        roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN)
-    }
 
-    private fun initAdapter(addresses: List<Address>) {
-        adapter = GeocodingAdapter(binding?.geocodingResults?.context!!, addresses)
-        binding?.geocodingResults?.adapter = adapter
+        roomToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!
+        query = intent.getStringExtra(BundleKeys.KEY_GEOCODING_QUERY)
     }
 
-    override fun onAttach(view: View) {
-        super.onAttach(view)
-
+    override fun onStart() {
+        super.onStart()
         initAdapter(geocodingResults)
-
         initGeocoder()
+    }
+
+    override fun onResume() {
+        super.onResume()
+
         if (!query.isNullOrEmpty()) {
             searchLocation()
         } else {
             Log.e(TAG, "search string that was passed to GeocodingController was null or empty")
         }
 
-        binding?.geocodingResults?.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
+        binding.geocodingResults.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
             val address: Address = adapter.getItem(position) as Address
-            val listener: GeocodingResultListener? = targetController as GeocodingResultListener?
-            listener?.receiveChosenGeocodingResult(address.latitude, address.longitude, address.displayName)
-            router.popCurrentController()
+            val geocodingResult = GeocodingResult(address.latitude, address.longitude, address.displayName)
+
+            val intent = Intent(this, LocationPickerActivity::class.java)
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken)
+            intent.putExtra(BundleKeys.KEY_GEOCODING_RESULT, geocodingResult)
+            startActivity(intent)
+        }
+    }
+
+    private fun setupActionBar() {
+        setSupportActionBar(binding.geocodingToolbar)
+        binding.geocodingToolbar.setNavigationOnClickListener {
+            onBackPressed()
         }
+        supportActionBar?.setDisplayHomeAsUpEnabled(true)
+        supportActionBar?.setDisplayShowHomeEnabled(true)
+        supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(R.color.transparent)))
+        supportActionBar?.title = ""
+    }
+
+    private fun setupSystemColors() {
+        DisplayUtils.applyColorToStatusBar(
+            this,
+            ResourcesCompat.getColor(
+                resources,
+                R.color.appbar,
+                null
+            )
+        )
+        DisplayUtils.applyColorToNavigationBar(
+            this.window,
+            ResourcesCompat.getColor(resources, R.color.bg_default, null)
+        )
+    }
+
+    private fun initAdapter(addresses: List<Address>) {
+        adapter = GeocodingAdapter(binding.geocodingResults.context!!, addresses)
+        binding.geocodingResults.adapter = adapter
     }
 
-    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
-        super.onCreateOptionsMenu(menu, inflater)
-        inflater.inflate(R.menu.menu_geocoding, menu)
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        super.onCreateOptionsMenu(menu)
+        menuInflater.inflate(R.menu.menu_geocoding, menu)
         searchItem = menu.findItem(R.id.geocoding_action_search)
         initSearchView()
 
         searchItem?.expandActionView()
         searchView?.setQuery(query, false)
         searchView?.clearFocus()
+        return true
     }
 
     override fun onQueryTextSubmit(query: String?): Boolean {
@@ -141,38 +177,39 @@ class GeocodingController(args: Bundle) :
     }
 
     private fun initSearchView() {
-        if (activity != null) {
-            val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager
-            if (searchItem != null) {
-                searchView = MenuItemCompat.getActionView(searchItem) as SearchView
-                searchView?.maxWidth = Int.MAX_VALUE
-                searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
-                var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
-                    imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
-                }
-                searchView?.imeOptions = imeOptions
-                searchView?.queryHint = resources!!.getString(R.string.nc_search)
-                searchView?.setSearchableInfo(searchManager.getSearchableInfo(activity!!.componentName))
-                searchView?.setOnQueryTextListener(this)
-
-                searchItem?.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
-                    override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
-                        return true
-                    }
-
-                    override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
-                        router.popCurrentController()
-                        return true
-                    }
-                })
+        val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
+        if (searchItem != null) {
+            searchView = MenuItemCompat.getActionView(searchItem) as SearchView
+            searchView?.maxWidth = Int.MAX_VALUE
+            searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
+            var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
+                imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
             }
+            searchView?.imeOptions = imeOptions
+            searchView?.queryHint = resources!!.getString(R.string.nc_search)
+            searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))
+            searchView?.setOnQueryTextListener(this)
+
+            searchItem?.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
+                override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
+                    return true
+                }
+
+                override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
+                    val intent = Intent(context, LocationPickerActivity::class.java)
+                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+                    intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken)
+                    startActivity(intent)
+                    return true
+                }
+            })
         }
     }
 
     private fun initGeocoder() {
-        val baseUrl = context!!.getString(R.string.osm_geocoder_url)
-        val email = context!!.getString(R.string.osm_geocoder_contact)
+        val baseUrl = getString(R.string.osm_geocoder_url)
+        val email = context.getString(R.string.osm_geocoder_contact)
         nominatimClient = TalkJsonNominatimClient(baseUrl, okHttpClient, email)
     }
 
@@ -206,11 +243,7 @@ class GeocodingController(args: Bundle) :
         }
     }
 
-    interface GeocodingResultListener {
-        fun receiveChosenGeocodingResult(lat: Double, lon: Double, name: String)
-    }
-
     companion object {
-        private const val TAG = "GeocodingController"
+        private val TAG = GeocodingActivity::class.java.simpleName
     }
 }

+ 31 - 0
app/src/main/java/com/nextcloud/talk/location/GeocodingResult.kt

@@ -0,0 +1,31 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Marcel Hibbe
+ * Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
+ *
+ * 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.location
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class GeocodingResult(
+    val lat: Double,
+    val lon: Double,
+    var displayName: String
+) : Parcelable

+ 184 - 135
app/src/main/java/com/nextcloud/talk/controllers/LocationPickerController.kt → app/src/main/java/com/nextcloud/talk/location/LocationPickerActivity.kt

@@ -18,11 +18,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package com.nextcloud.talk.controllers
+package com.nextcloud.talk.location
 
 import android.Manifest
+import android.app.Activity
 import android.app.SearchManager
 import android.content.Context
+import android.content.Intent
 import android.content.pm.PackageManager
 import android.graphics.drawable.ColorDrawable
 import android.location.Location
@@ -33,7 +35,6 @@ import android.os.Bundle
 import android.text.InputType
 import android.util.Log
 import android.view.Menu
-import android.view.MenuInflater
 import android.view.MenuItem
 import android.view.View
 import android.view.inputmethod.EditorInfo
@@ -44,19 +45,17 @@ import androidx.core.content.res.ResourcesCompat
 import androidx.core.view.MenuItemCompat
 import androidx.preference.PreferenceManager
 import autodagger.AutoInjector
-import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
-import com.nextcloud.talk.controllers.base.BaseController
-import com.nextcloud.talk.controllers.util.viewBinding
-import com.nextcloud.talk.databinding.ControllerLocationBinding
+import com.nextcloud.talk.databinding.ActivityLocationBinding
 import com.nextcloud.talk.models.json.generic.GenericOverall
 import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_GEOCODING_RESULT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
 import fr.dudie.nominatim.client.TalkJsonNominatimClient
 import fr.dudie.nominatim.model.Address
@@ -82,15 +81,12 @@ import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
-class LocationPickerController(args: Bundle) :
-    BaseController(
-        R.layout.controller_location,
-        args
-    ),
+class LocationPickerActivity :
+    BaseActivity(),
     SearchView.OnQueryTextListener,
-    LocationListener,
-    GeocodingController.GeocodingResultListener {
-    private val binding: ControllerLocationBinding? by viewBinding(ControllerLocationBinding::bind)
+    LocationListener {
+
+    private lateinit var binding: ActivityLocationBinding
 
     @Inject
     lateinit var ncApi: NcApi
@@ -103,110 +99,154 @@ class LocationPickerController(args: Bundle) :
 
     var nominatimClient: TalkJsonNominatimClient? = null
 
-    var roomToken: String?
+    lateinit var roomToken: String
+    var geocodingResult: GeocodingResult? = null
 
     var myLocation: GeoPoint = GeoPoint(COORDINATE_ZERO, COORDINATE_ZERO)
     private var locationManager: LocationManager? = null
     private lateinit var locationOverlay: MyLocationNewOverlay
 
-    var moveToCurrentLocationWasClicked: Boolean = true
+    var moveToCurrentLocation: Boolean = true
     var readyToShareLocation: Boolean = false
+
+    private var mapCenterLat: Double = 0.0
+    private var mapCenterLon: Double = 0.0
+
     var searchItem: MenuItem? = null
     var searchView: SearchView? = null
 
-    var receivedChosenGeocodingResult: Boolean = false
-    var geocodedLat: Double = 0.0
-    var geocodedLon: Double = 0.0
-    var geocodedName: String = ""
-
-    init {
-        setHasOptionsMenu(true)
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
-        getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
 
-        roomToken = args.getString(KEY_ROOM_TOKEN)
+        roomToken = intent.getStringExtra(KEY_ROOM_TOKEN)!!
+        geocodingResult = intent.getParcelableExtra(KEY_GEOCODING_RESULT)
+
+        if (savedInstanceState != null) {
+            moveToCurrentLocation = savedInstanceState.getBoolean("moveToCurrentLocation") == true
+            mapCenterLat = savedInstanceState.getDouble("mapCenterLat")
+            mapCenterLon = savedInstanceState.getDouble("mapCenterLon")
+            geocodingResult = savedInstanceState.getParcelable("geocodingResult")
+        }
+
+        binding = ActivityLocationBinding.inflate(layoutInflater)
+        setupActionBar()
+        setupSystemColors()
+        setContentView(binding.root)
+
+        getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
     }
 
-    override fun onAttach(view: View) {
-        super.onAttach(view)
+    override fun onStart() {
+        super.onStart()
         initMap()
     }
 
-    @Suppress("Detekt.TooGenericExceptionCaught")
-    override fun onDetach(view: View) {
-        super.onDetach(view)
+    override fun onResume() {
+        super.onResume()
 
-        try {
-            locationManager!!.removeUpdates(this)
-        } catch (e: Exception) {
-            Log.e(TAG, "error when trying to remove updates for location Manager", e)
+        if (geocodingResult != null) {
+            moveToCurrentLocation = false
         }
 
-        locationOverlay.disableMyLocation()
+        setLocationDescription(false, geocodingResult != null)
+        binding.shareLocation.isClickable = false
+        binding.shareLocation.setOnClickListener {
+            if (readyToShareLocation) {
+                shareLocation(
+                    binding.map.mapCenter?.latitude,
+                    binding.map.mapCenter?.longitude,
+                    binding.placeName.text.toString()
+                )
+            } else {
+                Log.w(TAG, "readyToShareLocation was false while user tried to share location.")
+            }
+        }
     }
 
-    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
-        super.onCreateOptionsMenu(menu, inflater)
-        inflater.inflate(R.menu.menu_locationpicker, menu)
-        searchItem = menu.findItem(R.id.location_action_search)
-        initSearchView()
+    override fun onSaveInstanceState(bundle: Bundle) {
+        super.onSaveInstanceState(bundle)
+        bundle.putBoolean("moveToCurrentLocation", moveToCurrentLocation)
+        bundle.putDouble("mapCenterLat", binding.map.mapCenter.latitude)
+        bundle.putDouble("mapCenterLon", binding.map.mapCenter.longitude)
+        bundle.putParcelable("geocodingResult", geocodingResult)
+    }
+
+    private fun setupActionBar() {
+        setSupportActionBar(binding.locationPickerToolbar)
+        binding.locationPickerToolbar.setNavigationOnClickListener {
+            onBackPressed()
+        }
+        supportActionBar?.setDisplayHomeAsUpEnabled(true)
+        supportActionBar?.setDisplayShowHomeEnabled(true)
+        supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent)))
+        supportActionBar?.title = context.getString(R.string.nc_share_location)
     }
 
-    override fun onPrepareOptionsMenu(menu: Menu) {
+    private fun setupSystemColors() {
+        DisplayUtils.applyColorToStatusBar(
+            this,
+            ResourcesCompat.getColor(
+                resources,
+                R.color.appbar,
+                null
+            )
+        )
+        DisplayUtils.applyColorToNavigationBar(
+            this.window,
+            ResourcesCompat.getColor(resources, R.color.bg_default, null)
+        )
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        super.onCreateOptionsMenu(menu)
+        menuInflater.inflate(R.menu.menu_locationpicker, menu)
+        return true
+    }
+
+    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
         super.onPrepareOptionsMenu(menu)
-        actionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent)))
-        actionBar?.title = context!!.getString(R.string.nc_share_location)
+        searchItem = menu.findItem(R.id.location_action_search)
+        initSearchView()
+        return true
     }
 
-    override val title: String
-        get() =
-            resources!!.getString(R.string.nc_share_location)
+    @Suppress("Detekt.TooGenericExceptionCaught")
+    override fun onStop() {
+        super.onStop()
 
-    override fun onViewBound(view: View) {
-        setLocationDescription(false, receivedChosenGeocodingResult)
-        binding?.shareLocation?.isClickable = false
-        binding?.shareLocation?.setOnClickListener {
-            if (readyToShareLocation) {
-                shareLocation(
-                    binding?.map?.mapCenter?.latitude,
-                    binding?.map?.mapCenter?.longitude,
-                    binding?.placeName?.text.toString()
-                )
-            } else {
-                Log.w(TAG, "readyToShareLocation was false while user tried to share location.")
-            }
+        try {
+            locationManager!!.removeUpdates(this)
+        } catch (e: Exception) {
+            Log.e(TAG, "error when trying to remove updates for location Manager", e)
         }
+
+        locationOverlay.disableMyLocation()
     }
 
     private fun initSearchView() {
-        if (activity != null) {
-            val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager
-            if (searchItem != null) {
-                searchView = MenuItemCompat.getActionView(searchItem) as SearchView
-                searchView?.maxWidth = Int.MAX_VALUE
-                searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
-                var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
-                    imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
-                }
-                searchView?.imeOptions = imeOptions
-                searchView?.queryHint = resources!!.getString(R.string.nc_search)
-                searchView?.setSearchableInfo(searchManager.getSearchableInfo(activity!!.componentName))
-                searchView?.setOnQueryTextListener(this)
+        val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
+        if (searchItem != null) {
+            searchView = MenuItemCompat.getActionView(searchItem) as SearchView
+            searchView?.maxWidth = Int.MAX_VALUE
+            searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
+            var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
+                imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
             }
+            searchView?.imeOptions = imeOptions
+            searchView?.queryHint = resources!!.getString(R.string.nc_search)
+            searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))
+            searchView?.setOnQueryTextListener(this)
         }
     }
 
     override fun onQueryTextSubmit(query: String?): Boolean {
         if (!query.isNullOrEmpty()) {
-            val bundle = Bundle()
-            bundle.putString(BundleKeys.KEY_GEOCODING_QUERY, query)
-            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
-            router.pushController(
-                RouterTransaction.with(GeocodingController(bundle, this))
-                    .pushChangeHandler(HorizontalChangeHandler())
-                    .popChangeHandler(HorizontalChangeHandler())
-            )
+            val intent = Intent(this, GeocodingActivity::class.java)
+            intent.putExtra(BundleKeys.KEY_GEOCODING_QUERY, query)
+            intent.putExtra(KEY_ROOM_TOKEN, roomToken)
+            startActivity(intent)
         }
         return true
     }
@@ -217,10 +257,10 @@ class LocationPickerController(args: Bundle) :
 
     @Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod")
     private fun initMap() {
-        binding?.map?.setTileSource(TileSourceFactory.MAPNIK)
-        binding?.map?.onResume()
+        binding.map.setTileSource(TileSourceFactory.MAPNIK)
+        binding.map.onResume()
 
-        locationManager = activity!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager
+        locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
 
         if (!isLocationPermissionsGranted()) {
             requestLocationPermissions()
@@ -229,12 +269,12 @@ class LocationPickerController(args: Bundle) :
         }
 
         val copyrightOverlay = CopyrightOverlay(context)
-        binding?.map?.overlays?.add(copyrightOverlay)
+        binding.map.overlays.add(copyrightOverlay)
 
-        binding?.map?.setMultiTouchControls(true)
-        binding?.map?.isTilesScaledToDpi = true
+        binding.map.setMultiTouchControls(true)
+        binding.map.isTilesScaledToDpi = true
 
-        locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding?.map)
+        locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding.map)
         locationOverlay.enableMyLocation()
         locationOverlay.setPersonHotspot(PERSON_HOT_SPOT_X, PERSON_HOT_SPOT_Y)
         locationOverlay.setPersonIcon(
@@ -242,24 +282,28 @@ class LocationPickerController(args: Bundle) :
                 ResourcesCompat.getDrawable(resources!!, R.drawable.current_location_circle, null)
             )
         )
-        binding?.map?.overlays?.add(locationOverlay)
+        binding.map.overlays.add(locationOverlay)
 
-        val mapController = binding?.map?.controller
+        val mapController = binding.map.controller
 
-        if (receivedChosenGeocodingResult) {
-            mapController?.setZoom(ZOOM_LEVEL_RECEIVED_RESULT)
+        if (geocodingResult != null) {
+            mapController.setZoom(ZOOM_LEVEL_RECEIVED_RESULT)
         } else {
-            mapController?.setZoom(ZOOM_LEVEL_DEFAULT)
+            mapController.setZoom(ZOOM_LEVEL_DEFAULT)
+        }
+
+        if (mapCenterLat != 0.0 && mapCenterLon != 0.0) {
+            mapController.setCenter(GeoPoint(mapCenterLat, mapCenterLon))
         }
 
-        val zoomToCurrentPositionOnFirstFix = !receivedChosenGeocodingResult
+        val zoomToCurrentPositionOnFirstFix = geocodingResult == null && moveToCurrentLocation
         locationOverlay.runOnFirstFix {
             if (locationOverlay.myLocation != null) {
                 myLocation = locationOverlay.myLocation
                 if (zoomToCurrentPositionOnFirstFix) {
-                    activity!!.runOnUiThread {
-                        mapController?.setZoom(ZOOM_LEVEL_DEFAULT)
-                        mapController?.setCenter(myLocation)
+                    runOnUiThread {
+                        mapController.setZoom(ZOOM_LEVEL_DEFAULT)
+                        mapController.setCenter(myLocation)
                     }
                 }
             } else {
@@ -269,20 +313,22 @@ class LocationPickerController(args: Bundle) :
             }
         }
 
-        if (receivedChosenGeocodingResult && geocodedLat != COORDINATE_ZERO && geocodedLon != COORDINATE_ZERO) {
-            mapController?.setCenter(GeoPoint(geocodedLat, geocodedLon))
+        geocodingResult?.let {
+            if (it.lat != COORDINATE_ZERO && it.lon != COORDINATE_ZERO) {
+                mapController.setCenter(GeoPoint(it.lat, it.lon))
+            }
         }
 
-        binding?.centerMapButton?.setOnClickListener {
+        binding.centerMapButton.setOnClickListener {
             if (myLocation.latitude == COORDINATE_ZERO && myLocation.longitude == COORDINATE_ZERO) {
                 Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
             } else {
-                mapController?.animateTo(myLocation)
-                moveToCurrentLocationWasClicked = true
+                mapController.animateTo(myLocation)
+                moveToCurrentLocation = true
             }
         }
 
-        binding?.map?.addMapListener(
+        binding.map.addMapListener(
             delayedMapListener()
         )
     }
@@ -293,17 +339,17 @@ class LocationPickerController(args: Bundle) :
             override fun onScroll(paramScrollEvent: ScrollEvent): Boolean {
                 try {
                     when {
-                        moveToCurrentLocationWasClicked -> {
+                        moveToCurrentLocation -> {
                             setLocationDescription(isGpsLocation = true, isGeocodedResult = false)
-                            moveToCurrentLocationWasClicked = false
+                            moveToCurrentLocation = false
                         }
-                        receivedChosenGeocodingResult -> {
-                            binding?.shareLocation?.isClickable = true
+                        geocodingResult != null -> {
+                            binding.shareLocation.isClickable = true
                             setLocationDescription(isGpsLocation = false, isGeocodedResult = true)
-                            receivedChosenGeocodingResult = false
+                            geocodingResult = null
                         }
                         else -> {
-                            binding?.shareLocation?.isClickable = true
+                            binding.shareLocation.isClickable = true
                             setLocationDescription(isGpsLocation = false, isGeocodedResult = false)
                         }
                     }
@@ -349,35 +395,35 @@ class LocationPickerController(args: Bundle) :
                             " and there is no alternative like UnifiedNlp installed. Furthermore no GPS is " +
                             "supported."
                     )
-                    Toast.makeText(context, context?.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG)
+                    Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG)
                         .show()
                 }
             }
         } catch (e: SecurityException) {
             Log.e(TAG, "Error when requesting location updates. Permissions may be missing.", e)
-            Toast.makeText(context, context?.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
+            Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
         } catch (e: Exception) {
             Log.e(TAG, "Error when requesting location updates.", e)
-            Toast.makeText(context, context?.getString(R.string.nc_common_error_sorry), Toast.LENGTH_LONG).show()
+            Toast.makeText(context, context.getString(R.string.nc_common_error_sorry), Toast.LENGTH_LONG).show()
         }
     }
 
     private fun setLocationDescription(isGpsLocation: Boolean, isGeocodedResult: Boolean) {
         when {
             isGpsLocation -> {
-                binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_current_location)
-                binding?.placeName?.visibility = View.GONE
-                binding?.placeName?.text = ""
+                binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_current_location)
+                binding.placeName.visibility = View.GONE
+                binding.placeName.text = ""
             }
             isGeocodedResult -> {
-                binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_this_location)
-                binding?.placeName?.visibility = View.VISIBLE
-                binding?.placeName?.text = geocodedName
+                binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
+                binding.placeName.visibility = View.VISIBLE
+                binding.placeName.text = geocodingResult?.displayName
             }
             else -> {
-                binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_this_location)
-                binding?.placeName?.visibility = View.GONE
-                binding?.placeName?.text = ""
+                binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
+                binding.placeName.visibility = View.GONE
+                binding.placeName.text = ""
             }
         }
     }
@@ -395,11 +441,14 @@ class LocationPickerController(args: Bundle) :
     }
 
     private fun executeShareLocation(selectedLat: Double?, selectedLon: Double?, locationName: String?) {
+        binding.roundedImageView.visibility = View.GONE
+        binding.sendingLocationProgressbar.visibility = View.VISIBLE
+
         val objectId = "geo:$selectedLat,$selectedLon"
 
         var locationNameToShare = locationName
         if (locationNameToShare.isNullOrBlank()) {
-            locationNameToShare = resources?.getString(R.string.nc_shared_location)
+            locationNameToShare = resources.getString(R.string.nc_shared_location)
         }
 
         val metaData: String =
@@ -410,8 +459,8 @@ class LocationPickerController(args: Bundle) :
         val apiVersion = ApiUtils.getChatApiVersion(currentUser, intArrayOf(1))
 
         ncApi.sendLocation(
-            ApiUtils.getCredentials(currentUser?.username, currentUser?.token),
-            ApiUtils.getUrlToSendLocation(apiVersion, currentUser?.baseUrl, roomToken),
+            ApiUtils.getCredentials(currentUser.username, currentUser.token),
+            ApiUtils.getUrlToSendLocation(apiVersion, currentUser.baseUrl, roomToken),
             "geo-location",
             objectId,
             metaData
@@ -424,13 +473,13 @@ class LocationPickerController(args: Bundle) :
                 }
 
                 override fun onNext(t: GenericOverall) {
-                    router.popCurrentController()
+                    finish()
                 }
 
                 override fun onError(e: Throwable) {
                     Log.e(TAG, "error when trying to share location", e)
                     Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
-                    router.popCurrentController()
+                    finish()
                 }
 
                 override fun onComplete() {
@@ -472,6 +521,8 @@ class LocationPickerController(args: Bundle) :
         permissions: Array<out String>,
         grantResults: IntArray
     ) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+
         fun areAllGranted(grantResults: IntArray): Boolean {
             grantResults.forEach {
                 if (it == PackageManager.PERMISSION_DENIED) return false
@@ -487,13 +538,6 @@ class LocationPickerController(args: Bundle) :
         }
     }
 
-    override fun receiveChosenGeocodingResult(lat: Double, lon: Double, name: String) {
-        receivedChosenGeocodingResult = true
-        geocodedLat = lat
-        geocodedLon = lon
-        geocodedName = name
-    }
-
     private fun initGeocoder() {
         val baseUrl = context!!.getString(R.string.osm_geocoder_url)
         val email = context!!.getString(R.string.osm_geocoder_contact)
@@ -542,8 +586,13 @@ class LocationPickerController(args: Bundle) :
         // empty
     }
 
+    override fun onBackPressed() {
+        setResult(Activity.RESULT_CANCELED)
+        finish()
+    }
+
     companion object {
-        private const val TAG = "LocPicker"
+        private val TAG = LocationPickerActivity::class.java.simpleName
         private const val REQUEST_PERMISSIONS_REQUEST_CODE = 1
         private const val PERSON_HOT_SPOT_X: Float = 20.0F
         private const val PERSON_HOT_SPOT_Y: Float = 20.0F

+ 1 - 0
app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt

@@ -85,4 +85,5 @@ object BundleKeys {
     const val KEY_NOTIFICATION_RESTRICT_DELETION = "KEY_NOTIFICATION_RESTRICT_DELETION"
     const val KEY_DISMISS_RECORDING_URL = "KEY_DISMISS_RECORDING_URL"
     const val KEY_SHARE_RECORDING_TO_CHAT_URL = "KEY_SHARE_RECORDING_TO_CHAT_URL"
+    const val KEY_GEOCODING_RESULT = "KEY_GEOCODING_RESULT"
 }

+ 19 - 0
app/src/main/res/layout/controller_geocoding.xml → app/src/main/res/layout/activity_geocoding.xml

@@ -20,11 +20,30 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/parent_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
 
+    <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/geocoding_appbar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <com.google.android.material.appbar.MaterialToolbar
+            android:id="@+id/geocoding_toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            android:background="@color/appbar"
+            android:theme="?attr/actionBarPopupTheme"
+            app:layout_scrollFlags="scroll|enterAlways"
+            app:navigationIconTint="@color/fontAppbar"
+            app:popupTheme="@style/appActionBarPopupMenu"
+            app:titleTextColor="@color/fontAppbar"
+            tools:title="@string/nc_app_product_name" />
+    </com.google.android.material.appbar.AppBarLayout>
+
     <ListView
         android:id="@+id/geocoding_results"
         android:layout_width="match_parent"

+ 25 - 0
app/src/main/res/layout/controller_location.xml → app/src/main/res/layout/activity_location.xml

@@ -29,6 +29,23 @@
     android:layout_height="match_parent"
     android:orientation="vertical">
 
+    <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/location_picker_appbar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <com.google.android.material.appbar.MaterialToolbar
+            android:id="@+id/location_picker_toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            android:background="@color/appbar"
+            android:theme="?attr/actionBarPopupTheme"
+            app:layout_scrollFlags="scroll|enterAlways"
+            app:navigationIconTint="@color/fontAppbar"
+            app:popupTheme="@style/appActionBarPopupMenu"
+            app:titleTextColor="@color/fontAppbar"
+            tools:title="@string/nc_app_product_name" />
+    </com.google.android.material.appbar.AppBarLayout>
+
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="0dp"
@@ -92,6 +109,14 @@
             android:contentDescription="@null"
             android:src="@drawable/ic_circular_location" />
 
+        <ProgressBar
+            android:id="@+id/sending_location_progressbar"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:visibility="gone">
+        </ProgressBar>
+
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"