diff --git a/app/build.gradle b/app/build.gradle index b74d955a05a..2d25c51fa6e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -676,6 +676,10 @@ dependencies { implementation deps.android_components.support_webextensions implementation deps.android_components.support_ktx implementation deps.android_components.feature_accounts + implementation deps.android_components.concept_push + implementation deps.android_components.feature_push + implementation deps.android_components.feature_accounts_push + implementation deps.android_components.lib_push_firebase implementation deps.android_components.feature_webcompat implementation deps.android_components.feature_webcompat_reporter implementation deps.android_components.feature_addons diff --git a/app/src/common/shared/com/igalia/wolvic/browser/Accounts.kt b/app/src/common/shared/com/igalia/wolvic/browser/Accounts.kt index 774d9ac814d..1c522944db2 100644 --- a/app/src/common/shared/com/igalia/wolvic/browser/Accounts.kt +++ b/app/src/common/shared/com/igalia/wolvic/browser/Accounts.kt @@ -25,19 +25,38 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.future.future import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import mozilla.components.concept.sync.* +import mozilla.components.concept.sync.AccountObserver +import mozilla.components.concept.sync.AuthFlowError +import mozilla.components.concept.sync.AuthType +import mozilla.components.concept.sync.ConstellationState +import mozilla.components.concept.sync.Device +import mozilla.components.concept.sync.DeviceCapability +import mozilla.components.concept.sync.DeviceCommandOutgoing +import mozilla.components.concept.sync.DeviceConstellationObserver +import mozilla.components.concept.sync.OAuthAccount +import mozilla.components.concept.sync.Profile +import mozilla.components.feature.accounts.push.FxaPushSupportFeature +import mozilla.components.feature.accounts.push.SendTabFeature +import mozilla.components.feature.push.AutoPushFeature +import mozilla.components.feature.push.PushConfig +import mozilla.components.feature.push.PushScope +import mozilla.components.lib.push.firebase.AbstractFirebasePushService import mozilla.components.service.fxa.FirefoxAccount import mozilla.components.service.fxa.SyncEngine import mozilla.components.service.fxa.manager.SyncEnginesStorage import mozilla.components.service.fxa.sync.SyncReason import mozilla.components.service.fxa.sync.SyncStatusObserver import mozilla.components.service.fxa.sync.getLastSynced +import mozilla.components.support.base.log.logger.Logger +import org.json.JSONObject import java.net.URL import java.util.concurrent.CompletableFuture import kotlin.concurrent.thread const val PROFILE_PICTURE_TAG = "fxa_profile_picture" +class FirebasePushService : AbstractFirebasePushService() + class Accounts constructor(val context: Context) { private val LOGTAG = SystemUtils.createLogtag(Accounts::class.java) @@ -74,6 +93,7 @@ class Accounts constructor(val context: Context) { private val syncStatusObserver = object : SyncStatusObserver { override fun onStarted() { Log.d(LOGTAG, "Account syncing has started") + Logger(LOGTAG).error("TabReceived : SyncStatusObserver Account syncing has started") isSyncing = true syncListeners.toMutableList().forEach { @@ -85,6 +105,7 @@ class Accounts constructor(val context: Context) { override fun onIdle() { Log.d(LOGTAG, "Account syncing has finished") + Logger(LOGTAG).error("TabReceived : SyncStatusObserver Account syncing has finished") isSyncing = false @@ -101,6 +122,7 @@ class Accounts constructor(val context: Context) { override fun onError(error: Exception?) { Log.d(LOGTAG, "There was an error while syncing the account: " + error?.localizedMessage) + Logger(LOGTAG).error("TabReceived : SyncStatusObserver There was an error while syncing the account: " + error?.localizedMessage) isSyncing = false syncListeners.toMutableList().forEach { @@ -127,12 +149,16 @@ class Accounts constructor(val context: Context) { private val accountObserver = object : AccountObserver { override fun onAuthenticated(account: OAuthAccount, authType: AuthType) { Log.d(LOGTAG, "The user has been successfully logged in") + Logger(LOGTAG).error("TabReceived : AccountObserver The user has been successfully logged in account: " + account) + + Logger(LOGTAG).error("TabReceived : " + account.toJSONString()) if (authType !== AuthType.Existing) { TelemetryService.FxA.signInResult(true) } accountStatus = AccountStatus.SIGNED_IN + Logger(LOGTAG).error("TabReceived : onAuthenticated account status $accountStatus") // We must delay applying the device name from settings after we are authenticated // as we will stuck if we get it directly when initializing services.accountManager @@ -155,21 +181,60 @@ class Accounts constructor(val context: Context) { it.onAuthenticated(account, authType) } originSessionId = null - } - runBlocking { - refreshJob = launch { - while (isSignedIn()) { - Log.d(LOGTAG, "Polling for events") - pollForEventsAsync() - kotlinx.coroutines.delay(10000) + var jsonString = (account as FirefoxAccount).toJSONString() + var senderId: String? = runCatching { + JSONObject(jsonString).optJSONObject("config")?.optString("client_id", null) + }.getOrNull() + + + senderId = runCatching { + JSONObject(jsonString).optJSONObject("server_local_device_info") + ?.optString("id", null) + }.getOrNull() + + Logger(LOGTAG).error("TabReceived : onAuthenticated client_id $senderId") + + var pushConfig = PushConfig( + senderId = senderId.toString() + ) + Logger(LOGTAG).error("TabReceived : onAuthenticated push config $pushConfig") + + var autoPushFeature = AutoPushFeature( + context = context, + service = FirebasePushService(), + config = pushConfig + ) + autoPushFeature.register(object : AutoPushFeature.Observer { + override fun onSubscriptionChanged(scope: PushScope) { + Logger(LOGTAG).error("TabReceived : autoPushFeature onSubscriptionChanged $scope") + } + + override fun onMessageReceived(scope: PushScope, message: ByteArray?) { + Logger(LOGTAG).error("TabReceived : autoPushFeature onMessageReceived $scope $message") + } + }) + Logger(LOGTAG).error("TabReceived : onAuthenticated auto push feature $autoPushFeature") + + // this works, but the push configuration does not + SendTabFeature(services.accountManager) { device, tabs -> + tabs.forEach { tab -> + Logger(LOGTAG).error("TabReceived : Received tab: Device=$device Title=${tab.title}, URL=${tab.url}") } } + + // manual sync shows "Current device needs push endpoint registration, so checking for missed commands" + var fxaPushSupportFeature = + FxaPushSupportFeature(context, services.accountManager, autoPushFeature) + fxaPushSupportFeature.initialize() + Logger(LOGTAG).error("TabReceived : onAuthenticated auto push feature $fxaPushSupportFeature") } + } override fun onAuthenticationProblems() { Log.d(LOGTAG, "There was a problem authenticating the user") + Logger(LOGTAG).error("TabReceived : AccountObserver There was a problem authenticating the user") TelemetryService.FxA.signInResult(false) @@ -177,6 +242,7 @@ class Accounts constructor(val context: Context) { refreshJob?.cancel(null) accountStatus = AccountStatus.NEEDS_RECONNECT + Logger(LOGTAG).error("TabReceived : onAuthenticationProblems account status $accountStatus") accountListeners.toMutableList().forEach { Handler(Looper.getMainLooper()).post { it.onAuthenticationProblems() @@ -186,11 +252,13 @@ class Accounts constructor(val context: Context) { override fun onLoggedOut() { Log.d(LOGTAG, "The user has been logged out") + Logger(LOGTAG).error("TabReceived : AccountObserver The user has been logged out") originSessionId = null refreshJob?.cancel(null) accountStatus = AccountStatus.SIGNED_OUT + Logger(LOGTAG).error("TabReceived : onLoggedOut account status $accountStatus") accountListeners.toMutableList().forEach { Handler(Looper.getMainLooper()).post { it.onLoggedOut() @@ -202,6 +270,7 @@ class Accounts constructor(val context: Context) { override fun onProfileUpdated(profile: Profile) { Log.d(LOGTAG, "The user profile has been updated") + Logger(LOGTAG).error("TabReceived : AccountObserver The user profile has been updated profile: " + profile) accountListeners.toMutableList().forEach { Handler(Looper.getMainLooper()).post { @@ -211,14 +280,27 @@ class Accounts constructor(val context: Context) { loadProfilePicture(profile) } + + override fun onFlowError(error: AuthFlowError) { + Logger(LOGTAG).error("TabReceived : AccountObserver onFlowError $error") + super.onFlowError(error) + } + + override fun onReady(authenticatedAccount: OAuthAccount?) { + Logger(LOGTAG).error("TabReceived : AccountObserver onReady account: $authenticatedAccount") + super.onReady(authenticatedAccount) + } } init { + Logger(LOGTAG).error("TabReceived : ${services.accountManager} register") + services.accountManager.register(accountObserver) + Logger(LOGTAG).error("TabReceived : ${services.accountManager} registerForSyncEvents") services.accountManager.registerForSyncEvents( syncStatusObserver, ProcessLifecycleOwner.get(), false ) - services.accountManager.register(accountObserver) accountStatus = if (services.accountManager.authenticatedAccount() != null) { + Logger(LOGTAG).error("TabReceived : account " + services.accountManager.authenticatedAccount()) if (services.accountManager.accountNeedsReauth()) { AccountStatus.NEEDS_RECONNECT @@ -229,6 +311,11 @@ class Accounts constructor(val context: Context) { } else { AccountStatus.SIGNED_OUT } + Logger(LOGTAG).error("TabReceived : init account status $accountStatus") + // accountStatus is SIGNED_OUT at this point + + + } private fun loadProfilePicture(profile: Profile) { @@ -331,6 +418,9 @@ class Accounts constructor(val context: Context) { } fun updateProfileAsync(): CompletableFuture? { + + Logger("Accounts").error("TabReceived : needs reauth " + services.accountManager.accountNeedsReauth()) + return CoroutineScope(Dispatchers.Main).future { services.accountManager.accountProfile() } @@ -379,7 +469,13 @@ class Accounts constructor(val context: Context) { } fun lastSync(): Long { + + Logger("Accounts").error("TabReceived : lastSync()") + Logger("Accounts").error("TabReceived : lastSync() ${services.accountManager.accountProfile()}") + Logger("Accounts").error("TabReceived : lastSync() ${services.accountManager.accountProfile()?.email}") + services.accountManager.accountProfile()?.email?.let { + Logger("Accounts").error("TabReceived : getFxALastSync $it") return SettingsStore.getInstance(context).getFxALastSync(it) } return 0 diff --git a/app/src/common/shared/com/igalia/wolvic/browser/Services.kt b/app/src/common/shared/com/igalia/wolvic/browser/Services.kt index a7bf7df31f8..9f3b7e5a778 100644 --- a/app/src/common/shared/com/igalia/wolvic/browser/Services.kt +++ b/app/src/common/shared/com/igalia/wolvic/browser/Services.kt @@ -73,13 +73,23 @@ class Services(val context: Context, places: Places): WSession.NavigationDelegat private val logTag = "DeviceEventsObserver" override fun onEvents(events: List) { + + Logger(logTag).error("TabReceived : AccountEventsObserver onEvents") + CoroutineScope(Dispatchers.Main).launch { Logger(logTag).info("Received ${events.size} device event(s)") + Logger(logTag).error("TabReceived : onEvents Received ${events.size} device event(s)") + + events.forEach { event -> + Logger(logTag).error("TabReceived : event $event") + } + events .filterIsInstance() .map { it.command } .filterIsInstance() .forEach { command -> + Logger(logTag).error("TabReceived : Received a TabReceived event") command.from?.deviceType?.let { TelemetryService.FxA.receivedTab(it) } tabReceivedDelegate?.onTabsReceived(command.entries) } @@ -101,6 +111,9 @@ class Services(val context: Context, places: Places): WSession.NavigationDelegat syncConfig = SyncConfig(setOf(SyncEngine.History, SyncEngine.Bookmarks, SyncEngine.Passwords), PeriodicSyncConfig(periodMinutes = 1440)) ).also { + + Logger("Services").error("TabReceived : $it registerForAccountEvents") + it.registerForAccountEvents(deviceEventObserver, ProcessLifecycleOwner.get(), true) } @@ -117,7 +130,10 @@ class Services(val context: Context, places: Places): WSession.NavigationDelegat } private fun init() { + Logger("Services").error("TabReceived : init() will call $accountManager start") CoroutineScope(Dispatchers.Main).launch { + Logger("Services").error("TabReceived : $accountManager start") + accountManager.start() } } diff --git a/app/src/common/shared/com/igalia/wolvic/browser/SettingsStore.java b/app/src/common/shared/com/igalia/wolvic/browser/SettingsStore.java index d239032fd1c..d4bc533b265 100644 --- a/app/src/common/shared/com/igalia/wolvic/browser/SettingsStore.java +++ b/app/src/common/shared/com/igalia/wolvic/browser/SettingsStore.java @@ -928,23 +928,34 @@ public void setFxALastSync(@NonNull String email, long timestamp) { } public long getFxALastSync(@NonNull String email) { + + Log.e(LOGTAG, "TabReceived : getFxALastSync " + email); + String json = mPrefs.getString( mContext.getString(R.string.settings_key_fxa_last_sync), null); + Log.e(LOGTAG, "TabReceived : " + json); + try { JSONObject jsonObject = new JSONObject(json); Iterator iterator = jsonObject.keys(); while (iterator.hasNext()) { String key = iterator.next(); if (key.equals(email)) { + + Log.e(LOGTAG, "TabReceived : found " + jsonObject.getLong(key)); + return jsonObject.getLong(key); } } + Log.e(LOGTAG, "TabReceived : not found"); + return FXA_LAST_SYNC_NEVER; } catch (Exception e) { + Log.e(LOGTAG, "TabReceived : error"); return FXA_LAST_SYNC_NEVER; } } diff --git a/app/src/common/shared/com/igalia/wolvic/browser/engine/Session.java b/app/src/common/shared/com/igalia/wolvic/browser/engine/Session.java index 8dc0db430a4..92b639de0b3 100644 --- a/app/src/common/shared/com/igalia/wolvic/browser/engine/Session.java +++ b/app/src/common/shared/com/igalia/wolvic/browser/engine/Session.java @@ -145,6 +145,9 @@ static Session createWebExtensionSession(Context aContext, WRuntime aRuntime, @N @NonNull static Session createSession(Context aContext, WRuntime aRuntime, @NonNull SessionSettings aSettings, @Session.SessionOpenModeFlags int aOpenMode, @NonNull SessionChangeListener listener) { + + Log.e(LOGTAG, "TabReceived : Session createSession"); + Session session = new Session(aContext, aRuntime, aSettings); session.addSessionChangeListener(listener); listener.onSessionAdded(session); diff --git a/app/src/common/shared/com/igalia/wolvic/browser/engine/SessionStore.java b/app/src/common/shared/com/igalia/wolvic/browser/engine/SessionStore.java index 6010e799d2d..83e61a12938 100644 --- a/app/src/common/shared/com/igalia/wolvic/browser/engine/SessionStore.java +++ b/app/src/common/shared/com/igalia/wolvic/browser/engine/SessionStore.java @@ -183,6 +183,9 @@ public void onTrackingProtectionLevelUpdated(int level) { @NonNull private Session addSession(@NonNull Session aSession) { + + Log.e(LOGTAG, "TabReceived : addSession " + aSession); + aSession.setPermissionDelegate(this); aSession.addNavigationListener(mServices); mSessions.add(aSession); @@ -220,6 +223,9 @@ public Session createWebExtensionSession(boolean openSession, boolean aPrivateMo @NonNull public Session createSession(boolean aPrivateMode) { + + Log.e(LOGTAG, "TabReceived : createSession(boolean aPrivateMode)"); + SessionSettings settings = new SessionSettings(new SessionSettings.Builder().withDefaultSettings(mContext).withPrivateBrowsing(aPrivateMode)); return createSession(settings, Session.SESSION_OPEN); } @@ -232,7 +238,13 @@ public Session createSession(boolean openSession, boolean aPrivateMode) { @NonNull Session createSession(@NonNull SessionSettings aSettings, @Session.SessionOpenModeFlags int aOpenMode) { + + Log.e(LOGTAG, "TabReceived : createSession(@NonNull SessionSettings aSettings, @Session.SessionOpenModeFlags int aOpenMode)"); + Session session = Session.createSession(mContext, mRuntime, aSettings, aOpenMode, this); + + Log.e(LOGTAG, "TabReceived : created " + session); + return addSession(session); } @@ -528,6 +540,9 @@ public void removePermissionException(@NonNull String uri, @SitePermission.Categ @Override public void onSessionAdded(Session aSession) { + + Log.e(LOGTAG, "TabReceived : SessionStore.onSessionAdded"); + ComponentsAdapter.get().addSession(aSession); for (SessionChangeListener listener : mSessionChangeListeners) { listener.onSessionAdded(aSession); diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/AbstractTabsBar.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/AbstractTabsBar.java index 4b338b74da2..6f6a722a68a 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/AbstractTabsBar.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/AbstractTabsBar.java @@ -1,6 +1,7 @@ package com.igalia.wolvic.ui.widgets; import android.content.Context; +import android.util.Log; import androidx.annotation.NonNull; import androidx.databinding.ObservableBoolean; @@ -106,6 +107,7 @@ public void onWidgetUpdate(Widget aWidget) { @Override public void onSessionAdded(Session aSession) { + Log.e(LOGTAG, "TabReceived : AbstractTabsBar.onSessionAdded"); refreshTabs(); } diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java index e144edf9377..03586082d1f 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/Windows.java @@ -1683,18 +1683,29 @@ private void closeTabs(List aTabs, boolean privateMode, boolean hidePan @Override public void onTabsReceived(@NonNull List aTabs) { + + Log.e(LOGTAG, "TabReceived : onTabsReceived"); + WindowWidget targetWindow = mFocusedWindow; boolean fullscreen = targetWindow.getSession().isInFullScreen(); for (int i = aTabs.size() - 1; i >= 0; --i) { + + Log.e(LOGTAG, "TabReceived : received " + aTabs.get(i) + " " + aTabs.get(i).getTitle() + " " + aTabs.get(i).getUrl()); + Session session = SessionStore.get().createSession(targetWindow.getSession().isPrivateMode()); // Cache the provided data to avoid delays if the tabs are loaded at the same time the // tabs panel is shown. - session.getSessionState().mTitle = aTabs.get(i).getTitle(); - session.getSessionState().mUri = aTabs.get(i).getUrl(); + session.onTitleChange(session.getWSession(), aTabs.get(i).getTitle()); + session.onLocationChange(session.getWSession(), aTabs.get(i).getUrl()); + +// session.getSessionState().mTitle = aTabs.get(i).getTitle(); +// session.getSessionState().mUri = aTabs.get(i).getUrl(); session.loadUri(aTabs.get(i).getUrl()); session.updateLastUse(); + Log.e(LOGTAG, "TabReceived : created " + session); + TelemetryService.Tabs.openedCounter(TelemetryService.Tabs.TabSource.RECEIVED); if (i == 0 && !fullscreen) { diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/FxAAccountOptionsView.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/FxAAccountOptionsView.java index f4c52e0b2d4..6f7a02ca507 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/FxAAccountOptionsView.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/settings/FxAAccountOptionsView.java @@ -241,31 +241,47 @@ public void resumeWith(@NonNull Object o) {} void updateCurrentAccountState() { switch(mAccounts.getAccountStatus()) { case NEEDS_RECONNECT: + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState NEEDS_RECONNECT"); mBinding.signButton.setButtonText(R.string.settings_fxa_account_reconnect); break; case SIGNED_IN: + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState SIGNED_IN"); mBinding.signButton.setButtonText(R.string.settings_fxa_account_sign_out); Profile profile = mAccounts.accountProfile(); if (profile != null) { + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState updateProfile(profile)"); updateProfile(profile); } else { + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState profile is NULL, refreshing"); try { + + // authenticatedAccount() + + Objects.requireNonNull(mAccounts.updateProfileAsync()). - thenAcceptAsync((u) -> updateProfile(mAccounts.accountProfile()), mUIThreadExecutor). + thenAcceptAsync((u) -> { + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState refreshed profile received: " + u); + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState refreshed profile stored: " + mAccounts.accountProfile()); + updateProfile(mAccounts.accountProfile()); + } + , mUIThreadExecutor). exceptionally(throwable -> { + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState Error getting the account profile"); Log.d(LOGTAG, "Error getting the account profile: " + throwable.getLocalizedMessage()); return null; }); } catch (NullPointerException e) { Log.d(LOGTAG, "Error getting the account profile: " + e.getLocalizedMessage()); + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState Error getting the account profile"); } } break; case SIGNED_OUT: + Log.e(LOGTAG, "TabReceived : updateCurrentAccountState SIGNED_OUT"); mBinding.signButton.setButtonText(R.string.settings_fxa_account_sign_in); break; @@ -275,12 +291,20 @@ void updateCurrentAccountState() { } private void updateProfile(Profile profile) { + + if (profile != null) { + Log.e(LOGTAG, "TabReceived : updateProfile is " + profile.getEmail() + " " + profile.getDisplayName()); mBinding.accountEmail.setText(profile.getEmail()); + } else { + Log.e(LOGTAG, "TabReceived : updateProfile was NULL"); } } private void sync(View view) { + + Log.e(LOGTAG, "TabReceived : sync button"); + mAccounts.syncNowAsync(SyncReason.User.INSTANCE, false); mAccounts.updateProfileAsync(); } diff --git a/versions.gradle b/versions.gradle index 7d9f33a9138..ed24d9bd04a 100644 --- a/versions.gradle +++ b/versions.gradle @@ -91,6 +91,10 @@ android_components.support_rusthttp = "org.mozilla.components:support-rusthttp:$ android_components.support_webextensions = "org.mozilla.components:support-webextensions:$versions.android_components" android_components.support_ktx = "org.mozilla.components:support-ktx:$versions.android_components" android_components.feature_accounts = "org.mozilla.components:feature-accounts:$versions.android_components" +android_components.concept_push = "org.mozilla.components:concept-push:$versions.android_components" +android_components.feature_push = "org.mozilla.components:feature-push:$versions.android_components" +android_components.feature_accounts_push = "org.mozilla.components:feature-accounts-push:$versions.android_components" +android_components.lib_push_firebase = "org.mozilla.components:lib-push-firebase:$versions.android_components" android_components.feature_webcompat = "org.mozilla.components:feature-webcompat:$versions.android_components" android_components.feature_webcompat_reporter = "org.mozilla.components:feature-webcompat-reporter:$versions.android_components" android_components.feature_addons = "org.mozilla.components:feature-addons:$versions.android_components"