Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Support for clearing bookmarks and history when signing out #2374

Merged
merged 1 commit into from
Nov 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package org.mozilla.vrbrowser.browser

import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.os.Handler
import android.os.Looper
import android.util.Log
Expand All @@ -21,10 +23,16 @@ 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 org.mozilla.vrbrowser.R
import org.mozilla.vrbrowser.VRBrowserApplication
import org.mozilla.vrbrowser.utils.BitmapCache
import org.mozilla.vrbrowser.utils.SystemUtils
import org.mozilla.vrbrowser.utils.ViewUtils
import java.net.URL
import java.util.concurrent.CompletableFuture

const val PROFILE_PICTURE_TAG = "fxa_profile_picture"

class Accounts constructor(val context: Context) {

private val LOGTAG = SystemUtils.createLogtag(Accounts::class.java)
Expand All @@ -43,6 +51,7 @@ class Accounts constructor(val context: Context) {
NONE
}

var profilePicture: BitmapDrawable? = loadDefaultProfilePicture()
var loginOrigin: LoginOrigin = LoginOrigin.NONE
var accountStatus = AccountStatus.SIGNED_OUT
private val accountListeners = ArrayList<AccountObserver>()
Expand Down Expand Up @@ -152,6 +161,8 @@ class Accounts constructor(val context: Context) {
it.onLoggedOut()
}
}

loadDefaultProfilePicture()
}

override fun onProfileUpdated(profile: Profile) {
Expand All @@ -162,6 +173,8 @@ class Accounts constructor(val context: Context) {
it.onProfileUpdated(profile)
}
}

loadProfilePicture(profile)
}
}

Expand All @@ -183,6 +196,38 @@ class Accounts constructor(val context: Context) {
}
}

private fun loadProfilePicture(profile: Profile) {
CoroutineScope(Dispatchers.IO).launch {
try {
val url = URL(profile.avatar!!.url)
BitmapFactory.decodeStream(url.openStream())?.let {
val bitmap = ViewUtils.getRoundedCroppedBitmap(it)
profilePicture = BitmapDrawable(context.resources, bitmap)
BitmapCache.getInstance(context).addBitmap(PROFILE_PICTURE_TAG, bitmap)

} ?: throw IllegalArgumentException()

} catch (e: Exception) {
loadDefaultProfilePicture()

} finally {
accountListeners.toMutableList().forEach {
Handler(Looper.getMainLooper()).post {
it.onProfileUpdated(profile)
}
}
}
}
}

private fun loadDefaultProfilePicture(): BitmapDrawable? {
BitmapFactory.decodeResource(context.resources, R.drawable.ic_icon_settings_account)?.let {
BitmapCache.getInstance(context).addBitmap(PROFILE_PICTURE_TAG, it)
profilePicture = BitmapDrawable(context.resources, ViewUtils.getRoundedCroppedBitmap(it))
}

return profilePicture
}

