Skip to content

Commit

Permalink
For mozilla-mobile#7249 Create a search widget
Browse files Browse the repository at this point in the history
  • Loading branch information
iorgamgabriel committed Aug 19, 2022
1 parent 63c3791 commit ee40969
Show file tree
Hide file tree
Showing 14 changed files with 342 additions and 12 deletions.
54 changes: 54 additions & 0 deletions app/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1900,3 +1900,57 @@ metrics:
metadata:
tags:
- Performance
search_widget_installed:
type: boolean
lifetime: application
description: |
Whether or not the search widget is installed
send_in_pings:
- metrics
bugs:
- https://github.com/mozilla-mobile/focus-android/issues/
data_reviews:
- https://github.com/mozilla-mobile/focus-android/pull/7474
data_sensitivity:
- interaction
notification_emails:
- [email protected]
expires: 119
metadata:
tags:
- Search

search_widget:
new_tab_button:
type: event
description: |
A user pressed anywhere from the Focus logo until the start of the
microphone icon, opening a new tab search screen.
bugs:
- https://github.com/mozilla-mobile/focus-android/issues/
data_reviews:
- https://github.com/mozilla-mobile/focus-android/pull/7474
data_sensitivity:
- interaction
notification_emails:
- [email protected]
expires: 119
metadata:
tags:
- Search
voice_button:
type: event
description: |
A user pressed the microphone icon, opening a new voice search screen.
bugs:
- https://github.com/mozilla-mobile/focus-android/issues/
data_reviews:
- https://github.com/mozilla-mobile/focus-android/pull/7474
data_sensitivity:
- interaction
notification_emails:
- [email protected]
expires: 119
metadata:
tags:
- Search
16 changes: 16 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@
<activity android:name=".activity.EraseAndOpenShortcutActivity"
android:theme="@android:style/Theme.Translucent" />

<activity
android:name=".searchwidget.VoiceSearchActivity"
android:theme="@style/Theme.AppCompat.Translucent" />

<provider
android:authorities="${applicationId}.fileprovider"
android:name="androidx.core.content.FileProvider"
Expand Down Expand Up @@ -161,6 +165,18 @@

<meta-data android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" />

<receiver
android:name=".searchwidget.SearchWidgetProvider"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/search_widget_info" />
</receiver>

