1
0
Fork 0

For #419: Create launch icon for private browsing (#4948)

master
Yeon Taek Jeong 2019-09-11 10:52:33 -07:00 committed by GitHub
parent 9033b8d676
commit 2e2bac4ccd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 595 additions and 12 deletions

View File

@ -22,6 +22,15 @@
<activity android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
android:exported="true"/>
<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>
</manifest>

View File

@ -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>

View File

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<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 -->
<uses-permission-sdk-23 android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
@ -58,6 +59,10 @@
<data android:scheme="fenix"
android:host="make_default_browser"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
@ -118,6 +123,54 @@
android:resource="@mipmap/ic_launcher" />
</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
android:name=".browser.BrowserPerformanceTestActivity"
android:enabled="${isRaptorEnabled}"

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -86,6 +86,8 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
final override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setPrivateModeIfNecessary()
components.publicSuffixList.prefetch()
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() {
browsingModeManager = createBrowsingModeManager()
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_AND_LOAD = "open_to_browser_and_load"
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_OPENED_FROM_NOTIFICATION = "notification_open"
}

View File

@ -6,6 +6,7 @@ package org.mozilla.fenix
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.speech.RecognizerIntent
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.metrics
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
class IntentReceiverActivity : Activity() {
@ -33,7 +35,10 @@ class IntentReceiverActivity : Activity() {
return
}
val isPrivate = this.settings.usePrivateMode
val isPrivate = packageManager
?.getActivityInfo(componentName, PackageManager.GET_META_DATA)
?.metaData
?.getBoolean(PRIVATE_MODE) ?: this.settings.usePrivateMode
MainScope().launch {
// 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".
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 -> {
intent.setClassName(applicationContext, HomeActivity::class.java.name)
false
@ -124,5 +147,8 @@ class IntentReceiverActivity : Activity() {
private const val SPEECH_REQUEST_CODE = 0
const val SPEECH_PROCESSING = "speech_processing"
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"
}
}

View File

@ -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)
}
}

View File

