2
0
mirror of https://github.com/fork-maintainers/iceraven-browser synced 2024-11-11 13:11:01 +00:00

[fenix] Issue https://github.com/mozilla-mobile/fenix/issues/22489: Remove "Fennec to Fenix" migration code

This commit is contained in:
Sebastian Kaspari 2021-11-19 12:42:23 +01:00 committed by mergify[bot]
parent a38538a52b
commit 51f88636e9
31 changed files with 31 additions and 877 deletions

View File

@ -177,14 +177,6 @@ android {
androidTest { androidTest {
resources.srcDirs += ['src/androidTest/resources'] resources.srcDirs += ['src/androidTest/resources']
} }
beta {
java.srcDirs = ['src/migration/java']
manifest.srcFile "src/migration/AndroidManifest.xml"
}
release {
java.srcDirs = ['src/migration/java']
manifest.srcFile "src/migration/AndroidManifest.xml"
}
} }
splits { splits {
@ -530,7 +522,6 @@ dependencies {
implementation Deps.mozilla_support_rustlog implementation Deps.mozilla_support_rustlog
implementation Deps.mozilla_support_utils implementation Deps.mozilla_support_utils
implementation Deps.mozilla_support_locale implementation Deps.mozilla_support_locale
implementation Deps.mozilla_support_migration
implementation Deps.mozilla_ui_colors implementation Deps.mozilla_ui_colors
implementation Deps.mozilla_ui_icons implementation Deps.mozilla_ui_icons

View File

@ -1493,17 +1493,6 @@
column="1"/> column="1"/>
</issue> </issue>
<issue
id="UnusedResources"
message="The resource `R.anim.placeholder_animation` appears to be unused"
errorLine1="&lt;translate"
errorLine2="^">
<location
file="src/main/res/anim/placeholder_animation.xml"
line="5"
column="1"/>
</issue>
<issue <issue
id="IconXmlAndPng" id="IconXmlAndPng"
message="The following images appear both as density independent `.xml` files and as bitmap files: /Users/oracle/Projects/fenix/app/src/main/res/drawable-hdpi/ic_logo_wordmark_normal.png, /Users/rotbolt/AndroidStudioProjects/fenix/app/src/main/res/drawable-night/ic_logo_wordmark_normal.xml"> message="The following images appear both as density independent `.xml` files and as bitmap files: /Users/oracle/Projects/fenix/app/src/main/res/drawable-hdpi/ic_logo_wordmark_normal.png, /Users/rotbolt/AndroidStudioProjects/fenix/app/src/main/res/drawable-night/ic_logo_wordmark_normal.xml">

View File

@ -1,5 +0,0 @@
History
Bookmarks
Logins
Open Tabs
Settings

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
sharedUserId: This release type is meant to replace Firefox (Beta channel) and therefore needs to inherit
its sharedUserId for all eternity. Shipping an app update without sharedUserId can have
fatal consequences. For example see:
- https://issuetracker.google.com/issues/36924841
- https://issuetracker.google.com/issues/36905922
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:sharedUserId="${sharedUserId}">
</manifest>

View File

@ -233,13 +233,6 @@
</activity> </activity>
<activity
android:name=".migration.MigrationProgressActivity"
android:noHistory="true"
android:launchMode="singleInstance"
android:exported="false">
</activity>
<activity <activity
android:name=".crashes.CrashListActivity" android:name=".crashes.CrashListActivity"
android:exported="false" /> android:exported="false" />

View File

@ -100,8 +100,7 @@ class IntentReceiverActivity : Activity() {
) )
} }
return listOf(components.intentProcessors.migrationIntentProcessor) + return components.intentProcessors.externalAppIntentProcessors +
components.intentProcessors.externalAppIntentProcessors +
components.intentProcessors.fennecPageShortcutIntentProcessor + components.intentProcessors.fennecPageShortcutIntentProcessor +
components.intentProcessors.externalDeepLinkIntentProcessor + components.intentProcessors.externalDeepLinkIntentProcessor +
modeDependentProcessors + modeDependentProcessors +

View File

