|
@ -22,6 +22,15 @@
|
||||||
<activity android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
|
<activity android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
|
||||||
android:exported="true"/>
|
android:exported="true"/>
|
||||||
<service android:name="com.facebook.flipper.plugins.leakcanary.RecordLeakService" />
|
<service android:name="com.facebook.flipper.plugins.leakcanary.RecordLeakService" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".HomeActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.app.shortcuts"
|
||||||
|
android:resource="@xml/shortcuts_debug"
|
||||||
|
tools:node="replace" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="open_new_tab"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_static_shortcut_tab"
|
||||||
|
android:shortcutShortLabel="@string/home_screen_shortcut_open_new_tab"
|
||||||
|
android:shortcutLongLabel="@string/home_screen_shortcut_open_new_tab">
|
||||||
|
<intent
|
||||||
|
android:action="org.mozilla.fenix.OPEN_TAB"
|
||||||
|
android:targetPackage="org.mozilla.fenix.debug"
|
||||||
|
android:targetClass="org.mozilla.fenix.IntentReceiverActivity" />
|
||||||
|
</shortcut>
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="open_new_private_tab"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_static_shortcut_private_tab"
|
||||||
|
android:shortcutShortLabel="@string/home_screen_shortcut_open_new_private_tab"
|
||||||
|
android:shortcutLongLabel="@string/home_screen_shortcut_open_new_private_tab">
|
||||||
|
<intent
|
||||||
|
android:action="org.mozilla.fenix.OPEN_PRIVATE_TAB"
|
||||||
|
android:targetPackage="org.mozilla.fenix.debug"
|
||||||
|
android:targetClass="org.mozilla.fenix.IntentReceiverActivity" />
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|
|
@ -10,6 +10,7 @@
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
|
||||||
|
|
||||||
<!-- Needed to prompt the user to give permission to install a downloaded apk -->
|
<!-- Needed to prompt the user to give permission to install a downloaded apk -->
|
||||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission-sdk-23 android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
|
@ -58,6 +59,10 @@
|
||||||
<data android:scheme="fenix"
|
<data android:scheme="fenix"
|
||||||
android:host="make_default_browser"/>
|
android:host="make_default_browser"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.app.shortcuts"
|
||||||
|
android:resource="@xml/shortcuts" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -118,6 +123,54 @@
|
||||||
android:resource="@mipmap/ic_launcher" />
|
android:resource="@mipmap/ic_launcher" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name="org.mozilla.fenix.alias.IntentReceiverActivity"
|
||||||
|
android:label="@string/app_name_private"
|
||||||
|
android:icon="@mipmap/ic_launcher_private"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_private_round"
|
||||||
|
android:targetActivity=".IntentReceiverActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:mimeType="text/html" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
<data android:mimeType="application/xhtml+xml" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.ASSIST" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="com.android.systemui.action_assist_icon"
|
||||||
|
android:resource="@mipmap/ic_launcher_private" />
|
||||||
|
<meta-data
|
||||||
|
android:name="private"
|
||||||
|
android:value="true" />
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".browser.BrowserPerformanceTestActivity"
|
android:name=".browser.BrowserPerformanceTestActivity"
|
||||||
android:enabled="${isRaptorEnabled}"
|
android:enabled="${isRaptorEnabled}"
|
||||||
|
|
After Width: | Height: | Size: 20 KiB |
|
@ -86,6 +86,8 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
final override fun onCreate(savedInstanceState: Bundle?) {
|
final override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setPrivateModeIfNecessary()
|
||||||
|
|
||||||
components.publicSuffixList.prefetch()
|
components.publicSuffixList.prefetch()
|
||||||
setupThemeAndBrowsingMode()
|
setupThemeAndBrowsingMode()
|
||||||
|
|
||||||
|
@ -169,6 +171,20 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External sources such as 3rd party links and shortcuts use this function to enter
|
||||||
|
* private mode directly before the content view is created.
|
||||||
|
*/
|
||||||
|
private fun setPrivateModeIfNecessary() {
|
||||||
|
intent?.toSafeIntent()?.let {
|
||||||
|
if (it.hasExtra(PRIVATE_BROWSING_MODE)) {
|
||||||
|
val startPrivateMode = it.getBooleanExtra(PRIVATE_BROWSING_MODE, false)
|
||||||
|
settings.usePrivateMode = startPrivateMode
|
||||||
|
intent.removeExtra(PRIVATE_BROWSING_MODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupThemeAndBrowsingMode() {
|
private fun setupThemeAndBrowsingMode() {
|
||||||
browsingModeManager = createBrowsingModeManager()
|
browsingModeManager = createBrowsingModeManager()
|
||||||
themeManager = createThemeManager()
|
themeManager = createThemeManager()
|
||||||
|
@ -347,6 +363,7 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
const val OPEN_TO_BROWSER = "open_to_browser"
|
const val OPEN_TO_BROWSER = "open_to_browser"
|
||||||
const val OPEN_TO_BROWSER_AND_LOAD = "open_to_browser_and_load"
|
const val OPEN_TO_BROWSER_AND_LOAD = "open_to_browser_and_load"
|
||||||
const val OPEN_TO_SEARCH = "open_to_search"
|
const val OPEN_TO_SEARCH = "open_to_search"
|
||||||
|
const val PRIVATE_BROWSING_MODE = "private_browsing_mode"
|
||||||
const val EXTRA_DELETE_PRIVATE_TABS = "notification_delete_and_open"
|
const val EXTRA_DELETE_PRIVATE_TABS = "notification_delete_and_open"
|
||||||
const val EXTRA_OPENED_FROM_NOTIFICATION = "notification_open"
|
const val EXTRA_OPENED_FROM_NOTIFICATION = "notification_open"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package org.mozilla.fenix
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.speech.RecognizerIntent
|
import android.speech.RecognizerIntent
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
|
@ -17,6 +18,7 @@ import org.mozilla.fenix.customtabs.CustomTabActivity
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.metrics
|
import org.mozilla.fenix.ext.metrics
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
|
import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
|
||||||
|
|
||||||
class IntentReceiverActivity : Activity() {
|
class IntentReceiverActivity : Activity() {
|
||||||
|
|
||||||
|
@ -33,7 +35,10 @@ class IntentReceiverActivity : Activity() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val isPrivate = this.settings.usePrivateMode
|
val isPrivate = packageManager
|
||||||
|
?.getActivityInfo(componentName, PackageManager.GET_META_DATA)
|
||||||
|
?.metaData
|
||||||
|
?.getBoolean(PRIVATE_MODE) ?: this.settings.usePrivateMode
|
||||||
|
|
||||||
MainScope().launch {
|
MainScope().launch {
|
||||||
// The intent property is nullable, but the rest of the code below
|
// The intent property is nullable, but the rest of the code below
|
||||||
|
@ -79,6 +84,24 @@ class IntentReceiverActivity : Activity() {
|
||||||
// from a session that the user already "erased".
|
// from a session that the user already "erased".
|
||||||
intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == 0
|
intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == 0
|
||||||
}
|
}
|
||||||
|
intent.action == ACTION_OPEN_TAB || intent.action == ACTION_OPEN_PRIVATE_TAB -> {
|
||||||
|
intent.setClassName(applicationContext, HomeActivity::class.java.name)
|
||||||
|
val startPrivateMode = (intent.action == ACTION_OPEN_PRIVATE_TAB)
|
||||||
|
if (startPrivateMode) {
|
||||||
|
intent.putExtra(
|
||||||
|
HomeActivity.OPEN_TO_SEARCH,
|
||||||
|
StartSearchIntentProcessor.STATIC_SHORTCUT_NEW_PRIVATE_TAB
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
intent.putExtra(
|
||||||
|
HomeActivity.OPEN_TO_SEARCH,
|
||||||
|
StartSearchIntentProcessor.STATIC_SHORTCUT_NEW_TAB
|
||||||
|
)
|
||||||
|
}
|
||||||
|
intent.putExtra(HomeActivity.PRIVATE_BROWSING_MODE, startPrivateMode)
|
||||||
|
intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
true
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
intent.setClassName(applicationContext, HomeActivity::class.java.name)
|
intent.setClassName(applicationContext, HomeActivity::class.java.name)
|
||||||
false
|
false
|
||||||
|
@ -124,5 +147,8 @@ class IntentReceiverActivity : Activity() {
|
||||||
private const val SPEECH_REQUEST_CODE = 0
|
private const val SPEECH_REQUEST_CODE = 0
|
||||||
const val SPEECH_PROCESSING = "speech_processing"
|
const val SPEECH_PROCESSING = "speech_processing"
|
||||||
const val PREVIOUS_INTENT = "previous_intent"
|
const val PREVIOUS_INTENT = "previous_intent"
|
||||||
|
const val PRIVATE_MODE = "private"
|
||||||
|
const val ACTION_OPEN_TAB = "org.mozilla.fenix.OPEN_TAB"
|
||||||
|
const val ACTION_OPEN_PRIVATE_TAB = "org.mozilla.fenix.OPEN_PRIVATE_TAB"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/* 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.fenix.components
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the creation of pinned shortcuts.
|
||||||
|
*/
|
||||||
|
object PrivateShortcutCreateManager {
|
||||||
|
|
||||||
|
fun createPrivateShortcut(context: Context) {
|
||||||
|
if (!ShortcutManagerCompat.isRequestPinShortcutSupported(context)) return
|
||||||
|
|
||||||
|
val icon = IconCompat.createWithResource(context, R.mipmap.ic_launcher_private_round)
|
||||||
|
val shortcut = ShortcutInfoCompat.Builder(context, UUID.randomUUID().toString())
|
||||||
|
.setShortLabel(context.getString(R.string.app_name_private))
|
||||||
|
.setLongLabel(context.getString(R.string.app_name_private))
|
||||||
|
.setIcon(icon)
|
||||||
|
.setIntent(Intent(context, HomeActivity::class.java).apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
putExtra(HomeActivity.PRIVATE_BROWSING_MODE, true)
|
||||||
|
putExtra(
|
||||||
|
HomeActivity.OPEN_TO_SEARCH,
|
||||||
|
StartSearchIntentProcessor.PRIVATE_BROWSING_PINNED_SHORTCUT
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
val homeScreenIntent = Intent(Intent.ACTION_MAIN)
|
||||||
|
.addCategory(Intent.CATEGORY_HOME)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
val intentSender = PendingIntent
|
||||||
|
.getActivity(context, 0, homeScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
.intentSender
|
||||||
|
ShortcutManagerCompat.requestPinShortcut(context, shortcut, intentSender)
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,9 +9,13 @@ import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.PopupWindow
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
@ -54,15 +58,18 @@ import org.mozilla.fenix.BrowserDirection
|
||||||
import org.mozilla.fenix.FenixViewModelProvider
|
import org.mozilla.fenix.FenixViewModelProvider
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
import org.mozilla.fenix.collections.CreateCollectionViewModel
|
||||||
import org.mozilla.fenix.collections.SaveCollectionStep
|
import org.mozilla.fenix.collections.SaveCollectionStep
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
|
import org.mozilla.fenix.components.PrivateShortcutCreateManager
|
||||||
import org.mozilla.fenix.components.TabCollectionStorage
|
import org.mozilla.fenix.components.TabCollectionStorage
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.metrics
|
import org.mozilla.fenix.ext.metrics
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.sessionsOfType
|
import org.mozilla.fenix.ext.sessionsOfType
|
||||||
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.ext.toTab
|
import org.mozilla.fenix.ext.toTab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
||||||
import org.mozilla.fenix.home.sessioncontrol.Mode
|
import org.mozilla.fenix.home.sessioncontrol.Mode
|
||||||
|
@ -84,7 +91,6 @@ import org.mozilla.fenix.onboarding.FenixOnboarding
|
||||||
import org.mozilla.fenix.settings.SupportUtils
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
import org.mozilla.fenix.share.ShareTab
|
import org.mozilla.fenix.share.ShareTab
|
||||||
import org.mozilla.fenix.utils.FragmentPreDrawManager
|
import org.mozilla.fenix.utils.FragmentPreDrawManager
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
import org.mozilla.fenix.utils.allowUndo
|
import org.mozilla.fenix.utils.allowUndo
|
||||||
import org.mozilla.fenix.whatsnew.WhatsNew
|
import org.mozilla.fenix.whatsnew.WhatsNew
|
||||||
|
|
||||||
|
@ -212,7 +218,7 @@ class HomeFragment : Fragment(), AccountObserver {
|
||||||
|
|
||||||
val searchEngine = requireComponents.search.searchEngineManager.getDefaultSearchEngineAsync(
|
val searchEngine = requireComponents.search.searchEngineManager.getDefaultSearchEngineAsync(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
Settings.getInstance(requireContext()).defaultSearchEngineName
|
requireContext().settings.defaultSearchEngineName
|
||||||
)
|
)
|
||||||
val searchIcon = BitmapDrawable(resources, searchEngine.icon)
|
val searchIcon = BitmapDrawable(resources, searchEngine.icon)
|
||||||
searchIcon.setBounds(0, 0, iconSize, iconSize)
|
searchIcon.setBounds(0, 0, iconSize, iconSize)
|
||||||
|
@ -251,6 +257,10 @@ class HomeFragment : Fragment(), AccountObserver {
|
||||||
) { newMode ->
|
) { newMode ->
|
||||||
invokePendingDeleteJobs()
|
invokePendingDeleteJobs()
|
||||||
|
|
||||||
|
if (newMode == BrowsingMode.Private) {
|
||||||
|
requireContext().settings.incrementNumTimesPrivateModeOpened()
|
||||||
|
}
|
||||||
|
|
||||||
if (onboarding.userHasBeenOnboarded()) {
|
if (onboarding.userHasBeenOnboarded()) {
|
||||||
getManagedEmitter<SessionControlChange>().onNext(
|
getManagedEmitter<SessionControlChange>().onNext(
|
||||||
SessionControlChange.ModeChange(Mode.fromBrowsingMode(newMode))
|
SessionControlChange.ModeChange(Mode.fromBrowsingMode(newMode))
|
||||||
|
@ -290,6 +300,11 @@ class HomeFragment : Fragment(), AccountObserver {
|
||||||
(activity as AppCompatActivity).supportActionBar?.hide()
|
(activity as AppCompatActivity).supportActionBar?.hide()
|
||||||
|
|
||||||
requireComponents.backgroundServices.accountManager.register(this, owner = this)
|
requireComponents.backgroundServices.accountManager.register(this, owner = this)
|
||||||
|
|
||||||
|
if (requireContext().settings.showPrivateModeContextualFeatureRecommender &&
|
||||||
|
browsingModeManager.mode.isPrivate) {
|
||||||
|
recommendPrivateBrowsingShortcut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -543,6 +558,34 @@ class HomeFragment : Fragment(), AccountObserver {
|
||||||
homeViewModel.motionLayoutProgress = homeLayout?.progress ?: 0F
|
homeViewModel.motionLayoutProgress = homeLayout?.progress ?: 0F
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun recommendPrivateBrowsingShortcut() {
|
||||||
|
context?.let {
|
||||||
|
val layout = LayoutInflater.from(it)
|
||||||
|
.inflate(R.layout.pbm_shortcut_popup, null)
|
||||||
|
val trackingOnboarding =
|
||||||
|
PopupWindow(
|
||||||
|
layout,
|
||||||
|
(resources.displayMetrics.widthPixels / CFR_WIDTH_DIVIDER).toInt(),
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
layout.findViewById<Button>(R.id.cfr_pos_button).apply {
|
||||||
|
setOnClickListener {
|
||||||
|
PrivateShortcutCreateManager.createPrivateShortcut(context)
|
||||||
|
trackingOnboarding.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layout.findViewById<Button>(R.id.cfr_neg_button).apply {
|
||||||
|
setOnClickListener { trackingOnboarding.dismiss() }
|
||||||
|
}
|
||||||
|
// We want to show the popup only after privateBrowsingButton is available.
|
||||||
|
// Otherwise, we will encounter an activity token error.
|
||||||
|
privateBrowsingButton.post {
|
||||||
|
trackingOnboarding.showAsDropDown(privateBrowsingButton, 0, CFR_Y_OFFSET, Gravity.TOP or Gravity.END)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun hideOnboardingIfNeeded() {
|
private fun hideOnboardingIfNeeded() {
|
||||||
if (!onboarding.userHasBeenOnboarded()) {
|
if (!onboarding.userHasBeenOnboarded()) {
|
||||||
onboarding.finish()
|
onboarding.finish()
|
||||||
|
@ -896,6 +939,8 @@ class HomeFragment : Fragment(), AccountObserver {
|
||||||
private const val TELEMETRY_HOME_IDENITIFIER = "home"
|
private const val TELEMETRY_HOME_IDENITIFIER = "home"
|
||||||
private const val SHARED_TRANSITION_MS = 200L
|
private const val SHARED_TRANSITION_MS = 200L
|
||||||
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
||||||
|
private const val CFR_WIDTH_DIVIDER = 1.7
|
||||||
|
private const val CFR_Y_OFFSET = -20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,20 @@ import org.mozilla.fenix.ext.nav
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the search widget is tapped, Fenix should open to the search fragment.
|
* When the search widget is tapped, Fenix should open to the search fragment.
|
||||||
|
* Tapping the private browsing mode launcher icon should also open to the search fragment.
|
||||||
*/
|
*/
|
||||||
class StartSearchIntentProcessor(
|
class StartSearchIntentProcessor(
|
||||||
private val metrics: MetricController
|
private val metrics: MetricController
|
||||||
) : HomeIntentProcessor {
|
) : HomeIntentProcessor {
|
||||||
|
|
||||||
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
|
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
|
||||||
return if (intent.extras?.getBoolean(HomeActivity.OPEN_TO_SEARCH) == true) {
|
val event = intent.extras?.getString(HomeActivity.OPEN_TO_SEARCH)
|
||||||
out.putExtra(HomeActivity.OPEN_TO_SEARCH, false)
|
return if (event != null) {
|
||||||
metrics.track(Event.SearchWidgetNewTabPressed)
|
when (event) {
|
||||||
|
SEARCH_WIDGET -> metrics.track(Event.SearchWidgetNewTabPressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
out.removeExtra(HomeActivity.OPEN_TO_SEARCH)
|
||||||
|
|
||||||
val directions = NavGraphDirections.actionGlobalSearch(
|
val directions = NavGraphDirections.actionGlobalSearch(
|
||||||
sessionId = null,
|
sessionId = null,
|
||||||
|
@ -34,4 +39,11 @@ class StartSearchIntentProcessor(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SEARCH_WIDGET = "search_widget"
|
||||||
|
const val STATIC_SHORTCUT_NEW_TAB = "static_shortcut_new_tab"
|
||||||
|
const val STATIC_SHORTCUT_NEW_PRIVATE_TAB = "static_shortcut_new_private_tab"
|
||||||
|
const val PRIVATE_BROWSING_PINNED_SHORTCUT = "private_browsing_pinned_shortcut"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.mozilla.fenix.R.string.pref_key_accessibility
|
||||||
import org.mozilla.fenix.R.string.pref_key_account
|
import org.mozilla.fenix.R.string.pref_key_account
|
||||||
import org.mozilla.fenix.R.string.pref_key_account_auth_error
|
import org.mozilla.fenix.R.string.pref_key_account_auth_error
|
||||||
import org.mozilla.fenix.R.string.pref_key_account_category
|
import org.mozilla.fenix.R.string.pref_key_account_category
|
||||||
|
import org.mozilla.fenix.R.string.pref_key_add_private_browsing_shortcut
|
||||||
import org.mozilla.fenix.R.string.pref_key_data_choices
|
import org.mozilla.fenix.R.string.pref_key_data_choices
|
||||||
import org.mozilla.fenix.R.string.pref_key_delete_browsing_data
|
import org.mozilla.fenix.R.string.pref_key_delete_browsing_data
|
||||||
import org.mozilla.fenix.R.string.pref_key_help
|
import org.mozilla.fenix.R.string.pref_key_help
|
||||||
|
@ -52,6 +53,7 @@ import org.mozilla.fenix.R.string.pref_key_site_permissions
|
||||||
import org.mozilla.fenix.R.string.pref_key_theme
|
import org.mozilla.fenix.R.string.pref_key_theme
|
||||||
import org.mozilla.fenix.R.string.pref_key_tracking_protection_settings
|
import org.mozilla.fenix.R.string.pref_key_tracking_protection_settings
|
||||||
import org.mozilla.fenix.R.string.pref_key_your_rights
|
import org.mozilla.fenix.R.string.pref_key_your_rights
|
||||||
|
import org.mozilla.fenix.components.PrivateShortcutCreateManager
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.getPreferenceKey
|
import org.mozilla.fenix.ext.getPreferenceKey
|
||||||
|
@ -142,7 +144,7 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
|
||||||
updateAccountUIState(context!!, requireComponents.backgroundServices.accountManager.accountProfile())
|
updateAccountUIState(context!!, requireComponents.backgroundServices.accountManager.accountProfile())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ComplexMethod")
|
@Suppress("ComplexMethod", "LongMethod")
|
||||||
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||||
when (preference.key) {
|
when (preference.key) {
|
||||||
resources.getString(pref_key_search_engine_settings) -> {
|
resources.getString(pref_key_search_engine_settings) -> {
|
||||||
|
@ -154,6 +156,9 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
|
||||||
resources.getString(pref_key_site_permissions) -> {
|
resources.getString(pref_key_site_permissions) -> {
|
||||||
navigateToSitePermissions()
|
navigateToSitePermissions()
|
||||||
}
|
}
|
||||||
|
resources.getString(pref_key_add_private_browsing_shortcut) -> {
|
||||||
|
PrivateShortcutCreateManager.createPrivateShortcut(requireContext())
|
||||||
|
}
|
||||||
resources.getString(pref_key_accessibility) -> {
|
resources.getString(pref_key_accessibility) -> {
|
||||||
navigateToAccessibility()
|
navigateToAccessibility()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.utils
|
package org.mozilla.fenix.utils
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.MODE_PRIVATE
|
import android.content.Context.MODE_PRIVATE
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
@ -18,6 +19,7 @@ import mozilla.components.support.ktx.android.content.stringPreference
|
||||||
import org.mozilla.fenix.BuildConfig
|
import org.mozilla.fenix.BuildConfig
|
||||||
import org.mozilla.fenix.Config
|
import org.mozilla.fenix.Config
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.components.metrics.MozillaProductDetector
|
||||||
import org.mozilla.fenix.ext.getPreferenceKey
|
import org.mozilla.fenix.ext.getPreferenceKey
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import java.security.InvalidParameterException
|
import java.security.InvalidParameterException
|
||||||
|
@ -35,6 +37,8 @@ class Settings private constructor(
|
||||||
const val FENIX_PREFERENCES = "fenix_preferences"
|
const val FENIX_PREFERENCES = "fenix_preferences"
|
||||||
private const val BLOCKED_INT = 0
|
private const val BLOCKED_INT = 0
|
||||||
private const val ASK_TO_ALLOW_INT = 1
|
private const val ASK_TO_ALLOW_INT = 1
|
||||||
|
private const val CFR_COUNT_CONDITION_FOCUS_INSTALLED = 1
|
||||||
|
private const val CFR_COUNT_CONDITION_FOCUS_NOT_INSTALLED = 3
|
||||||
|
|
||||||
private fun actionToInt(action: SitePermissionsRules.Action) = when (action) {
|
private fun actionToInt(action: SitePermissionsRules.Action) = when (action) {
|
||||||
SitePermissionsRules.Action.BLOCKED -> BLOCKED_INT
|
SitePermissionsRules.Action.BLOCKED -> BLOCKED_INT
|
||||||
|
@ -247,4 +251,37 @@ class Settings private constructor(
|
||||||
appContext.getPreferenceKey(R.string.pref_key_search_widget_installed),
|
appContext.getPreferenceKey(R.string.pref_key_search_widget_installed),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun incrementNumTimesPrivateModeOpened() {
|
||||||
|
preferences.edit().putInt(
|
||||||
|
appContext.getPreferenceKey(R.string.pref_key_private_mode_opened),
|
||||||
|
numTimesPrivateModeOpened + 1
|
||||||
|
).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var showedPrivateModeContextualFeatureRecommender by booleanPreference(
|
||||||
|
appContext.getPreferenceKey(R.string.pref_key_showed_private_mode_cfr),
|
||||||
|
default = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private val numTimesPrivateModeOpened: Int
|
||||||
|
get() = preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_private_mode_opened), 0)
|
||||||
|
|
||||||
|
val showPrivateModeContextualFeatureRecommender: Boolean
|
||||||
|
get() {
|
||||||
|
val focusInstalled = MozillaProductDetector
|
||||||
|
.getInstalledMozillaProducts(appContext as Application)
|
||||||
|
.contains(MozillaProductDetector.MozillaProducts.FOCUS.productName)
|
||||||
|
|
||||||
|
val showCondition =
|
||||||
|
(numTimesPrivateModeOpened == CFR_COUNT_CONDITION_FOCUS_INSTALLED && focusInstalled) ||
|
||||||
|
(numTimesPrivateModeOpened == CFR_COUNT_CONDITION_FOCUS_NOT_INSTALLED && !focusInstalled)
|
||||||
|
|
||||||
|
if (showCondition && !showedPrivateModeContextualFeatureRecommender) {
|
||||||
|
showedPrivateModeContextualFeatureRecommender = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import androidx.annotation.Dimension.DP
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.IntentReceiverActivity
|
import org.mozilla.fenix.IntentReceiverActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.appcompat.widget.AppCompatDrawableManager
|
import androidx.appcompat.widget.AppCompatDrawableManager
|
||||||
|
@ -101,7 +102,7 @@ class SearchWidgetProvider : AppWidgetProvider() {
|
||||||
return Intent(context, HomeActivity::class.java)
|
return Intent(context, HomeActivity::class.java)
|
||||||
.let { intent ->
|
.let { intent ->
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
intent.putExtra(HomeActivity.OPEN_TO_SEARCH, true)
|
intent.putExtra(HomeActivity.OPEN_TO_SEARCH, StartSearchIntentProcessor.SEARCH_WIDGET)
|
||||||
PendingIntent.getActivity(context,
|
PendingIntent.getActivity(context,
|
||||||
REQUEST_CODE_NEW_TAB, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
REQUEST_CODE_NEW_TAB, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M 0 0 H 108 V 108 H 0 L 0 0">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:startY="48"
|
||||||
|
android:startX="0.51729584"
|
||||||
|
android:endY="-0.46862793"
|
||||||
|
android:endX="48.54931"
|
||||||
|
android:type="linear">
|
||||||
|
<item android:offset="0" android:color="#7529A7"/>
|
||||||
|
<item android:offset="0.5" android:color="#492E85"/>
|
||||||
|
<item android:offset="1" android:color="#383372"/>
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/static_shortcut_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_static_shortcut_private_tab_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/static_shortcut_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_static_shortcut_tab_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -10,4 +10,3 @@
|
||||||
<path android:fillColor="@android:color/white"
|
<path android:fillColor="@android:color/white"
|
||||||
android:pathData="M12 23a11 11 0 1 0 0-22 11 11 0 0 0 0 22zm3.3-7.94c-1.25 0-2.1-1.53-3.3-1.53-1.2 0-2.13 1.53-3.3 1.53-1.53 0-2.67-1.5-2.69-4 0-1.58 0.45-2.1 2.45-2.08 2 0 2.57 0.83 3.54 0.83 1 0 1.55-0.83 3.54-0.83 2 0 2.46 0.5 2.45 2.08-0 2.54-1.16 4.03-2.7 4zm-5.87-4.17c0.74-0.1 1.43 0.37 1.6 1.11 0 0.26-1 0.56-1.72 0.56-0.78 0-1.6-0.52-1.6-0.7 0-0.18 0.5-1 1.71-1zm5.13 0c-0.73-0.1-1.42 0.38-1.6 1.11 0 0.26 1 0.56 1.72 0.56 0.78 0 1.58-0.52 1.58-0.7 0-0.18-0.5-0.9-1.7-1z"/>
|
android:pathData="M12 23a11 11 0 1 0 0-22 11 11 0 0 0 0 22zm3.3-7.94c-1.25 0-2.1-1.53-3.3-1.53-1.2 0-2.13 1.53-3.3 1.53-1.53 0-2.67-1.5-2.69-4 0-1.58 0.45-2.1 2.45-2.08 2 0 2.57 0.83 3.54 0.83 1 0 1.55-0.83 3.54-0.83 2 0 2.46 0.5 2.45 2.08-0 2.54-1.16 4.03-2.7 4zm-5.87-4.17c0.74-0.1 1.43 0.37 1.6 1.11 0 0.26-1 0.56-1.72 0.56-0.78 0-1.6-0.52-1.6-0.7 0-0.18 0.5-1 1.71-1zm5.13 0c-0.73-0.1-1.42 0.38-1.6 1.11 0 0.26 1 0.56 1.72 0.56 0.78 0 1.58-0.52 1.58-0.7 0-0.18-0.5-0.9-1.7-1z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<rotate
|
||||||
|
android:fromDegrees="45"
|
||||||
|
android:pivotX="-40%"
|
||||||
|
android:pivotY="87%"
|
||||||
|
android:toDegrees="45">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<stroke
|
||||||
|
android:width="10dp"
|
||||||
|
android:color="#7542E5" />
|
||||||
|
<solid android:color="#7542E5" />
|
||||||
|
</shape>
|
||||||
|
</rotate>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="@color/static_shortcut_background" />
|
||||||
|
<size android:width="108dp" android:height="108dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/ic_static_shortcut_background" />
|
||||||
|
<item android:drawable="@drawable/ic_static_shortcut_private_tab_foreground" />
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/ic_static_shortcut_background" />
|
||||||
|
<item android:drawable="@drawable/ic_static_shortcut_tab_foreground" />
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!-- 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/. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="234.78261"
|
||||||
|
android:viewportHeight="234.78261">
|
||||||
|
<group android:translateX="63.391304"
|
||||||
|
android:translateY="63.391304">
|
||||||
|
<path
|
||||||
|
android:pathData="M81,49.5L58.5,49.5L58.5,27C58.5,24.515 56.485,22.5 54,22.5C51.515,22.5 49.5,24.515 49.5,27L49.5,49.5L27,49.5C24.515,49.5 22.5,51.515 22.5,54C22.5,56.485 24.515,58.5 27,58.5L49.5,58.5L49.5,81C49.5,83.485 51.515,85.5 54,85.5C56.485,85.5 58.5,83.485 58.5,81L58.5,58.5L81,58.5C83.485,58.5 85.5,56.485 85.5,54C85.5,51.515 83.485,49.5 81,49.5Z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:fillColor="#312A65"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#00000000"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:angle="225"
|
||||||
|
android:endColor="#B833E1"
|
||||||
|
android:startColor="#7542E5"
|
||||||
|
android:type="linear" />
|
||||||
|
<size
|
||||||
|
android:width="256dp"
|
||||||
|
android:height="152dp" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="8dp"
|
||||||
|
android:bottomRightRadius="8dp"
|
||||||
|
android:topLeftRadius="8dp"
|
||||||
|
android:topRightRadius="8dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/grey_button_color" />
|
||||||
|
<corners android:radius="@dimen/tab_corner_radius"/>
|
||||||
|
</shape>
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_pbm_triangle" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/pbm_shortcut_popup_background">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cfr_message"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:lineSpacingExtra="2dp"
|
||||||
|
android:text="@string/cfr_message"
|
||||||
|
android:textColor="@color/primary_text_dark_theme"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/cfr_pos_button"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="@drawable/rounded_gray_corners"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:text="@string/cfr_pos_button_text"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/above_dark_theme"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cfr_message" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/cfr_neg_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:text="@string/cfr_neg_button_text"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/white_color"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cfr_pos_button" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_private_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_private_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_private_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_private_foreground"/>
|
||||||
|
</adaptive-icon>
|
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -220,4 +220,7 @@
|
||||||
|
|
||||||
<!-- Notification Color -->
|
<!-- Notification Color -->
|
||||||
<color name="whats_new_notification_color">#00B3F4</color>
|
<color name="whats_new_notification_color">#00B3F4</color>
|
||||||
|
|
||||||
|
<!-- Static Shortcut Background Color -->
|
||||||
|
<color name="static_shortcut_background">#F5F5F5</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<string name="pref_key_passwords" translatable="false">pref_key_passwords</string>
|
<string name="pref_key_passwords" translatable="false">pref_key_passwords</string>
|
||||||
<string name="pref_key_credit_cards_addresses" translatable="false">pref_key_credit_cards_addresses</string>
|
<string name="pref_key_credit_cards_addresses" translatable="false">pref_key_credit_cards_addresses</string>
|
||||||
<string name="pref_key_site_permissions" translatable="false">pref_key_site_permissions</string>
|
<string name="pref_key_site_permissions" translatable="false">pref_key_site_permissions</string>
|
||||||
|
<string name="pref_key_add_private_browsing_shortcut" translatable="false">pref_key_add_private_browsing_shortcut</string>
|
||||||
<string name="pref_key_accessibility" translatable="false">pref_key_accessibility</string>
|
<string name="pref_key_accessibility" translatable="false">pref_key_accessibility</string>
|
||||||
<string name="pref_key_accessibility_auto_size" translatable="false">pref_key_accessibility_auto_size</string>
|
<string name="pref_key_accessibility_auto_size" translatable="false">pref_key_accessibility_auto_size</string>
|
||||||
<string name="pref_key_accessibility_font_scale" translatable="false">pref_key_accessibility_font_scale</string>
|
<string name="pref_key_accessibility_font_scale" translatable="false">pref_key_accessibility_font_scale</string>
|
||||||
|
@ -28,6 +29,8 @@
|
||||||
<string name="pref_key_leakcanary" translatable="false">pref_key_leakcanary</string>
|
<string name="pref_key_leakcanary" translatable="false">pref_key_leakcanary</string>
|
||||||
<string name="pref_key_remote_debugging" translatable="false">pref_key_remote_debugging</string>
|
<string name="pref_key_remote_debugging" translatable="false">pref_key_remote_debugging</string>
|
||||||
<string name="pref_key_experimentation" translatable="false">pref_key_experimentation</string>
|
<string name="pref_key_experimentation" translatable="false">pref_key_experimentation</string>
|
||||||
|
<string name="pref_key_showed_private_mode_cfr" translatable="false">pref_key_showed_private_mode_cfr</string>
|
||||||
|
<string name="pref_key_private_mode_opened" translatable="false">pref_key_private_mode_opened</string>
|
||||||
|
|
||||||
<!-- Data Choices -->
|
<!-- Data Choices -->
|
||||||
<string name="pref_key_telemetry" translatable="false">pref_key_telemetry</string>
|
<string name="pref_key_telemetry" translatable="false">pref_key_telemetry</string>
|
||||||
|
|
|
@ -58,6 +58,10 @@
|
||||||
android:icon="@drawable/ic_tracking_protection_enabled"
|
android:icon="@drawable/ic_tracking_protection_enabled"
|
||||||
android:key="@string/pref_key_tracking_protection_settings"
|
android:key="@string/pref_key_tracking_protection_settings"
|
||||||
android:title="@string/preference_enhanced_tracking_protection" />
|
android:title="@string/preference_enhanced_tracking_protection" />
|
||||||
|
<androidx.preference.Preference
|
||||||
|
android:icon="@drawable/ic_private_browsing"
|
||||||
|
android:key="@string/pref_key_add_private_browsing_shortcut"
|
||||||
|
android:title="@string/preferences_add_private_browsing_shortcut"/>
|
||||||
<androidx.preference.Preference
|
<androidx.preference.Preference
|
||||||
android:icon="@drawable/ic_permission"
|
android:icon="@drawable/ic_permission"
|
||||||
android:key="@string/pref_key_site_permissions"
|
android:key="@string/pref_key_site_permissions"
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="open_new_tab"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_static_shortcut_tab"
|
||||||
|
android:shortcutShortLabel="@string/home_screen_shortcut_open_new_tab"
|
||||||
|
android:shortcutLongLabel="@string/home_screen_shortcut_open_new_tab">
|
||||||
|
<intent
|
||||||
|
android:action="org.mozilla.fenix.OPEN_TAB"
|
||||||
|
android:targetPackage="org.mozilla"
|
||||||
|
android:targetClass="org.mozilla.fenix.IntentReceiverActivity" />
|
||||||
|
</shortcut>
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="open_new_private_tab"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_static_shortcut_private_tab"
|
||||||
|
android:shortcutShortLabel="@string/home_screen_shortcut_open_new_private_tab"
|
||||||
|
android:shortcutLongLabel="@string/home_screen_shortcut_open_new_private_tab">
|
||||||
|
<intent
|
||||||
|
android:action="org.mozilla.fenix.OPEN_PRIVATE_TAB"
|
||||||
|
android:targetPackage="org.mozilla"
|
||||||
|
android:targetClass="org.mozilla.fenix.IntentReceiverActivity" />
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|
|
@ -43,7 +43,7 @@ class StartSearchIntentProcessorTest {
|
||||||
val navController: NavController = mockk()
|
val navController: NavController = mockk()
|
||||||
val out: Intent = mockk()
|
val out: Intent = mockk()
|
||||||
val intent = Intent().apply {
|
val intent = Intent().apply {
|
||||||
putExtra(HomeActivity.OPEN_TO_SEARCH, false)
|
removeExtra(HomeActivity.OPEN_TO_SEARCH)
|
||||||
}
|
}
|
||||||
StartSearchIntentProcessor(metrics).process(intent, navController, out)
|
StartSearchIntentProcessor(metrics).process(intent, navController, out)
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class StartSearchIntentProcessorTest {
|
||||||
val navController: NavController = mockk(relaxed = true)
|
val navController: NavController = mockk(relaxed = true)
|
||||||
val out: Intent = mockk(relaxed = true)
|
val out: Intent = mockk(relaxed = true)
|
||||||
val intent = Intent().apply {
|
val intent = Intent().apply {
|
||||||
putExtra(HomeActivity.OPEN_TO_SEARCH, true)
|
putExtra(HomeActivity.OPEN_TO_SEARCH, StartSearchIntentProcessor.SEARCH_WIDGET)
|
||||||
}
|
}
|
||||||
StartSearchIntentProcessor(metrics).process(intent, navController, out)
|
StartSearchIntentProcessor(metrics).process(intent, navController, out)
|
||||||
|
|
||||||
|
@ -71,6 +71,6 @@ class StartSearchIntentProcessorTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
verify { out.putExtra(HomeActivity.OPEN_TO_SEARCH, false) }
|
verify { out.removeExtra(HomeActivity.OPEN_TO_SEARCH) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|