migrate to MenuProvider

pull/543/head
akliuxingyuan 1 year ago
parent 025493a05f
commit acaad0490a

@ -638,15 +638,6 @@ dependencies {
implementation Deps.protobuf_javalite implementation Deps.protobuf_javalite
implementation Deps.google_material implementation Deps.google_material
implementation Deps.adjust
implementation Deps.installreferrer // Required by Adjust
implementation Deps.google_ads_id // Required for the Google Advertising ID
// Required for in-app reviews
implementation Deps.google_play_review
implementation Deps.google_play_review_ktx
androidTestImplementation Deps.uiautomator androidTestImplementation Deps.uiautomator
androidTestImplementation "tools.fastlane:screengrab:2.0.0" androidTestImplementation "tools.fastlane:screengrab:2.0.0"
// This Falcon version is added to maven central now required for Screengrab // This Falcon version is added to maven central now required for Screengrab

@ -12,6 +12,7 @@ import android.os.Bundle
import android.view.Gravity import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuItem
import android.view.MenuInflater import android.view.MenuInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -20,7 +21,10 @@ import android.view.inputmethod.EditorInfo
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.MenuHost
import androidx.core.view.MenuProvider
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
@ -69,16 +73,6 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
// downloaded for the non-suspending search function // downloaded for the non-suspending search function
private var addons: List<Addon>? = null private var addons: List<Addon>? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
logger.info("Creating view for AddonsManagementFragment")
setHasOptionsMenu(true)
return super.onCreateView(inflater, container, savedInstanceState)
}
private var installExternalAddonComplete: Boolean private var installExternalAddonComplete: Boolean
set(value) { set(value) {
arguments?.putBoolean(BUNDLE_KEY_INSTALL_EXTERNAL_ADDON_COMPLETE, value) arguments?.putBoolean(BUNDLE_KEY_INSTALL_EXTERNAL_ADDON_COMPLETE, value)
@ -90,28 +84,40 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
logger.info("View created for AddonsManagementFragment") logger.info("View created for AddonsManagementFragment")
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupMenu()
binding = FragmentAddOnsManagementBinding.bind(view) binding = FragmentAddOnsManagementBinding.bind(view)
bindRecyclerView() bindRecyclerView()
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { private fun setupMenu() {
inflater.inflate(R.menu.addons_menu, menu) val menuHost: MenuHost = requireActivity()
val searchItem = menu.findItem(R.id.search)
val searchView: SearchView = searchItem.actionView as SearchView menuHost.addMenuProvider(object : MenuProvider {
searchView.imeOptions = EditorInfo.IME_ACTION_DONE override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
searchView.queryHint = getString(R.string.addons_search_hint) inflater.inflate(R.menu.addons_menu, menu)
val searchItem = menu.findItem(R.id.search)
searchView.setOnQueryTextListener( val searchView: SearchView = searchItem.actionView as SearchView
object : SearchView.OnQueryTextListener { searchView.imeOptions = EditorInfo.IME_ACTION_DONE
override fun onQueryTextSubmit(query: String): Boolean { searchView.queryHint = getString(R.string.addons_search_hint)
return searchAddons(query.trim())
} searchView.setOnQueryTextListener(
object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return searchAddons(query.trim())
}
override fun onQueryTextChange(newText: String): Boolean { override fun onQueryTextChange(newText: String): Boolean {
return searchAddons(newText.trim()) return searchAddons(newText.trim())
} }
}, },
) )
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return true
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
} }
private fun searchAddons(addonNameSubStr: String): Boolean { private fun searchAddons(addonNameSubStr: String): Boolean {

@ -6,15 +6,10 @@ package org.mozilla.fenix.components
import android.app.Activity import android.app.Activity
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import com.google.android.play.core.review.ReviewInfo
import com.google.android.play.core.review.ReviewManager import com.google.android.play.core.review.ReviewManager
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.mozilla.fenix.GleanMetrics.ReviewPrompt
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
/** /**
* Interface that describes the settings needed to track the Review Prompt. * Interface that describes the settings needed to track the Review Prompt.
@ -55,11 +50,6 @@ class ReviewPromptController(
flow.addOnCompleteListener { flow.addOnCompleteListener {
if (it.isSuccessful) { if (it.isSuccessful) {
manager.launchReviewFlow(activity, it.result) manager.launchReviewFlow(activity, it.result)
recordReviewPromptEvent(
it.result.toString(),
reviewSettings.numberOfAppLaunches,
Date(),
)
} }
} }
} }
@ -108,44 +98,3 @@ class ReviewPromptController(
private const val NUMBER_OF_MONTHS_TO_PASS = 4 private const val NUMBER_OF_MONTHS_TO_PASS = 4
} }
} }
/**
* Records a [ReviewPrompt] with the required data.
*
* **Note:** The docs for [ReviewManager.launchReviewFlow] state 'In some circumstances the review
* flow will not be shown to the user, e.g. they have already seen it recently, so do not assume that
* calling this method will always display the review dialog.'
* However, investigation has shown that a [ReviewInfo] instance with the flag:
* - 'isNoOp=true' indicates that the prompt has NOT been displayed.
* - 'isNoOp=false' indicates that a prompt has been displayed.
* [ReviewManager.launchReviewFlow] will modify the ReviewInfo instance which can be used to determine
* which of these flags is present.
*/
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun recordReviewPromptEvent(
reviewInfoAsString: String,
numberOfAppLaunches: Int,
now: Date,
) {
val formattedLocalDatetime =
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()).format(now)
// The internals of ReviewInfo cannot be accessed directly or cast nicely, so lets simply use
// the object as a string.
// ReviewInfo is susceptible to changes outside of our control hence the catch-all 'else' statement.
val promptWasDisplayed = if (reviewInfoAsString.contains("isNoOp=true")) {
"false"
} else if (reviewInfoAsString.contains("isNoOp=false")) {
"true"
} else {
"error"
}
ReviewPrompt.promptAttempt.record(
ReviewPrompt.PromptAttemptExtra(
promptWasDisplayed = promptWasDisplayed,
localDatetime = formattedLocalDatetime,
numberOfAppLaunches = numberOfAppLaunches,
),
)
}

Loading…
Cancel
Save