@ -19,7 +19,6 @@ import mozilla.components.feature.addons.update.DefaultAddonUpdater
import mozilla.components.feature.autofill.AutofillConfiguration import mozilla.components.feature.autofill.AutofillConfiguration
import mozilla.components.lib.publicsuffixlist.PublicSuffixList import mozilla.components.lib.publicsuffixlist.PublicSuffixList
import mozilla.components.support.base.worker.Frequency import mozilla.components.support.base.worker.Frequency
import mozilla.components.support.migration.state.MigrationStore
import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config import org.mozilla.fenix.Config
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
@ -99,7 +98,6 @@ class Components(private val context: Context) {
useCases.searchUseCases, useCases.searchUseCases,
core.relationChecker, core.relationChecker,
core.customTabsStore, core.customTabsStore,
migrationStore,
core.webAppManifestStorage core.webAppManifestStorage
) )
} }
@ -157,7 +155,6 @@ class Components(private val context: Context) {
val analytics by lazyMonitored { Analytics(context) } val analytics by lazyMonitored { Analytics(context) }
val publicSuffixList by lazyMonitored { PublicSuffixList(context) } val publicSuffixList by lazyMonitored { PublicSuffixList(context) }
val clipboardHandler by lazyMonitored { ClipboardHandler(context) } val clipboardHandler by lazyMonitored { ClipboardHandler(context) }
val migrationStore by lazyMonitored { MigrationStore() }
val performance by lazyMonitored { PerformanceComponent() } val performance by lazyMonitored { PerformanceComponent() }
val push by lazyMonitored { Push(context, analytics.crashReporter) } val push by lazyMonitored { Push(context, analytics.crashReporter) }
val wifiConnectionMonitor by lazyMonitored { WifiConnectionMonitor(context as Application) } val wifiConnectionMonitor by lazyMonitored { WifiConnectionMonitor(context as Application) }

View File

@ -8,10 +8,9 @@ import android.content.Intent
import mozilla.components.feature.intent.processing.IntentProcessor import mozilla.components.feature.intent.processing.IntentProcessor
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity
import org.mozilla.fenix.migration.MigrationProgressActivity
enum class IntentProcessorType { enum class IntentProcessorType {
EXTERNAL_APP, NEW_TAB, MIGRATION, EXTERNAL_DEEPLINK, OTHER; EXTERNAL_APP, NEW_TAB, EXTERNAL_DEEPLINK, OTHER;
/** /**
* The destination activity based on this intent * The destination activity based on this intent
@ -20,7 +19,6 @@ enum class IntentProcessorType {
get() = when (this) { get() = when (this) {
EXTERNAL_APP -> ExternalAppBrowserActivity::class.java.name EXTERNAL_APP -> ExternalAppBrowserActivity::class.java.name
NEW_TAB, EXTERNAL_DEEPLINK, OTHER -> HomeActivity::class.java.name NEW_TAB, EXTERNAL_DEEPLINK, OTHER -> HomeActivity::class.java.name
MIGRATION -> MigrationProgressActivity::class.java.name
} }
/** /**
@ -29,7 +27,7 @@ enum class IntentProcessorType {
fun shouldOpenToBrowser(intent: Intent): Boolean = when (this) { fun shouldOpenToBrowser(intent: Intent): Boolean = when (this) {
EXTERNAL_APP -> true EXTERNAL_APP -> true
NEW_TAB -> intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == 0 NEW_TAB -> intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == 0
MIGRATION, EXTERNAL_DEEPLINK, OTHER -> false EXTERNAL_DEEPLINK, OTHER -> false
} }
} }
@ -37,7 +35,6 @@ enum class IntentProcessorType {
* Classifies the [IntentProcessorType] based on the [IntentProcessor] that handled the [Intent]. * Classifies the [IntentProcessorType] based on the [IntentProcessor] that handled the [Intent].
*/ */
fun IntentProcessors.getType(processor: IntentProcessor?) = when { fun IntentProcessors.getType(processor: IntentProcessor?) = when {
migrationIntentProcessor == processor -> IntentProcessorType.MIGRATION
externalAppIntentProcessors.contains(processor) || externalAppIntentProcessors.contains(processor) ||
customTabIntentProcessor == processor || customTabIntentProcessor == processor ||
privateCustomTabIntentProcessor == processor -> IntentProcessorType.EXTERNAL_APP privateCustomTabIntentProcessor == processor -> IntentProcessorType.EXTERNAL_APP

View File

@ -17,8 +17,6 @@ import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.tabs.CustomTabsUseCases import mozilla.components.feature.tabs.CustomTabsUseCases
import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.feature.tabs.TabsUseCases
import mozilla.components.service.digitalassetlinks.RelationChecker import mozilla.components.service.digitalassetlinks.RelationChecker
import mozilla.components.support.migration.MigrationIntentProcessor
import mozilla.components.support.migration.state.MigrationStore
import org.mozilla.fenix.customtabs.FennecWebAppIntentProcessor import org.mozilla.fenix.customtabs.FennecWebAppIntentProcessor
import org.mozilla.fenix.home.intent.FennecBookmarkShortcutsIntentProcessor import org.mozilla.fenix.home.intent.FennecBookmarkShortcutsIntentProcessor
import org.mozilla.fenix.intent.ExternalDeepLinkIntentProcessor import org.mozilla.fenix.intent.ExternalDeepLinkIntentProcessor
@ -37,7 +35,6 @@ class IntentProcessors(
private val searchUseCases: SearchUseCases, private val searchUseCases: SearchUseCases,
private val relationChecker: RelationChecker, private val relationChecker: RelationChecker,
private val customTabsStore: CustomTabsServiceStore, private val customTabsStore: CustomTabsServiceStore,
private val migrationStore: MigrationStore,
private val manifestStorage: ManifestStorage private val manifestStorage: ManifestStorage
) { ) {
/** /**
@ -82,8 +79,4 @@ class IntentProcessors(
val fennecPageShortcutIntentProcessor by lazyMonitored { val fennecPageShortcutIntentProcessor by lazyMonitored {
FennecBookmarkShortcutsIntentProcessor(tabsUseCases.addTab) FennecBookmarkShortcutsIntentProcessor(tabsUseCases.addTab)
} }
val migrationIntentProcessor by lazyMonitored {
MigrationIntentProcessor(migrationStore)
}
} }

View File

@ -186,7 +186,6 @@ sealed class Event {
} }
) )
} }
object FennecToFenixMigrated : Event()
object AddonsOpenInSettings : Event() object AddonsOpenInSettings : Event()
object StudiesSettings : Event() object StudiesSettings : Event()
object VoiceSearchTapped : Event() object VoiceSearchTapped : Event()

View File

@ -981,7 +981,6 @@ private val Event.wrapper: EventWrapper<*>?
is Event.InteractWithSearchURLArea -> null is Event.InteractWithSearchURLArea -> null
is Event.ClearedPrivateData -> null is Event.ClearedPrivateData -> null
is Event.DismissedOnboarding -> null is Event.DismissedOnboarding -> null
is Event.FennecToFenixMigrated -> null
is Event.AddonInstalled -> null is Event.AddonInstalled -> null
is Event.SearchWidgetInstalled -> null is Event.SearchWidgetInstalled -> null
is Event.SyncAuthFromSharedReuse, Event.SyncAuthFromSharedCopy -> null is Event.SyncAuthFromSharedReuse, Event.SyncAuthFromSharedCopy -> null

View File

@ -1,105 +0,0 @@
/* 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.migration
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.migration.AbstractMigrationProgressActivity
import mozilla.components.support.migration.AbstractMigrationService
import mozilla.components.support.migration.MigrationResults
import mozilla.components.support.migration.state.MigrationAction
import mozilla.components.support.migration.state.MigrationProgress
import mozilla.components.support.migration.state.MigrationStore
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.ActivityMigrationBinding
import org.mozilla.fenix.ext.components
class MigrationProgressActivity : AbstractMigrationProgressActivity() {
private val logger = Logger("MigrationProgressActivity")
private val statusAdapter = MigrationStatusAdapter()
override val store: MigrationStore by lazy { components.migrationStore }
private lateinit var binding: ActivityMigrationBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMigrationBinding.inflate(layoutInflater)
setContentView(binding.root)
init()
}
fun init() {
window.navigationBarColor = getColorFromAttr(R.attr.layer1)
val appName = binding.migrationDescription.context.getString(R.string.app_name)
binding.migrationDescription.apply {
text = context.getString(R.string.migration_description, appName)
}
binding.migrationStatusList.apply {
val margin = resources.getDimensionPixelSize(R.dimen.migration_margin)
addItemDecoration(MigrationStatusItemDecoration(margin))
layoutManager = LinearLayoutManager(this@MigrationProgressActivity)
adapter = statusAdapter
}
binding.migrationWelcomeTitle.apply {
text = context.getString(R.string.migration_title, appName)
}
binding.migrationButtonTextView.text = getString(R.string.migration_updating_app_button_text, appName)
}
override fun onMigrationCompleted(results: MigrationResults) {
// Enable clicking the finish button
binding.migrationButton.apply {
setOnClickListener {
AbstractMigrationService.dismissNotification(context)
finish()
overridePendingTransition(0, 0)
store.dispatch(MigrationAction.Clear)
// If we received a user-initiated intent, throw this back to the intent receiver.
if (intent.hasExtra(HomeActivity.OPEN_TO_BROWSER)) {
intent.setClassName(applicationContext, IntentReceiverActivity::class.java.name)
startActivity(intent)
} else {
// Fallback: Just launch the browser
logger.warn("Intent does not contain OPEN_TO_BROWSER extra, launching HomeActivity")
startActivity(Intent(this@MigrationProgressActivity, HomeActivity::class.java))
}
}
}
binding.migrationButtonTextView.apply {
text = getString(R.string.migration_update_app_button, getString(R.string.app_name))
setTextColor(
ContextCompat.getColor(
context,
R.color.fx_mobile_text_color_oncolor_primary
)
)
}
binding.migrationButton.setBackgroundResource(R.drawable.migration_button_background)
binding.migrationButtonProgressBar.visibility = View.INVISIBLE
// Keep the results list up-to-date.
statusAdapter.updateData(results)
}
override fun onMigrationStateChanged(progress: MigrationProgress, results: MigrationResults) {
statusAdapter.updateData(results)
}
}

View File

@ -1,109 +0,0 @@
/* 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.migration
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.Px
import androidx.core.view.isInvisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.support.migration.Migration
import mozilla.components.support.migration.MigrationResults
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.MigrationListItemBinding
internal data class MigrationItem(
val migration: Migration,
val status: Boolean = false
)
// These are the only items we want to show migrating in the UI.
internal val whiteList = linkedMapOf(
Migration.Settings to R.string.settings_title,
Migration.History to R.string.preferences_sync_history,
Migration.Bookmarks to R.string.preferences_sync_bookmarks,
Migration.Logins to R.string.migration_text_passwords
)
internal class MigrationStatusAdapter :
ListAdapter<MigrationItem, MigrationStatusAdapter.ViewHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.migration_list_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
/**
* Filter the [results] to only include items in [whiteList] and update the adapter.
*/
fun updateData(results: MigrationResults) {
val itemList = whiteList.keys.map {
if (results.containsKey(it)) {
MigrationItem(it, results.getValue(it).success)
} else {
MigrationItem(it)
}
}
submitList(itemList)
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val context = view.context
private val binding = MigrationListItemBinding.bind(view)
private val title = binding.migrationItemName
private val status = binding.migrationStatusImage
fun bind(item: MigrationItem) {
// Get the resource ID for the item.
val migrationText = whiteList[item.migration]?.let {
context.getString(it)
}.orEmpty()
title.text = migrationText
status.isInvisible = !item.status
status.contentDescription = context.getString(R.string.migration_icon_description)
}
}
private object DiffCallback : DiffUtil.ItemCallback<MigrationItem>() {
override fun areItemsTheSame(oldItem: MigrationItem, newItem: MigrationItem) =
oldItem.migration.javaClass.simpleName == newItem.migration.javaClass.simpleName
override fun areContentsTheSame(oldItem: MigrationItem, newItem: MigrationItem) =
oldItem.migration.javaClass.simpleName == newItem.migration.javaClass.simpleName &&
oldItem.status == newItem.status
}
}
internal class MigrationStatusItemDecoration(
@Px private val spacing: Int
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val position = parent.getChildViewHolder(view).bindingAdapterPosition
val itemCount = state.itemCount
outRect.left = spacing
outRect.right = spacing
outRect.top = spacing
outRect.bottom = if (position == itemCount - 1) spacing else 0
}
}

View File

@ -1,34 +0,0 @@
/* 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.migration
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.migration.state.MigrationProgress
import mozilla.components.support.migration.state.MigrationStore
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
class MigrationTelemetryListener(
private val metrics: MetricController,
private val store: MigrationStore,
private val logger: Logger = Logger("MigrationTelemetryListener")
) {
@OptIn(ExperimentalCoroutinesApi::class)
fun start() {
// Observe for migration completed.
store.flowScoped { flow ->
flow.collect { state ->
logger.debug("Migration state: ${state.progress}")
if (state.progress == MigrationProgress.COMPLETED) {
metrics.track(Event.FennecToFenixMigrated)
}
}
}
}
}

View File

@ -1,9 +0,0 @@
<?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/. -->
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="0"
android:duration="900" />

View File

@ -1,9 +0,0 @@
<?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">
<corners android:radius="4dp"/>
<solid android:color="@color/fx_mobile_action_color_secondary" />
</shape>

View File

@ -1,9 +0,0 @@
<?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">
<corners android:radius="4dp"/>
<solid android:color="#312A65" />
</shape>

View File

@ -1,132 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?><!-- 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/. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/photonLightGrey05">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="@dimen/migration_progress_margin"
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none"
app:layout_constraintBottom_toTopOf="@+id/migration_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- MozMultipleConstraintLayouts: we're not changing the migration code. -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MozMultipleConstraintLayouts">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/migration_firefox_logo"
android:layout_width="@dimen/migration_firefox_logo_size"
android:layout_height="@dimen/migration_firefox_logo_size"
android:layout_marginStart="@dimen/migration_margin_horizontal_large"
android:fontFamily="@font/metropolis_bold"
android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="@+id/migration_welcome_title"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/migration_welcome_title"
app:layout_constraintTop_toTopOf="@+id/migration_welcome_title"
app:srcCompat="@drawable/ic_firefox" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/migration_welcome_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/migration_margin"
android:layout_marginTop="@dimen/migration_margin"
android:layout_marginEnd="@dimen/migration_margin_horizontal_large"
android:fontFamily="@font/metropolis_bold"
android:maxLines="2"
android:lineHeight="24sp"
android:text="@string/migration_title"
android:textColor="@color/fx_mobile_text_color_action_secondary"
android:textSize="@dimen/migration_welcome_title_text_size"
android:textAppearance="@style/Header16TextStyle"
app:layout_constraintBottom_toTopOf="@+id/migration_description"
app:layout_constraintLeft_toRightOf="@id/migration_firefox_logo"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Welcome to the all-new Firefox Preview" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/migration_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/migration_margin_horizontal_large"
android:layout_marginTop="@dimen/migration_margin"
android:layout_marginRight="@dimen/migration_margin_horizontal_large"
android:lineHeight="24sp"
android:text="@string/migration_description"
android:textColor="@color/primary_text_light_theme"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintBottom_toTopOf="@+id/migration_status_list"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/migration_welcome_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/migration_status_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/migration_margin_horizontal_large"
android:layout_marginTop="@dimen/migration_margin"
android:layout_marginRight="@dimen/migration_margin_horizontal_large"
android:nestedScrollingEnabled="false"
android:overScrollMode="never"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.45"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/migration_description"
tools:itemCount="5"
tools:listitem="@layout/migration_list_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:id="@+id/migration_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/migration_margin"
android:background="@drawable/button_background_grey"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<ProgressBar
android:id="@+id/migration_button_progress_bar"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="@dimen/migration_progress_size"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/migration_margin"
android:layout_marginEnd="@dimen/migration_progress_margin_start" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/migration_button_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/migration_progress_margin_compound"
android:background="@android:color/transparent"
android:text="@string/migration_updating_app_button_text"
android:textSize="@dimen/migration_button_text_size"
android:textAppearance="@style/NeutralButton"
tools:text="Updating Firefox…" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?><!-- 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/. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/migration_status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/migration_icon_description"
app:tint="@color/photonViolet60"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/mozac_ic_check"
tools:tint="@color/photonDarkGrey50" />
<TextView
android:id="@+id/migration_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="32dp"
android:textColor="@color/primary_text_light_theme"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/migration_status_image"
app:layout_constraintTop_toTopOf="parent"
tools:text="@sample/migration_items" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -121,17 +121,6 @@
<dimen name="locale_item_subtitle_size">12sp</dimen> <dimen name="locale_item_subtitle_size">12sp</dimen>
<dimen name="locale_item_height">48dp</dimen> <dimen name="locale_item_height">48dp</dimen>
<!--Migration Activity-->
<dimen name="migration_margin_horizontal_large">20dp</dimen>
<dimen name="migration_margin">16dp</dimen>
<dimen name="migration_firefox_logo_size">48dp</dimen>
<dimen name="migration_welcome_title_text_size">20sp</dimen>
<dimen name="migration_button_text_size">14sp</dimen>
<dimen name="migration_progress_size">24dp</dimen>
<dimen name="migration_progress_margin">8dp</dimen>
<dimen name="migration_progress_margin_start">4dp</dimen>
<dimen name="migration_progress_margin_compound">44dp</dimen>
<!-- Share Fragment --> <!-- Share Fragment -->
<dimen name="share_recent_apps_background_radius">10dp</dimen> <dimen name="share_recent_apps_background_radius">10dp</dimen>
<dimen name="share_recent_apps_padding">8dp</dimen> <dimen name="share_recent_apps_padding">8dp</dimen>

View File

@ -1564,17 +1564,17 @@
<string name="search_delete_search_engine_success_message">Deleted %s</string> <string name="search_delete_search_engine_success_message">Deleted %s</string>
<!-- Title text shown for the migration screen to the new browser. Placeholder replaced with app name --> <!-- Title text shown for the migration screen to the new browser. Placeholder replaced with app name -->
<string name="migration_title">Welcome to an all-new %s</string> <string name="migration_title" moz:removedIn="100" tools:ignore="UnusedResources">Welcome to an all-new %s</string>
<!-- Description text followed by a list of things migrating (e.g. Bookmarks, History). Placeholder replaced with app name--> <!-- Description text followed by a list of things migrating (e.g. Bookmarks, History). Placeholder replaced with app name-->
<string name="migration_description">A completely redesigned browser awaits, with improved performance and features to help you do more online.\n\nPlease wait while we update %s with your</string> <string name="migration_description" moz:removedIn="100" tools:ignore="UnusedResources">A completely redesigned browser awaits, with improved performance and features to help you do more online.\n\nPlease wait while we update %s with your</string>
<!-- Text on the disabled button while in progress. Placeholder replaced with app name --> <!-- Text on the disabled button while in progress. Placeholder replaced with app name -->
<string name="migration_updating_app_button_text">Updating %s…</string> <string name="migration_updating_app_button_text" moz:removedIn="100" tools:ignore="UnusedResources">Updating %s…</string>
<!-- Text on the enabled button. Placeholder replaced with app name--> <!-- Text on the enabled button. Placeholder replaced with app name-->
<string name="migration_update_app_button">Start %s</string> <string name="migration_update_app_button" moz:removedIn="100" tools:ignore="UnusedResources">Start %s</string>
<!-- Accessibility description text for a completed migration item --> <!-- Accessibility description text for a completed migration item -->
<string name="migration_icon_description">Migration completed</string> <string name="migration_icon_description" moz:removedIn="100" tools:ignore="UnusedResources">Migration completed</string>
<!--Text on list of migrated items (e.g. Settings, History, etc.)--> <!--Text on list of migrated items (e.g. Settings, History, etc.)-->
<string name="migration_text_passwords">Passwords</string> <string name="migration_text_passwords" moz:removedIn="100" tools:ignore="UnusedResources">Passwords</string>
<!-- Heading for the instructions to allow a permission --> <!-- Heading for the instructions to allow a permission -->
<string name="phone_feature_blocked_intro">To allow it:</string> <string name="phone_feature_blocked_intro">To allow it:</string>

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
sharedUserId: This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
its sharedUserId for all eternity. Shipping an app update without sharedUserId can have
fatal consequences. For example see:
- https://issuetracker.google.com/issues/36924841
- https://issuetracker.google.com/issues/36905922
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:sharedUserId="${sharedUserId}">
<application
android:name="org.mozilla.fenix.MigratingFenixApplication"
tools:replace="android:name">
<!-- Overriding the alias of the main manifest to route app launches through our
MigrationDecisionActivity which will show the migration screen before launching
into the app if needed. -->
<activity-alias
android:name="${applicationId}.App"
android:targetActivity="org.mozilla.fenix.MigrationDecisionActivity"
tools:replace="android:targetActivity" />
<activity
android:name="org.mozilla.fenix.MigrationDecisionActivity"
android:exported="false" />
<service android:name="org.mozilla.fenix.MigrationService" />
</application>
</manifest>

View File

@ -1,93 +0,0 @@
/* 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
import android.content.Context
import mozilla.components.support.migration.FennecMigrator
import org.mozilla.fenix.session.PerformanceActivityLifecycleCallbacks
import org.mozilla.fenix.migration.MigrationTelemetryListener
import org.mozilla.fenix.perf.runBlockingIncrement
/**
* An application class which knows how to migrate Fennec data.
*/
class MigratingFenixApplication : FenixApplication() {
init {
recordOnInit() // DO NOT MOVE ANYTHING ABOVE HERE: the timing of this measurement is critical.
PerformanceActivityLifecycleCallbacks.isTransientActivityInMigrationVariant = {
if (it is MigrationDecisionActivity) true else false
}
}
val fxaExpectChinaServers = Config.channel.isMozillaOnline
val migrator by lazy {
FennecMigrator.Builder(this, this.components.analytics.crashReporter)
.migrateOpenTabs(this.components.useCases.tabsUseCases)
.migrateHistory(this.components.core.lazyHistoryStorage)
.migrateBookmarks(
this.components.core.lazyBookmarksStorage,
this.components.core.pinnedSiteStorage
)
.migrateLogins(this.components.core.lazyPasswordsStorage)
.migrateFxa(lazy { this.components.backgroundServices.accountManager }, fxaExpectChinaServers)
.migrateAddons(
this.components.core.engine,
this.components.addonCollectionProvider,
this.components.addonUpdater
)
.migrateTelemetryIdentifiers()
.build()
}
val migrationPushSubscriber by lazy {
MigrationPushRenewer(
components.push.feature,
components.migrationStore
)
}
val migrationTelemetryListener by lazy {
MigrationTelemetryListener(
components.analytics.metrics,
components.migrationStore
)
}
override fun setupInMainProcessOnly() {
// These migrations need to run before regular initialization happens.
migrateBlocking()
// Now that we have migrated from Fennec whether the user wants to enable telemetry we can
// initialize Glean
initializeGlean()
// Fenix application initialization can happen now.
super.setupInMainProcessOnly()
// The rest of the migrations can happen now.
migrationPushSubscriber.start()
migrationTelemetryListener.start()
migrator.startMigrationIfNeeded(components.migrationStore, MigrationService::class.java)
}
private fun migrateBlocking() {
val migrator = FennecMigrator.Builder(this, this.components.analytics.crashReporter)
.migrateGecko()
// Telemetry may have been disabled in Fennec, so we need to migrate Settings first
// to correctly initialize telemetry.
.migrateSettings()
.build()
runBlockingIncrement {
migrator.migrateAsync(components.migrationStore).await()
}
}
}
fun Context.getMigratorFromApplication(): FennecMigrator {
return (applicationContext as MigratingFenixApplication).migrator
}

View File

@ -1,44 +0,0 @@
/* 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
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import mozilla.components.support.migration.state.MigrationProgress
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.migration.MigrationProgressActivity
/**
* The purpose of this activity, when launched, is to decide whether we want to show the migration
* screen ([MigrationProgressActivity]) or launch the browser normally ([HomeActivity]).
*/
class MigrationDecisionActivity : Activity() {
private val store by lazy { components.migrationStore }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = if (intent != null) intent else Intent()
val activity = when (store.state.progress) {
MigrationProgress.NONE, MigrationProgress.COMPLETED -> HomeActivity::class.java
MigrationProgress.MIGRATING -> MigrationProgressActivity::class.java
}
intent.setClass(applicationContext, activity)
intent.putExtra(HomeActivity.OPEN_TO_BROWSER, false)
startActivity(intent)
finish()
// We are disabling animations here when switching activities because this results in a
// perceived faster launch. This activity will start immediately with a solid background
// and then we switch to the actual activity without an animation. This visually looks like
// a faster start than launching this activity invisibly and switching to the actual
// activity after that.
overridePendingTransition(0, R.anim.placeholder_animation)
}
}

View File

@ -1,40 +0,0 @@
/* 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
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect
import mozilla.components.concept.push.PushProcessor
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.migration.state.MigrationProgress
import mozilla.components.support.migration.state.MigrationStore
/**
* Force-renews push subscription after migration was complete.
*/
class MigrationPushRenewer(
private val service: PushProcessor?,
private val store: MigrationStore
) {
@OptIn(ExperimentalCoroutinesApi::class)
fun start() {
// Observe for migration completed.
store.flowScoped { flow ->
flow.collect { state ->
Logger("MigrationPushRenewer").debug("Migration state: ${state.progress}")
if (state.progress == MigrationProgress.COMPLETED) {
Logger("MigrationPushRenewer").debug("Renewing registration....")
// This should force a recreation of firebase device token, re-registration with
// the autopush service, and subsequent update of the FxA device record with
// new push subscription information.
service?.renewRegistration()
}
}
}
}
}

View File

@ -1,18 +0,0 @@
/* 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
import mozilla.components.support.migration.AbstractMigrationService
import mozilla.components.support.migration.state.MigrationStore
import org.mozilla.fenix.ext.components
/**
* Background service for running the migration from legacy Firefox for Android (Fennec).
*/
class MigrationService : AbstractMigrationService() {
override val migrator by lazy { getMigratorFromApplication() }
override val store: MigrationStore by lazy { components.migrationStore }
override val migrationDecisionActivity = MigrationDecisionActivity::class.java
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
sharedUserId: This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
its sharedUserId for all eternity. Shipping an app update without sharedUserId can have
fatal consequences. For example see:
- https://issuetracker.google.com/issues/36924841
- https://issuetracker.google.com/issues/36905922
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:sharedUserId="${sharedUserId}">
</manifest>

View File

@ -53,7 +53,6 @@ class IntentReceiverActivityTest {
every { intentProcessors.privateCustomTabIntentProcessor } returns mockIntentProcessor() every { intentProcessors.privateCustomTabIntentProcessor } returns mockIntentProcessor()
every { intentProcessors.externalAppIntentProcessors } returns emptyList() every { intentProcessors.externalAppIntentProcessors } returns emptyList()
every { intentProcessors.fennecPageShortcutIntentProcessor } returns mockIntentProcessor() every { intentProcessors.fennecPageShortcutIntentProcessor } returns mockIntentProcessor()
every { intentProcessors.migrationIntentProcessor } returns mockIntentProcessor()
every { intentProcessors.externalDeepLinkIntentProcessor } returns mockIntentProcessor() every { intentProcessors.externalDeepLinkIntentProcessor } returns mockIntentProcessor()
coEvery { intentProcessors.intentProcessor.process(any()) } returns true coEvery { intentProcessors.intentProcessor.process(any()) } returns true

View File

@ -1,65 +0,0 @@
/* 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.migration
import android.view.View
import android.widget.FrameLayout
import mozilla.components.support.migration.Migration
import mozilla.components.support.migration.MigrationRun
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.databinding.MigrationListItemBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
class MigrationStatusAdapterTest {
private lateinit var adapter: MigrationStatusAdapter
@Before
fun setup() {
adapter = MigrationStatusAdapter()
}
@Test
fun `getItemCount should return the number of items in whitelist`() {
assertEquals(0, adapter.itemCount)
adapter.updateData(
mapOf(
Migration.Addons to MigrationRun(0, success = true),
Migration.Settings to MigrationRun(0, success = true),
Migration.Bookmarks to MigrationRun(0, success = false)
)
)
assertEquals(4, adapter.itemCount)
}
@Test
fun `creates and binds viewholder`() {
adapter.updateData(
mapOf(
Migration.History to MigrationRun(0, success = true)
)
)
val holder1 = adapter.createViewHolder(FrameLayout(testContext), 0)
val holder2 = adapter.createViewHolder(FrameLayout(testContext), 0)
val binding1 = MigrationListItemBinding.bind(holder1.itemView)
val binding2 = MigrationListItemBinding.bind(holder2.itemView)
adapter.bindViewHolder(holder1, 0)
adapter.bindViewHolder(holder2, 1)
assertEquals("Settings", binding1.migrationItemName.text)
assertEquals(View.INVISIBLE, binding1.migrationStatusImage.visibility)
assertEquals("History", binding2.migrationItemName.text)
assertEquals(View.VISIBLE, binding2.migrationStatusImage.visibility)
assertEquals("Migration completed", binding2.migrationStatusImage.contentDescription)
}
}

View File

@ -1,74 +0,0 @@
/* 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.migration
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import io.mockk.verifyOrder
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.migration.state.MigrationAction
import mozilla.components.support.migration.state.MigrationStore
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.rule.MainCoroutineRule
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
class MigrationTelemetryListenerTest {
private val testDispatcher = TestCoroutineDispatcher()
@get:Rule
val coroutinesTestRule = MainCoroutineRule(testDispatcher)
@MockK(relaxed = true) private lateinit var metrics: MetricController
@MockK(relaxed = true) private lateinit var logger: Logger
private lateinit var store: MigrationStore
private lateinit var listener: MigrationTelemetryListener
@Before
fun setup() {
MockKAnnotations.init(this)
store = MigrationStore()
listener = MigrationTelemetryListener(
metrics = metrics,
store = store,
logger = logger
)
}
@After
fun cleanUp() {
testDispatcher.cleanupTestCoroutines()
}
@Test
fun `progress state is logged`() = testDispatcher.runBlockingTest {
listener.start()
store.dispatch(MigrationAction.Started).joinBlocking()
store.dispatch(MigrationAction.Completed).joinBlocking()
store.dispatch(MigrationAction.Clear).joinBlocking()
verifyOrder {
logger.debug("Migration state: MIGRATING")
logger.debug("Migration state: COMPLETED")
logger.debug("Migration state: NONE")
}
}
@Test
fun `metrics are logged when migration is completed`() = testDispatcher.runBlockingTest {
listener.start()
store.dispatch(MigrationAction.Completed).joinBlocking()
verify { metrics.track(Event.FennecToFenixMigrated) }
}
}

View File

@ -172,7 +172,6 @@ object Deps {
const val mozilla_support_utils = "org.mozilla.components:support-utils:${Versions.mozilla_android_components}" const val mozilla_support_utils = "org.mozilla.components:support-utils:${Versions.mozilla_android_components}"
const val mozilla_support_test = "org.mozilla.components:support-test:${Versions.mozilla_android_components}" const val mozilla_support_test = "org.mozilla.components:support-test:${Versions.mozilla_android_components}"
const val mozilla_support_test_libstate = "org.mozilla.components:support-test-libstate:${Versions.mozilla_android_components}" const val mozilla_support_test_libstate = "org.mozilla.components:support-test-libstate:${Versions.mozilla_android_components}"
const val mozilla_support_migration = "org.mozilla.components:support-migration:${Versions.mozilla_android_components}"
const val mozilla_support_locale = "org.mozilla.components:support-locale:${Versions.mozilla_android_components}" const val mozilla_support_locale = "org.mozilla.components:support-locale:${Versions.mozilla_android_components}"
const val sentry = "io.sentry:sentry-android:${Versions.sentry}" const val sentry = "io.sentry:sentry-android:${Versions.sentry}"