</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import android.app.Activity
import android.content.Intent
import android.os.Bundle
import mozilla.components.feature.intent.ext.sanitize
import mozilla.components.feature.search.widget.BaseVoiceSearchActivity
import mozilla.components.service.glean.private.NoExtras
import mozilla.components.support.utils.toSafeIntent
import org.mozilla.focus.GleanMetrics.SearchWidget
import org.mozilla.focus.ext.components
import org.mozilla.focus.session.IntentProcessor
import org.mozilla.focus.utils.SupportUtils
Expand All @@ -25,14 +28,15 @@ class IntentReceiverActivity : Activity() {
super.onCreate(savedInstanceState)

val intent = intent.sanitize().toSafeIntent()

if (intent.getBooleanExtra(SEARCH_WIDGET, false)) {
SearchWidget.newTabButton.record(NoExtras())
}
if (intent.dataString.equals(SupportUtils.OPEN_WITH_DEFAULT_BROWSER_URL)) {
dispatchNormalIntent()
return
}

val result = intentProcessor.handleIntent(this, intent, savedInstanceState)

if (result is IntentProcessor.Result.CustomTab) {
dispatchCustomTabsIntent(result.id)
} else {
Expand All @@ -43,6 +47,7 @@ class IntentReceiverActivity : Activity() {
}

private fun dispatchCustomTabsIntent(tabId: String) {

val intent = Intent(intent)

intent.setClassName(applicationContext, CustomTabActivity::class.java.name)
Expand All @@ -58,7 +63,15 @@ class IntentReceiverActivity : Activity() {
val intent = Intent(intent)
intent.setClassName(applicationContext, MainActivity::class.java.name)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP

intent.putExtra(SEARCH_WIDGET, intent.getBooleanExtra(SEARCH_WIDGET, false))
intent.putExtra(
BaseVoiceSearchActivity.SPEECH_PROCESSING,
intent.getStringExtra(BaseVoiceSearchActivity.SPEECH_PROCESSING)
)
startActivity(intent)
}

companion object {
const val SEARCH_WIDGET = "search_widget"
}
}
53 changes: 46 additions & 7 deletions app/src/main/java/org/mozilla/focus/activity/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.isVisible
import androidx.preference.PreferenceManager
import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.state.state.SessionState
import mozilla.components.concept.engine.EngineView
import mozilla.components.feature.search.widget.BaseVoiceSearchActivity
import mozilla.components.lib.auth.canUseBiometricFeature
import mozilla.components.lib.crash.Crash
import mozilla.components.service.glean.private.NoExtras
Expand Down Expand Up @@ -51,6 +53,7 @@ import org.mozilla.focus.state.Screen
import org.mozilla.focus.telemetry.TelemetryWrapper
import org.mozilla.focus.telemetry.startuptelemetry.StartupPathProvider
import org.mozilla.focus.telemetry.startuptelemetry.StartupTypeTelemetry
import org.mozilla.focus.utils.SearchUtils
import org.mozilla.focus.utils.StatusBarUtils
import org.mozilla.focus.utils.SupportUtils

Expand Down Expand Up @@ -78,7 +81,6 @@ open class MainActivity : LocaleAwareAppCompatActivity() {
updateSecureWindowFlags()

super.onCreate(savedInstanceState)

_binding = ActivityMainBinding.inflate(layoutInflater)

// Checks if Activity is currently in PiP mode if launched from external intents, then exits it
Expand Down Expand Up @@ -113,12 +115,8 @@ open class MainActivity : LocaleAwareAppCompatActivity() {
}

val safeIntent = SafeIntent(intent)
val isTheFirstLaunch = settings.getAppLaunchCount() == 0
if (isTheFirstLaunch) {
setSplashScreenPreDrawListener(safeIntent)
} else {
showFirstScreen(safeIntent)
}

handleSearchWidgetNavigation(safeIntent)

if (intent.hasExtra(HomeScreen.ADD_TO_HOMESCREEN_TAG)) {
intentProcessor.handleNewIntent(this, safeIntent)
Expand All @@ -139,6 +137,27 @@ open class MainActivity : LocaleAwareAppCompatActivity() {
AppReviewUtils.showAppReview(this)
}

private fun handleSearchWidgetNavigation(safeIntent: SafeIntent) {
val voiceSearchText = safeIntent.getStringExtra(BaseVoiceSearchActivity.SPEECH_PROCESSING)
if (!voiceSearchText.isNullOrEmpty()) {
openVoiceSearchBrowser(voiceSearchText)
return
}

val searchWidgetIntent = safeIntent.getBooleanExtra(IntentReceiverActivity.SEARCH_WIDGET, false)
if (searchWidgetIntent) {
showHomeScreen()
return
}

val isTheFirstLaunch = settings.getAppLaunchCount() == 0
if (isTheFirstLaunch) {
setSplashScreenPreDrawListener(safeIntent)
} else {
showFirstScreen(safeIntent)
}
}

private fun setSplashScreenPreDrawListener(safeIntent: SafeIntent) {
val endTime = System.currentTimeMillis() + REQUEST_TIME_OUT
binding.container.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
Expand All @@ -155,6 +174,26 @@ open class MainActivity : LocaleAwareAppCompatActivity() {
)
}

private fun openVoiceSearchBrowser(voiceSearchText: String) {
val tabId = this.components.tabsUseCases.addTab(
url = SearchUtils.createSearchUrl(
this,
voiceSearchText
),
source = SessionState.Source.External.ActionSend(null),
searchTerms = voiceSearchText,
selectTab = true,
private = true
)
components.appStore.dispatch(AppAction.OpenTab(tabId))
lifecycle.addObserver(navigator)
}

private fun showHomeScreen() {
components.appStore.dispatch(AppAction.ShowHomeScreen)
lifecycle.addObserver(navigator)
}

private fun showFirstScreen(safeIntent: SafeIntent) {
// The performance check was added after the shouldShowFirstRun to take as much of the
// code path as possible
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.focus.searchwidget

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.annotation.VisibleForTesting
import mozilla.components.feature.search.widget.AppSearchWidgetProvider
import mozilla.components.feature.search.widget.BaseVoiceSearchActivity
import mozilla.components.feature.search.widget.SearchWidgetConfig
import mozilla.components.support.utils.PendingIntentUtils
import org.mozilla.focus.R
import org.mozilla.focus.activity.IntentReceiverActivity
import org.mozilla.focus.ext.components

class SearchWidgetProvider : AppSearchWidgetProvider() {

override fun onEnabled(context: Context) {
context.components.settings.addSearchWidgetInstalled(1)
}

override fun onDeleted(context: Context, appWidgetIds: IntArray) {
context.components.settings.addSearchWidgetInstalled(-appWidgetIds.size)
}

override val config: SearchWidgetConfig =
SearchWidgetConfig(
searchWidgetIconResource = R.drawable.ic_splash_screen,
searchWidgetMicrophoneResource = R.drawable.mozac_ic_microphone,
appName = R.string.app_name
)

override fun createTextSearchIntent(context: Context): PendingIntent {
val textSearchIntent = Intent(context, IntentReceiverActivity::class.java)
.apply {
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
this.putExtra(IntentReceiverActivity.SEARCH_WIDGET, true)
}
return PendingIntent.getActivity(
context,
REQUEST_CODE_NEW_TAB,
textSearchIntent,
PendingIntentUtils.defaultFlags or
PendingIntent.FLAG_UPDATE_CURRENT
)
}

override fun shouldShowVoiceSearch(context: Context): Boolean {
return true
}

override fun voiceSearchActivity(): Class<out BaseVoiceSearchActivity> {
return VoiceSearchActivity::class.java
}

companion object {
@VisibleForTesting
const val REQUEST_CODE_NEW_TAB = 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.focus.searchwidget

import android.content.Intent
import mozilla.components.feature.search.widget.BaseVoiceSearchActivity
import mozilla.components.support.locale.LocaleManager
import mozilla.components.support.locale.LocaleManager.getCurrentLocale
import mozilla.telemetry.glean.private.NoExtras
import org.mozilla.focus.GleanMetrics.SearchWidget
import org.mozilla.focus.activity.IntentReceiverActivity
import java.util.Locale

class VoiceSearchActivity : BaseVoiceSearchActivity() {

override fun getCurrentLocale(): Locale {
return getCurrentLocale(this)
?: LocaleManager.getSystemDefault()
}

override fun onSpeechRecognitionEnded(spokenText: String) {
val intent = Intent(this, IntentReceiverActivity::class.java)
intent.putExtra(SPEECH_PROCESSING, spokenText)
startActivity(intent)
}

override fun onSpeechRecognitionStarted() {
SearchWidget.voiceButton.record(NoExtras())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.mozilla.focus.Components
import org.mozilla.focus.GleanMetrics.Browser
import org.mozilla.focus.GleanMetrics.GleanBuildInfo
import org.mozilla.focus.GleanMetrics.LegacyIds
import org.mozilla.focus.GleanMetrics.Metrics
import org.mozilla.focus.GleanMetrics.MozillaProducts
import org.mozilla.focus.GleanMetrics.Pings
import org.mozilla.focus.GleanMetrics.Preferences
Expand Down Expand Up @@ -75,7 +76,7 @@ class GleanMetricsService(context: Context) : MetricsService {
GlobalScope.launch(IO) {

// Wait for preferences to be collected before we send the activation ping.
collectPrefMetrics(components, settings, context).await()
collectPrefMetricsAsync(components, settings, context).await()

// Set the client ID in Glean as part of the deletion-request.
LegacyIds.clientId.set(UUID.fromString(TelemetryWrapper.clientId))
Expand All @@ -90,7 +91,7 @@ class GleanMetricsService(context: Context) : MetricsService {
}
}

private fun collectPrefMetrics(
private fun collectPrefMetricsAsync(
components: Components,
settings: Settings,
context: Context
Expand All @@ -100,6 +101,8 @@ class GleanMetricsService(context: Context) : MetricsService {
val isFenixDefaultBrowser = FenixProductDetector.isFenixDefaultBrowser(installedBrowsers.defaultBrowser)
val isFocusDefaultBrowser = installedBrowsers.isDefaultBrowser

Metrics.searchWidgetInstalled.set(settings.searchWidgetInstalled)

Browser.isDefault.set(isFocusDefaultBrowser)
Browser.localeOverride.set(components.store.state.locale?.displayName ?: "none")
val shortcutsOnHomeNumber = components.topSitesStorage.getTopSites(
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/org/mozilla/focus/utils/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,20 @@ class Settings(
.commit()
}

fun addSearchWidgetInstalled(count: Int) {
val key = getPreferenceKey(R.string.pref_key_search_widget_installed)
val newValue = preferences.getInt(key, 0) + count
preferences.edit()
.putInt(key, newValue)
.apply()
}

val searchWidgetInstalled: Boolean
get() = 0 < preferences.getInt(
getPreferenceKey(R.string.pref_key_search_widget_installed),
0
)

fun getHttpsOnlyMode(): Engine.HttpsOnlyMode {
return if (preferences.getBoolean(getPreferenceKey(R.string.pref_key_https_only), true)) {
Engine.HttpsOnlyMode.ENABLED
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions app/src/main/res/values/preference_keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@

<string name="pref_key_category_security" translatable="false"><xliff:g id="preference_key">security_category</xliff:g></string>

<string name="pref_key_search_widget_installed" translatable="false"><xliff:g id="preference_key">pref_key_search_widget_installed</xliff:g></string>

<string name="pref_key_homescreen_tips" translatable="false">
<xliff:g id="preference_key">use_homescreen_tips</xliff:g>
</string>
Expand Down
Loading

0 comments on commit ee40969

Please sign in to comment.