@ -9,9 +9,13 @@ import android.content.Context
import android.content.DialogInterface
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.LinearLayout
import android.widget.PopupWindow
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
@ -54,15 +58,18 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.FenixViewModelProvider
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.collections.CreateCollectionViewModel
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.PrivateShortcutCreateManager
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.sessionsOfType
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.toTab
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
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.share.ShareTab
import org.mozilla.fenix.utils.FragmentPreDrawManager
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.allowUndo
import org.mozilla.fenix.whatsnew.WhatsNew
@ -212,7 +218,7 @@ class HomeFragment : Fragment(), AccountObserver {
val searchEngine = requireComponents.search.searchEngineManager.getDefaultSearchEngineAsync(
requireContext(),
Settings.getInstance(requireContext()).defaultSearchEngineName
requireContext().settings.defaultSearchEngineName
)
val searchIcon = BitmapDrawable(resources, searchEngine.icon)
searchIcon.setBounds(0, 0, iconSize, iconSize)
@ -251,6 +257,10 @@ class HomeFragment : Fragment(), AccountObserver {
) { newMode ->
invokePendingDeleteJobs()
if (newMode == BrowsingMode.Private) {
requireContext().settings.incrementNumTimesPrivateModeOpened()
}
if (onboarding.userHasBeenOnboarded()) {
getManagedEmitter<SessionControlChange>().onNext(
SessionControlChange.ModeChange(Mode.fromBrowsingMode(newMode))
@ -290,6 +300,11 @@ class HomeFragment : Fragment(), AccountObserver {
(activity as AppCompatActivity).supportActionBar?.hide()
requireComponents.backgroundServices.accountManager.register(this, owner = this)
if (requireContext().settings.showPrivateModeContextualFeatureRecommender &&
browsingModeManager.mode.isPrivate) {
recommendPrivateBrowsingShortcut()
}
}
override fun onStart() {
@ -543,6 +558,34 @@ class HomeFragment : Fragment(), AccountObserver {
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() {
if (!onboarding.userHasBeenOnboarded()) {
onboarding.finish()
@ -896,6 +939,8 @@ class HomeFragment : Fragment(), AccountObserver {
private const val TELEMETRY_HOME_IDENITIFIER = "home"
private const val SHARED_TRANSITION_MS = 200L
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
private const val CFR_WIDTH_DIVIDER = 1.7
private const val CFR_Y_OFFSET = -20
}
}

View File

@ -14,15 +14,20 @@ import org.mozilla.fenix.ext.nav
/**
* 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(
private val metrics: MetricController
) : HomeIntentProcessor {
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
return if (intent.extras?.getBoolean(HomeActivity.OPEN_TO_SEARCH) == true) {
out.putExtra(HomeActivity.OPEN_TO_SEARCH, false)
metrics.track(Event.SearchWidgetNewTabPressed)
val event = intent.extras?.getString(HomeActivity.OPEN_TO_SEARCH)
return if (event != null) {
when (event) {
SEARCH_WIDGET -> metrics.track(Event.SearchWidgetNewTabPressed)
}
out.removeExtra(HomeActivity.OPEN_TO_SEARCH)
val directions = NavGraphDirections.actionGlobalSearch(
sessionId = null,
@ -34,4 +39,11 @@ class StartSearchIntentProcessor(
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"
}
}

View File

@ -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_auth_error
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_delete_browsing_data
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_tracking_protection_settings
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.ext.components
import org.mozilla.fenix.ext.getPreferenceKey
@ -142,7 +144,7 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
updateAccountUIState(context!!, requireComponents.backgroundServices.accountManager.accountProfile())
}
@Suppress("ComplexMethod")
@Suppress("ComplexMethod", "LongMethod")
override fun onPreferenceTreeClick(preference: Preference): Boolean {
when (preference.key) {
resources.getString(pref_key_search_engine_settings) -> {
@ -154,6 +156,9 @@ class SettingsFragment : PreferenceFragmentCompat(), AccountObserver {
resources.getString(pref_key_site_permissions) -> {
navigateToSitePermissions()
}
resources.getString(pref_key_add_private_browsing_shortcut) -> {
PrivateShortcutCreateManager.createPrivateShortcut(requireContext())
}
resources.getString(pref_key_accessibility) -> {
navigateToAccessibility()
}

View File

@ -4,6 +4,7 @@
package org.mozilla.fenix.utils
import android.app.Application
import android.content.Context
import android.content.Context.MODE_PRIVATE
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.Config
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.MozillaProductDetector
import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.settings.PhoneFeature
import java.security.InvalidParameterException
@ -35,6 +37,8 @@ class Settings private constructor(
const val FENIX_PREFERENCES = "fenix_preferences"
private const val BLOCKED_INT = 0
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) {
SitePermissionsRules.Action.BLOCKED -> BLOCKED_INT
@ -247,4 +251,37 @@ class Settings private constructor(
appContext.getPreferenceKey(R.string.pref_key_search_widget_installed),
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
}
}

View File

@ -19,6 +19,7 @@ import androidx.annotation.Dimension.DP
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
import org.mozilla.fenix.ext.settings
import android.os.Build
import androidx.appcompat.widget.AppCompatDrawableManager
@ -101,7 +102,7 @@ class SearchWidgetProvider : AppWidgetProvider() {
return Intent(context, HomeActivity::class.java)
.let { intent ->
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,
REQUEST_CODE_NEW_TAB, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}

View File

@ -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>

File diff suppressed because one or more lines are too long

View File

@ -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>

View File

@ -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>

View File

@ -10,4 +10,3 @@
<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"/>
</vector>

View File

@ -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>

View File

@ -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>

View File

@ -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>

File diff suppressed because one or more lines are too long

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -220,4 +220,7 @@
<!-- Notification Color -->
<color name="whats_new_notification_color">#00B3F4</color>
<!-- Static Shortcut Background Color -->
<color name="static_shortcut_background">#F5F5F5</color>
</resources>

View File

@ -8,6 +8,7 @@
<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_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_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>
@ -28,6 +29,8 @@
<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_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 -->
<string name="pref_key_telemetry" translatable="false">pref_key_telemetry</string>

View File

@ -58,6 +58,10 @@
android:icon="@drawable/ic_tracking_protection_enabled"
android:key="@string/pref_key_tracking_protection_settings"
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
android:icon="@drawable/ic_permission"
android:key="@string/pref_key_site_permissions"

View File

@ -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>

View File

@ -43,7 +43,7 @@ class StartSearchIntentProcessorTest {
val navController: NavController = mockk()
val out: Intent = mockk()
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_SEARCH, false)
removeExtra(HomeActivity.OPEN_TO_SEARCH)
}
StartSearchIntentProcessor(metrics).process(intent, navController, out)
@ -58,7 +58,7 @@ class StartSearchIntentProcessorTest {
val navController: NavController = mockk(relaxed = true)
val out: Intent = mockk(relaxed = true)
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_SEARCH, true)
putExtra(HomeActivity.OPEN_TO_SEARCH, StartSearchIntentProcessor.SEARCH_WIDGET)
}
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) }
}
}