Issue #22489: Remove "Fennec to Fenix" migration code

upstream-sync
Sebastian Kaspari 3 years ago committed by mergify[bot]
parent b6932dd590
commit 834d0ee12d

@ -177,14 +177,6 @@ android {
androidTest {
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 {
@ -530,7 +522,6 @@ dependencies {
implementation Deps.mozilla_support_rustlog
implementation Deps.mozilla_support_utils
implementation Deps.mozilla_support_locale
implementation Deps.mozilla_support_migration
implementation Deps.mozilla_ui_colors
implementation Deps.mozilla_ui_icons

@ -1493,17 +1493,6 @@
column="1"/>
</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
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">

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

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

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

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

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

@ -8,10 +8,9 @@ import android.content.Intent
import mozilla.components.feature.intent.processing.IntentProcessor
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity
import org.mozilla.fenix.migration.MigrationProgressActivity
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
@ -20,7 +19,6 @@ enum class IntentProcessorType {
get() = when (this) {
EXTERNAL_APP -> ExternalAppBrowserActivity::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) {
EXTERNAL_APP -> true
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].
*/
fun IntentProcessors.getType(processor: IntentProcessor?) = when {
migrationIntentProcessor == processor -> IntentProcessorType.MIGRATION
externalAppIntentProcessors.contains(processor) ||
customTabIntentProcessor == processor ||
privateCustomTabIntentProcessor == processor -> IntentProcessorType.EXTERNAL_APP

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

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

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

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

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

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

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

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

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

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

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

@ -121,17 +121,6 @@
<dimen name="locale_item_subtitle_size">12sp</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 -->
<dimen name="share_recent_apps_background_radius">10dp</dimen>
<dimen name="share_recent_apps_padding">8dp</dimen>

@ -1564,17 +1564,17 @@
<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 -->
<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-->
<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 -->
<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-->
<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 -->
<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.)-->
<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 -->
<string name="phone_feature_blocked_intro">To allow it:</string>

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

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

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

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

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

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

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

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

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

@ -172,7 +172,6 @@ object Deps {
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_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 sentry = "io.sentry:sentry-android:${Versions.sentry}"

Loading…
Cancel
Save