fun addAccountListener(aListener: AccountObserver) {
if (!accountListeners.contains(aListener)) {
Expand Down Expand Up @@ -271,7 +316,7 @@ class Accounts constructor(val context: Context) {
return services.accountManager.accountProfile()
}

fun logoutAsync(): CompletableFuture<Unit?>? {
fun logoutAsync(): CompletableFuture<Unit?> {
otherDevices = emptyList()
return CoroutineScope(Dispatchers.Main).future {
services.accountManager.logoutAsync().await()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class BookmarksStore constructor(val context: Context) {
}

private val listeners = ArrayList<BookmarkListener>()
private val storage = (context.applicationContext as VRBrowserApplication).places.bookmarks
private var storage = (context.applicationContext as VRBrowserApplication).places.bookmarks
private val titles = rootTitles(context)
private val accountManager = (context.applicationContext as VRBrowserApplication).services.accountManager

Expand Down Expand Up @@ -100,6 +100,11 @@ class BookmarksStore constructor(val context: Context) {
listeners.clear()
}

internal fun updateStorage() {
storage = (context.applicationContext as VRBrowserApplication).places.bookmarks
notifyListeners()
}

fun getBookmarks(guid: String): CompletableFuture<List<BookmarkNode>?> = GlobalScope.future {
when (guid) {
BookmarkRoot.Mobile.id -> {
Expand Down Expand Up @@ -157,9 +162,7 @@ class BookmarksStore constructor(val context: Context) {

fun getTree(guid: String, recursive: Boolean): CompletableFuture<List<BookmarkNode>?> = GlobalScope.future {
storage.getTree(guid, recursive)?.children
?.map {
it.copy(title = titles[it.guid])
}
?.map { it.copy(title = titles[it.guid]) }
}

fun searchBookmarks(query: String, limit: Int): CompletableFuture<List<BookmarkNode>> = GlobalScope.future {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class HistoryStore constructor(val context: Context) {
private val LOGTAG = SystemUtils.createLogtag(HistoryStore::class.java)

private var listeners = ArrayList<HistoryListener>()
private val storage = (context.applicationContext as VRBrowserApplication).places.history
private var storage = (context.applicationContext as VRBrowserApplication).places.history

// Bookmarks might have changed during sync, so notify our listeners.
private val syncStatusObserver = object : SyncStatusObserver {
Expand Down Expand Up @@ -61,6 +61,11 @@ class HistoryStore constructor(val context: Context) {
listeners.clear()
}

internal fun updateStorage() {
storage = (context.applicationContext as VRBrowserApplication).places.history
notifyListeners()
}

fun getHistory(): CompletableFuture<List<String>?> = GlobalScope.future {
storage.getVisited()
}
Expand Down
37 changes: 34 additions & 3 deletions app/src/common/shared/org/mozilla/vrbrowser/browser/Places.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,42 @@ package org.mozilla.vrbrowser.browser
import android.content.Context
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.vrbrowser.browser.engine.SessionStore
import org.mozilla.vrbrowser.utils.SystemUtils

/**
* Entry point for interacting with places-backed storage layers.
*/
class Places(context: Context) {
val bookmarks by lazy { PlacesBookmarksStorage(context) }
val history by lazy { PlacesHistoryStorage(context) }
class Places(var context: Context) {

private val LOGTAG = SystemUtils.createLogtag(Places::class.java)

var bookmarks = PlacesBookmarksStorage(context)
var history = PlacesHistoryStorage(context)

fun clear() {
val files = context.filesDir.listFiles { dir, name ->
name.matches("places\\.sqlite.*".toRegex())
}
for (file in files) {
if (!file.delete()) {
Logger(LOGTAG).debug("Can't remove " + file.absolutePath)
}
}

bookmarks.cleanup()
// We create a new storage, otherwise we would need to restart the app so it's created in the Application onCreate
bookmarks = PlacesBookmarksStorage(context)
// Update the storage in the proxy class
SessionStore.get().bookmarkStore.updateStorage()

// We are supposed to call this but it fails internally as apparently the PlacesStorage is common
// and it's already being cleaned after bookmarks.cleanup()
// history.cleanup()
// We create a new storage, otherwise we would need to restart the app so it's created in the Application onCreate
history = PlacesHistoryStorage(context)
// Update the storage in the proxy class
SessionStore.get().historyStore.updateStorage()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.appservices.Megazord
import mozilla.components.concept.sync.*
import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
import mozilla.components.service.fxa.*
import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.sync.GlobalSyncableStoreProvider
Expand All @@ -32,8 +31,13 @@ import org.mozilla.vrbrowser.R
import org.mozilla.vrbrowser.browser.engine.EngineProvider
import org.mozilla.vrbrowser.browser.engine.GeckoViewFetchClient
import org.mozilla.vrbrowser.browser.engine.SessionStore
import org.mozilla.vrbrowser.utils.SystemUtils


class Services(val context: Context, places: Places): GeckoSession.NavigationDelegate {

private val LOGTAG = SystemUtils.createLogtag(Services::class.java)

class Services(context: Context, places: Places): GeckoSession.NavigationDelegate {
companion object {
const val CLIENT_ID = "7ad9917f6c55fb77"
const val REDIRECT_URL = "https://accounts.firefox.com/oauth/success/$CLIENT_ID"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ private static List<Bookmark> getDisplayListTree(@NonNull List<BookmarkNode> boo
for (BookmarkNode node : bookmarkNodes) {
if (node.getType() == BookmarkNodeType.FOLDER) {
if (openFolderGuid != null && openFolderGuid.contains(node.getGuid())) {
Bookmark bookmark = new Bookmark(node, level, true);
boolean canExpand = node.getChildren() != null && !node.getChildren().isEmpty();
Bookmark bookmark = new Bookmark(node, level, canExpand);
children.add(bookmark);
if (node.getChildren() != null) {
children.addAll(getDisplayListTree(node.getChildren(), level + 1, openFolderGuid));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import mozilla.components.service.fxa.sync.SyncReason;
import mozilla.components.service.fxa.sync.SyncStatusObserver;

import static org.mozilla.vrbrowser.browser.BookmarksStoreKt.DESKTOP_ROOT;

public class BookmarksView extends FrameLayout implements BookmarksStore.BookmarkListener {

private static final String LOGTAG = SystemUtils.createLogtag(BookmarksView.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* 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.vrbrowser.ui.widgets.dialogs;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.ViewTreeObserver;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.databinding.DataBindingUtil;

import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.databinding.CheckboxDialogBinding;
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;

public class CheckboxDialogWidget extends UIDialog {

public interface Delegate {
void onButtonClicked(int index);
default void onDismiss() {}
}

public static final int NEGATIVE = 0;
public static final int POSITIVE = 1;

protected CheckboxDialogBinding mBinding;
private Delegate mAppDialogDelegate;

public CheckboxDialogWidget(Context aContext) {
super(aContext);
initialize(aContext);
}

protected void initialize(Context aContext) {
LayoutInflater inflater = LayoutInflater.from(aContext);

// Inflate this data binding layout
mBinding = DataBindingUtil.inflate(inflater, R.layout.checkbox_dialog, this, true);

mBinding.leftButton.setOnClickListener(v -> {
if (mAppDialogDelegate != null) {
mAppDialogDelegate.onButtonClicked(NEGATIVE);
}
});
mBinding.rightButton.setOnClickListener(v -> {
if (mAppDialogDelegate != null) {
mAppDialogDelegate.onButtonClicked(POSITIVE);
}
});
}

@Override
protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.visible = false;
aPlacement.width = WidgetPlacement.dpDimension(getContext(), R.dimen.checkbox_dialog_width);
aPlacement.height = WidgetPlacement.dpDimension(getContext(), R.dimen.checkbox_dialog_height);
aPlacement.parentAnchorX = 0.5f;
aPlacement.parentAnchorY = 0.5f;
aPlacement.anchorX = 0.5f;
aPlacement.anchorY = 0.5f;
aPlacement.translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.base_app_dialog_z_distance);
}

@Override
public void show(@ShowFlags int aShowFlags) {
measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
super.show(aShowFlags);

mWidgetManager.pushWorldBrightness(this, WidgetManagerDelegate.DEFAULT_DIM_BRIGHTNESS);

ViewTreeObserver viewTreeObserver = getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
mWidgetPlacement.height = (int)(getHeight()/mWidgetPlacement.density);
mWidgetManager.updateWidget(CheckboxDialogWidget.this);
}
});
}
}

public void hide(@HideFlags int aHideFlags) {
super.hide(aHideFlags);
mWidgetManager.popWorldBrightness(this);
}

public void setButtonsDelegate(Delegate delegate) {
mAppDialogDelegate = delegate;
}

public void setIcon(Drawable icon) {
mBinding.icon.setImageDrawable(icon);
}

public void setIcon(@DrawableRes int icon) {
mBinding.icon.setImageResource(icon);
}

public void setTitle(@StringRes int title) {
mBinding.title.setText(title);
}

public void setTitle(String title) {
mBinding.title.setText(title);
}

public void setBody(String body) {
mBinding.body.setText(body);
}

public void setBody(@StringRes int title) {
mBinding.body.setText(title);
}

public void setCheckboxText(@StringRes int text) {
mBinding.checkbox.setText(text);
}

public void setCheckboxText(String text) {
mBinding.checkbox.setText(text);
}

public void setButtons(@NonNull @StringRes int[] buttons) {
if (buttons.length > 0) {
mBinding.leftButton.setText(buttons[NEGATIVE]);
}
if (buttons.length > 1) {
mBinding.rightButton.setText(buttons[POSITIVE]);
}
}

public void setButtons(@NonNull String[] buttons) {
if (buttons.length > 0) {
mBinding.leftButton.setText(buttons[NEGATIVE]);
}
if (buttons.length > 1) {
mBinding.rightButton.setText(buttons[POSITIVE]);
}
}

public boolean isChecked() {
return mBinding.checkbox.isChecked();
}

}
Loading