diff --git a/CHANGELOG.md b/CHANGELOG.md index 818bde7fe..94f366956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #1874 - Added TOP info panel dialog for custom tabs. - #1411 - Added disabled style for disabled permissions items in site info panel. - #1735 - Adds API to see the release channel +- #2318 - Added Firefox Accounts Pairing feature to "Turn On Sync" options ### Changed - #1429 - Updated site permissions ui for MVP diff --git a/app/src/main/java/org/mozilla/fenix/settings/PairFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/PairFragment.kt new file mode 100644 index 000000000..19d5785e7 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/PairFragment.kt @@ -0,0 +1,83 @@ +/* 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.settings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.core.text.HtmlCompat +import androidx.fragment.app.Fragment +import mozilla.components.feature.qr.QrFeature +import mozilla.components.support.base.feature.BackHandler +import mozilla.components.support.base.feature.ViewBoundFeatureWrapper +import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.requireComponents + +class PairFragment : Fragment(), BackHandler { + private val qrFeature = ViewBoundFeatureWrapper() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_pair, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val instructionsText = view.findViewById(R.id.pair_instructions) as TextView + instructionsText.setText(HtmlCompat.fromHtml(getString(R.string.pair_instructions), + HtmlCompat.FROM_HTML_MODE_LEGACY)) + + qrFeature.set( + QrFeature( + requireContext(), + fragmentManager = requireFragmentManager(), + onNeedToRequestPermissions = { permissions -> + requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSIONS) + }, + onScanResult = { pairingUrl -> + requireComponents.services.accountsAuthFeature.beginPairingAuthentication(pairingUrl) + view?.let { + (activity as HomeActivity).openToBrowser(BrowserDirection.FromSettings) + } + }), + owner = this, + view = view + ) + + qrFeature.withFeature { + it.scan(R.id.pair_layout) + } + } + + override fun onResume() { + super.onResume() + (activity as AppCompatActivity).title = getString(R.string.preferences_sync) + (activity as AppCompatActivity).supportActionBar?.show() + } + + override fun onBackPressed(): Boolean { + return when { + qrFeature.onBackPressed() -> true + else -> false + } + } + + companion object { + private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1 + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + when (requestCode) { + REQUEST_CODE_CAMERA_PERMISSIONS -> qrFeature.withFeature { + it.onPermissionsResult(permissions, grantResults) + } + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/PairInstructionsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/PairInstructionsFragment.kt new file mode 100644 index 000000000..cda30de7e --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/PairInstructionsFragment.kt @@ -0,0 +1,58 @@ +/* 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.settings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.core.text.HtmlCompat +import androidx.navigation.Navigation +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import mozilla.components.support.base.feature.BackHandler +import org.mozilla.fenix.R + +class PairInstructionsFragment : BottomSheetDialogFragment(), BackHandler { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + (activity as AppCompatActivity).title = getString(R.string.preferences_sync) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_pair_instructions, container, false) + } + + override fun onResume() { + super.onResume() + (activity as AppCompatActivity).title = getString(R.string.preferences_sync) + (activity as AppCompatActivity).supportActionBar?.show() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val instructionsText = view.findViewById(R.id.pair_instructions_info) as TextView + instructionsText.setText(HtmlCompat.fromHtml(getString(R.string.pair_instructions), + HtmlCompat.FROM_HTML_MODE_LEGACY)) + + val openCamera = view.findViewById(R.id.pair_open_camera) as Button + openCamera.setOnClickListener(View.OnClickListener { + val directions = PairInstructionsFragmentDirections.actionPairInstructionsFragmentToPairFragment() + Navigation.findNavController(view!!).navigate(directions) + }) + + val cancelCamera = view.findViewById(R.id.pair_cancel) as Button + cancelCamera.setOnClickListener(View.OnClickListener { + onBackPressed() + }) + } + + override fun onBackPressed(): Boolean { + return true + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt index 131cc2e0c..de4b11c96 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -188,7 +188,7 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope, AccountObse private fun getClickListenerForSignIn(): OnPreferenceClickListener { return OnPreferenceClickListener { - val directions = SettingsFragmentDirections.actionSettingsFragmentToSyncFragment() + val directions = SettingsFragmentDirections.actionSettingsFragmentToTurnOnSyncFragment() Navigation.findNavController(view!!).navigate(directions) true } diff --git a/app/src/main/java/org/mozilla/fenix/settings/TurnOnSyncFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/TurnOnSyncFragment.kt index dd3cb51de..75f36af10 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/TurnOnSyncFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/TurnOnSyncFragment.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.settings import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.Navigation import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import org.mozilla.fenix.BrowserDirection @@ -16,8 +17,8 @@ import org.mozilla.fenix.ext.requireComponents class TurnOnSyncFragment : PreferenceFragmentCompat() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + override fun onResume() { + super.onResume() (activity as AppCompatActivity).title = getString(R.string.preferences_sync) (activity as AppCompatActivity).supportActionBar?.show() } @@ -29,8 +30,11 @@ class TurnOnSyncFragment : PreferenceFragmentCompat() { findPreference(context!!.getPreferenceKey(R.string.pref_key_sync_sign_in)) val preferenceNewAccount = findPreference(context!!.getPreferenceKey(R.string.pref_key_sync_create_account)) + val preferencePairSignIn = + findPreference(context!!.getPreferenceKey(R.string.pref_key_sync_pair)) preferenceSignIn?.onPreferenceClickListener = getClickListenerForSignIn() preferenceNewAccount?.onPreferenceClickListener = getClickListenerForSignIn() + preferencePairSignIn?.onPreferenceClickListener = getClickListenerForPairing() } private fun getClickListenerForSignIn(): Preference.OnPreferenceClickListener { @@ -47,4 +51,13 @@ class TurnOnSyncFragment : PreferenceFragmentCompat() { true } } + + private fun getClickListenerForPairing(): Preference.OnPreferenceClickListener { + return Preference.OnPreferenceClickListener { + val directions = TurnOnSyncFragmentDirections.actionTurnOnSyncFragmentToPairInstructionsFragment() + Navigation.findNavController(view!!).navigate(directions) + + true + } + } } diff --git a/app/src/main/res/layout/fragment_pair.xml b/app/src/main/res/layout/fragment_pair.xml new file mode 100644 index 000000000..e8818ef9f --- /dev/null +++ b/app/src/main/res/layout/fragment_pair.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/app/src/main/res/layout/fragment_pair_instructions.xml b/app/src/main/res/layout/fragment_pair_instructions.xml new file mode 100644 index 000000000..9a7c09c11 --- /dev/null +++ b/app/src/main/res/layout/fragment_pair_instructions.xml @@ -0,0 +1,58 @@ + + + + + + + + +