From e6f5e2b699c2504244f46282639d27a36d224d96 Mon Sep 17 00:00:00 2001 From: Manuel Martin Date: Tue, 26 Nov 2019 19:25:51 +0100 Subject: [PATCH] Sign-out dialog (#2374) --- .../org/mozilla/vrbrowser/browser/Accounts.kt | 47 +++++- .../vrbrowser/browser/BookmarksStore.kt | 11 +- .../mozilla/vrbrowser/browser/HistoryStore.kt | 7 +- .../org/mozilla/vrbrowser/browser/Places.kt | 37 ++++- .../org/mozilla/vrbrowser/browser/Services.kt | 8 +- .../vrbrowser/ui/adapters/Bookmark.java | 3 +- .../vrbrowser/ui/views/BookmarksView.java | 2 + .../widgets/dialogs/CheckboxDialogWidget.java | 155 ++++++++++++++++++ .../settings/FxAAccountOptionsView.java | 74 ++++++++- .../ui/widgets/settings/SettingsWidget.java | 20 +-- .../mozilla/vrbrowser/utils/ViewUtils.java | 29 ++++ .../main/res/layout/bookmark_item_folder.xml | 3 +- app/src/main/res/layout/checkbox_dialog.xml | 114 +++++++++++++ app/src/main/res/layout/honeycomb_button.xml | 2 +- app/src/main/res/layout/send_tabs_display.xml | 2 +- app/src/main/res/values/dimen.xml | 7 + app/src/main/res/values/strings.xml | 18 ++ 17 files changed, 499 insertions(+), 40 deletions(-) create mode 100644 app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/CheckboxDialogWidget.java create mode 100644 app/src/main/res/layout/checkbox_dialog.xml diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt index f3d393fa5..720c3fb33 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt @@ -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 @@ -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) @@ -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() @@ -152,6 +161,8 @@ class Accounts constructor(val context: Context) { it.onLoggedOut() } } + + loadDefaultProfilePicture() } override fun onProfileUpdated(profile: Profile) { @@ -162,6 +173,8 @@ class Accounts constructor(val context: Context) { it.onProfileUpdated(profile) } } + + loadProfilePicture(profile) } } @@ -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)) { @@ -271,7 +316,7 @@ class Accounts constructor(val context: Context) { return services.accountManager.accountProfile() } - fun logoutAsync(): CompletableFuture? { + fun logoutAsync(): CompletableFuture { otherDevices = emptyList() return CoroutineScope(Dispatchers.Main).future { services.accountManager.logoutAsync().await() diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/BookmarksStore.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/BookmarksStore.kt index 4fc9eaed2..cd24b9c7c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/BookmarksStore.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/BookmarksStore.kt @@ -59,7 +59,7 @@ class BookmarksStore constructor(val context: Context) { } private val listeners = ArrayList() - 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 @@ -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?> = GlobalScope.future { when (guid) { BookmarkRoot.Mobile.id -> { @@ -157,9 +162,7 @@ class BookmarksStore constructor(val context: Context) { fun getTree(guid: String, recursive: Boolean): CompletableFuture?> = 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> = GlobalScope.future { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/HistoryStore.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/HistoryStore.kt index c2f3584a4..ab151314a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/HistoryStore.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/HistoryStore.kt @@ -23,7 +23,7 @@ class HistoryStore constructor(val context: Context) { private val LOGTAG = SystemUtils.createLogtag(HistoryStore::class.java) private var listeners = ArrayList() - 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 { @@ -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?> = GlobalScope.future { storage.getVisited() } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/Places.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/Places.kt index fe6a6410c..7b00a9779 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/Places.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/Places.kt @@ -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() + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/Services.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/Services.kt index dc792cdf3..692bc17af 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/Services.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/Services.kt @@ -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 @@ -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" diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/Bookmark.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/Bookmark.java index 4c411499d..281ea2f13 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/Bookmark.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/Bookmark.java @@ -104,7 +104,8 @@ private static List getDisplayListTree(@NonNull List 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)); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/BookmarksView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/BookmarksView.java index fc3b18d28..4cd1f5069 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/BookmarksView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/BookmarksView.java @@ -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); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/CheckboxDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/CheckboxDialogWidget.java new file mode 100644 index 000000000..ec49cc85f --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/CheckboxDialogWidget.java @@ -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(); + } + +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/FxAAccountOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/FxAAccountOptionsView.java index 8123721b3..69fb5084d 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/FxAAccountOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/FxAAccountOptionsView.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets.settings; import android.content.Context; +import android.graphics.drawable.BitmapDrawable; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -17,10 +18,14 @@ import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.VRBrowserApplication; import org.mozilla.vrbrowser.browser.Accounts; +import org.mozilla.vrbrowser.browser.Places; import org.mozilla.vrbrowser.browser.SettingsStore; import org.mozilla.vrbrowser.databinding.OptionsFxaAccountBinding; import org.mozilla.vrbrowser.ui.views.settings.SwitchSetting; +import org.mozilla.vrbrowser.ui.widgets.UIWidget; import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate; +import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement; +import org.mozilla.vrbrowser.ui.widgets.dialogs.CheckboxDialogWidget; import org.mozilla.vrbrowser.utils.SystemUtils; import java.util.Objects; @@ -40,9 +45,11 @@ class FxAAccountOptionsView extends SettingsView { private OptionsFxaAccountBinding mBinding; private Accounts mAccounts; + private Places mPlaces; private Executor mUIThreadExecutor; private boolean mInitialBookmarksState; private boolean mInitialHistoryState; + private CheckboxDialogWidget mSignOutDialog; public FxAAccountOptionsView(Context aContext, WidgetManagerDelegate aWidgetManager) { super(aContext, aWidgetManager); @@ -61,10 +68,11 @@ private void initialize(Context aContext) { mBinding.headerLayout.setBackClickListener(view -> onDismiss()); mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); + mPlaces = ((VRBrowserApplication)getContext().getApplicationContext()).getPlaces(); mUIThreadExecutor = ((VRBrowserApplication)getContext().getApplicationContext()).getExecutors().mainThread(); - mBinding.signButton.setOnClickListener(view -> mAccounts.logoutAsync()); + mBinding.signButton.setOnClickListener(this::signOut); mBinding.syncButton.setOnClickListener(this::sync); mBinding.setIsSyncing(mAccounts.isSyncing()); @@ -165,13 +173,17 @@ void updateCurrentAccountState() { updateProfile(profile); } else { - Objects.requireNonNull(mAccounts.updateProfileAsync()). - thenAcceptAsync((u) -> updateProfile(mAccounts.accountProfile()), mUIThreadExecutor). - exceptionally(throwable -> { - Log.d(LOGTAG, "Error getting the account profile: " + throwable.getLocalizedMessage()); - throwable.printStackTrace(); - return null; - }); + try { + Objects.requireNonNull(mAccounts.updateProfileAsync()). + thenAcceptAsync((u) -> updateProfile(mAccounts.accountProfile()), mUIThreadExecutor). + exceptionally(throwable -> { + 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()); + } } break; @@ -197,6 +209,52 @@ private void sync(View view) { } else { mAccounts.syncNowAsync(SyncReason.User.INSTANCE, false); } + mAccounts.updateProfileAsync(); + } + + private void signOut(View view) { + if (mSignOutDialog == null) { + mSignOutDialog = new CheckboxDialogWidget(getContext()); + mSignOutDialog.getPlacement().parentHandle = mWidgetManager.getFocusedWindow().getHandle(); + mSignOutDialog.getPlacement().parentAnchorY = 0.0f; + mSignOutDialog.getPlacement().translationY = WidgetPlacement.unitFromMeters(getContext(), R.dimen.base_app_dialog_y_distance); + BitmapDrawable profilePicture = mAccounts.getProfilePicture(); + if (profilePicture != null) { + mSignOutDialog.setIcon(profilePicture); + + } else { + mSignOutDialog.setIcon(R.drawable.ic_icon_settings_account); + } + mSignOutDialog.setTitle(R.string.fxa_signout_confirmation_title); + mSignOutDialog.setBody(R.string.fxa_signout_confirmation_body); + mSignOutDialog.setCheckboxText(R.string.fxa_signout_confirmation_checkbox); + mSignOutDialog.setButtons(new int[] { + R.string.fxa_signout_confirmation_signout, + R.string.fxa_signout_confirmation_cancel + }); + mSignOutDialog.setButtonsDelegate(index -> { + // Sign out button pressed + if (index == CheckboxDialogWidget.NEGATIVE) { + mAccounts.logoutAsync().thenAcceptAsync(unit -> { + if (mSignOutDialog.isChecked()) { + // Clear History and Bookmarks + mPlaces.clear(); + } + mSignOutDialog.hide(UIWidget.REMOVE_WIDGET); + mWidgetManager.getTray().toggleSettingsDialog(); + + }, mUIThreadExecutor); + + } else if (index == CheckboxDialogWidget.POSITIVE) { + mSignOutDialog.hide(UIWidget.REMOVE_WIDGET); + mWidgetManager.getTray().toggleSettingsDialog(SettingsWidget.SettingDialog.FXA); + } + }); + mSignOutDialog.setDelegate(() -> mWidgetManager.getTray().toggleSettingsDialog(SettingsWidget.SettingDialog.FXA)); + } + + exitWholeSettings(); + mSignOutDialog.show(UIWidget.REQUEST_FOCUS); } private AccountObserver mAccountListener = new AccountObserver() { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsWidget.java index 20fdaab93..a8f380b35 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsWidget.java @@ -10,7 +10,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Point; -import android.graphics.drawable.Drawable; +import android.graphics.drawable.BitmapDrawable; import android.text.Html; import android.util.AttributeSet; import android.util.Log; @@ -25,7 +25,6 @@ import androidx.databinding.DataBindingUtil; import org.jetbrains.annotations.NotNull; -import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.geckoview.GeckoSessionSettings; import org.mozilla.vrbrowser.BuildConfig; import org.mozilla.vrbrowser.R; @@ -44,9 +43,7 @@ import org.mozilla.vrbrowser.ui.widgets.prompts.AlertPromptWidget; import org.mozilla.vrbrowser.utils.StringUtils; -import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.URL; import java.net.URLEncoder; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -354,18 +351,9 @@ public void onAuthenticationProblems() { }; private void updateProfile(Profile profile) { - if (profile != null) { - ThreadUtils.postToBackgroundThread(() -> { - try { - URL url = new URL(profile.getAvatar().getUrl()); - Drawable picture = Drawable.createFromStream(url.openStream(), "src"); - post(() -> mBinding.fxaButton.setImageDrawable(picture)); - - } catch (IOException e) { - e.printStackTrace(); - - } - }); + BitmapDrawable profilePicture = mAccounts.getProfilePicture(); + if (profile != null && profilePicture != null) { + mBinding.fxaButton.setImageDrawable(profilePicture); } else { mBinding.fxaButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_icon_settings_account)); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java index d4cb84f02..3e46a6e9a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java @@ -1,6 +1,13 @@ package org.mozilla.vrbrowser.utils; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; import android.os.Build; import android.text.Html; import android.text.Layout; @@ -213,4 +220,26 @@ public boolean onTouch(View view, MotionEvent event) { public static void setStickyClickListener(@NonNull View aView, View.OnClickListener aCallback) { aView.setOnTouchListener(new StickyClickListener(aCallback)); } + + @NonNull + public static Bitmap getRoundedCroppedBitmap(@NonNull Bitmap bitmap) { + int widthLight = bitmap.getWidth(); + int heightLight = bitmap.getHeight(); + + Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(output); + Paint paintColor = new Paint(); + paintColor.setFlags(Paint.ANTI_ALIAS_FLAG); + + RectF rectF = new RectF(new Rect(0, 0, widthLight, heightLight)); + + canvas.drawRoundRect(rectF, widthLight / 2 ,heightLight / 2,paintColor); + + Paint paintImage = new Paint(); + paintImage.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); + canvas.drawBitmap(bitmap, 0, 0, paintImage); + + return output; + } } diff --git a/app/src/main/res/layout/bookmark_item_folder.xml b/app/src/main/res/layout/bookmark_item_folder.xml index a71155538..a7fba4e48 100644 --- a/app/src/main/res/layout/bookmark_item_folder.xml +++ b/app/src/main/res/layout/bookmark_item_folder.xml @@ -41,7 +41,6 @@ android:duplicateParentState="true" android:drawableEnd="@{item.isExpanded ? @drawable/ic_baseline_arrow_drop_down_24px : @drawable/ic_baseline_arrow_drop_up_24px}" android:drawableTint="@color/fog" - android:drawablePadding="10dp" - visibleGone="@{item.hasChildren()}"/> + android:drawablePadding="10dp"/> diff --git a/app/src/main/res/layout/checkbox_dialog.xml b/app/src/main/res/layout/checkbox_dialog.xml new file mode 100644 index 000000000..e99523684 --- /dev/null +++ b/app/src/main/res/layout/checkbox_dialog.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + +