diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java index 707fb33e7..2c398cab8 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -35,6 +35,11 @@ import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.lifecycle.ViewModelStore; +import androidx.lifecycle.ViewModelStoreOwner; import org.mozilla.geckoview.GeckoRuntime; import org.mozilla.geckoview.GeckoSession; @@ -81,11 +86,12 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; +import java.util.Locale; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; -public class VRBrowserActivity extends PlatformActivity implements WidgetManagerDelegate, ComponentCallbacks2 { +public class VRBrowserActivity extends PlatformActivity implements WidgetManagerDelegate, ComponentCallbacks2, LifecycleOwner, ViewModelStoreOwner { private BroadcastReceiver mCrashReceiver = new BroadcastReceiver() { @Override @@ -97,6 +103,29 @@ public void onReceive(Context context, Intent intent) { } }; + private final LifecycleRegistry mLifeCycle; + + @NonNull + @Override + public Lifecycle getLifecycle() { + return mLifeCycle; + } + + private final ViewModelStore mViewModelStore; + + @NonNull + @Override + public ViewModelStore getViewModelStore() { + return mViewModelStore; + } + + public VRBrowserActivity() { + mLifeCycle = new LifecycleRegistry(this); + mLifeCycle.setCurrentState(Lifecycle.State.INITIALIZED); + + mViewModelStore = new ViewModelStore(); + } + class SwipeRunnable implements Runnable { boolean mCanceled = false; @Override @@ -269,6 +298,8 @@ protected void onCreate(Bundle savedInstanceState) { mConnectivityReceiver = new ConnectivityReceiver(); mPoorPerformanceWhiteList = new HashSet<>(); checkForCrash(); + + mLifeCycle.setCurrentState(Lifecycle.State.CREATED); } protected void initializeWidgets() { @@ -362,6 +393,7 @@ protected void onStart() { super.onStart(); TelemetryWrapper.start(); UISurfaceTextureRenderer.setRenderActive(true); + mLifeCycle.setCurrentState(Lifecycle.State.STARTED); } @Override @@ -423,6 +455,7 @@ protected void onResume() { ((VRBrowserApplication)getApplicationContext()).getAccounts().pollForEventsAsync(); super.onResume(); + mLifeCycle.setCurrentState(Lifecycle.State.RESUMED); } @Override @@ -455,6 +488,8 @@ protected void onDestroy() { super.onDestroy(); + mLifeCycle.setCurrentState(Lifecycle.State.DESTROYED); + mViewModelStore.clear(); } @Override @@ -473,6 +508,11 @@ protected void onNewIntent(final Intent intent) { @Override public void onConfigurationChanged(Configuration newConfig) { + getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics()); + + LocaleUtils.refresh(); + mWidgets.forEach((i, widget) -> widget.onConfigurationChanged(newConfig)); + SessionStore.get().onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig); @@ -502,7 +542,7 @@ void loadFromIntent(final Intent intent) { SettingsStore.getInstance(this).setHomepage(homepageUri.toString()); } - // Enable/Disbale e10s + // Enable/Disable e10s if (extras.containsKey("e10s")) { boolean wasEnabled = SettingsStore.getInstance(this).isMultiprocessEnabled(); boolean enabled = extras.getBoolean("e10s", wasEnabled); @@ -1445,7 +1485,7 @@ public boolean canOpenNewWindow() { @Override public void openNewWindow(String uri) { WindowWidget newWindow = mWindows.addWindow(); - if (newWindow != null) { + if ((newWindow != null) && (newWindow.getSession() != null)) { newWindow.getSession().loadUri(uri); } } @@ -1475,6 +1515,13 @@ public void saveState() { mWindows.saveState(); } + @Override + public void updateLocale(@NonNull Context context) { + Configuration configuration = context.getResources().getConfiguration(); + configuration.setLocale(Locale.forLanguageTag(LocaleUtils.getDisplayLanguage(this).getId())); + onConfigurationChanged(new Configuration(context.getResources().getConfiguration())); + } + private native void addWidgetNative(int aHandle, WidgetPlacement aPlacement); private native void updateWidgetNative(int aHandle, WidgetPlacement aPlacement); private native void updateVisibleWidgetsNative(); @@ -1483,7 +1530,7 @@ public void saveState() { private native void finishWidgetResizeNative(int aHandle); private native void startWidgetMoveNative(int aHandle, int aMoveBehaviour); private native void finishWidgetMoveNative(); - private native void setWorldBrightnessNative(float aBrigthness); + private native void setWorldBrightnessNative(float aBrightness); private native void setTemporaryFilePath(String aPath); private native void exitImmersiveNative(); private native void workaroundGeckoSigAction(); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java index bce32b3f7..f94cb5811 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java @@ -50,6 +50,7 @@ protected void attachBaseContext(Context base) { @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + LocaleUtils.setDisplayLocale(this, newConfig.getLocales().get(0).toLanguageTag()); LocaleUtils.setLocale(this); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java index 270abbb2d..1eebc6d14 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java @@ -144,6 +144,10 @@ public void onPlaybackStateChange(MediaElement mediaElement, int playbackState) mPlaying = false; } else if (playbackState == MediaElement.MEDIA_STATE_ENDED) { mEnded = true; + } else if (playbackState == MediaElement.MEDIA_STATE_EMPTIED) { + mEnded = true; + mPlaying = false; + mIsUnloaded = true; } mMediaListeners.forEach(listener -> listener.onPlaybackStateChange(mediaElement, playbackState)); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java index d42062be5..8d69e5cbb 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java @@ -382,6 +382,8 @@ private void showPopUp(int sessionId, @NonNull Pair mExecutors.mainThread().execute(() -> { if (mPopupDelegate != null) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java index d8ca3003d..15c720282 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java @@ -43,6 +43,7 @@ import org.mozilla.vrbrowser.utils.BitmapCache; import org.mozilla.vrbrowser.utils.InternalPages; import org.mozilla.vrbrowser.utils.SystemUtils; +import org.mozilla.vrbrowser.utils.UrlUtils; import java.net.URI; import java.net.URISyntaxException; @@ -569,9 +570,7 @@ public String getHomeUri() { } public Boolean isHomeUri(String aUri) { - return aUri != null && aUri.toLowerCase().startsWith( - SettingsStore.getInstance(mContext).getHomepage() - ); + return UrlUtils.isHomeUri(mContext, aUri); } public String getCurrentUri() { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java b/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java index 947185677..03aed88c5 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java @@ -95,7 +95,10 @@ public void registerForUpdates() { public void unregisterForUpdates() { if (mContext != null) { - mContext.unregisterReceiver(mLocaleChangedReceiver); + try { + mContext.unregisterReceiver(mLocaleChangedReceiver); + + } catch(IllegalArgumentException ignored) {} if (mPrefs != null) { mPrefs.unregisterOnSharedPreferenceChangeListener(this); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BindingAdapters.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BindingAdapters.java index e21454ee7..85d4c785c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BindingAdapters.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BindingAdapters.java @@ -10,15 +10,14 @@ import android.widget.ImageView; import android.widget.TextView; -import androidx.annotation.DimenRes; import androidx.annotation.Dimension; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.databinding.BindingAdapter; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.ui.views.HoneycombButton; import org.mozilla.vrbrowser.ui.views.UIButton; +import org.mozilla.vrbrowser.ui.views.UITextButton; import org.mozilla.vrbrowser.ui.views.settings.ButtonSetting; import org.mozilla.vrbrowser.ui.views.settings.SwitchSetting; @@ -154,4 +153,15 @@ public static void setLayoutWidth(@NonNull ImageView view, @NonNull @Dimension f params.height = (int)dimen; view.setLayoutParams(params); } -} \ No newline at end of file + + @BindingAdapter("privateMode") + public static void setPrivateMode(@NonNull UIButton button, boolean isPrivateMode) { + button.setPrivateMode(isPrivateMode); + } + + @BindingAdapter("privateMode") + public static void setPrivateMode(@NonNull UITextButton button, boolean isPrivateMode) { + button.setPrivateMode(isPrivateMode); + } + + } \ No newline at end of file diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java new file mode 100644 index 000000000..523e16ddf --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java @@ -0,0 +1,661 @@ +package org.mozilla.vrbrowser.ui.viewmodel; + +import android.app.Application; +import android.content.res.Resources; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.util.TypedValue; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.MediatorLiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; + +import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserApplication; +import org.mozilla.vrbrowser.browser.SettingsStore; +import org.mozilla.vrbrowser.browser.engine.SessionStore; +import org.mozilla.vrbrowser.ui.widgets.Windows; +import org.mozilla.vrbrowser.utils.ServoUtils; +import org.mozilla.vrbrowser.utils.StringUtils; +import org.mozilla.vrbrowser.utils.UrlUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.concurrent.Executor; + +public class WindowViewModel extends AndroidViewModel { + + private Executor mUIThreadExecutor; + + private int mURLProtocolColor; + private int mURLWebsiteColor; + + private MutableLiveData url; + private MutableLiveData hint; + private MutableLiveData isWindowVisible; + private MutableLiveData placement; + private MutableLiveData isOnlyWindow; + private MutableLiveData isFullscreen; + private MediatorLiveData isTopBarVisible; + private MutableLiveData isResizeMode; + private MutableLiveData isPrivateSession; + private MediatorLiveData showClearButton; + private MutableLiveData isInsecure; + private MutableLiveData isActiveWindow; + private MediatorLiveData isTitleBarVisible; + private MutableLiveData isBookmarksVisible; + private MutableLiveData isHistoryVisible; + private MediatorLiveData isLibraryVisible; + private MutableLiveData isLoading; + private MutableLiveData isMicrophoneEnabled; + private MutableLiveData isBookmarked; + private MutableLiveData isFocused; + private MutableLiveData isSpecialUrl; + private MutableLiveData isUrlEmpty; + private MutableLiveData isPopUpAvailable; + private MutableLiveData canGoForward; + private MutableLiveData canGoBack; + private MutableLiveData isInVRVideo; + private MutableLiveData autoEnteredVRVideo; + private MediatorLiveData isServoAvailable; + private MediatorLiveData titleBarUrl; + private MediatorLiveData isInsecureVisible; + private MutableLiveData isMediaAvailable; + private MutableLiveData isMediaPlaying; + private MediatorLiveData navigationBarUrl; + + + public WindowViewModel(Application application) { + super(application); + + mUIThreadExecutor = ((VRBrowserApplication)application).getExecutors().mainThread(); + + TypedValue typedValue = new TypedValue(); + Resources.Theme theme = application.getTheme(); + theme.resolveAttribute(R.attr.urlProtocolColor, typedValue, true); + mURLProtocolColor = typedValue.data; + theme.resolveAttribute(R.attr.urlWebsiteColor, typedValue, true); + mURLWebsiteColor = typedValue.data; + + url = new MutableLiveData<>(new SpannableString("")); + hint = new MutableLiveData<>(""); + isWindowVisible = new MutableLiveData<>(new ObservableBoolean(true)); + placement = new MutableLiveData<>(Windows.WindowPlacement.FRONT); + isOnlyWindow = new MutableLiveData<>(new ObservableBoolean(false)); + isFullscreen = new MutableLiveData<>(new ObservableBoolean(false)); + isResizeMode = new MutableLiveData<>(new ObservableBoolean(false)); + isPrivateSession = new MutableLiveData<>(new ObservableBoolean(false)); + + isTopBarVisible = new MediatorLiveData<>(); + isTopBarVisible.addSource(isOnlyWindow, mIsTopBarVisibleObserver); + isTopBarVisible.addSource(isFullscreen, mIsTopBarVisibleObserver); + isTopBarVisible.addSource(isResizeMode, mIsTopBarVisibleObserver); + isTopBarVisible.addSource(isPrivateSession, mIsTopBarVisibleObserver); + isTopBarVisible.addSource(isWindowVisible, mIsTopBarVisibleObserver); + isTopBarVisible.setValue(new ObservableBoolean(false)); + + showClearButton = new MediatorLiveData<>(); + showClearButton.addSource(isOnlyWindow, mShowClearButtonObserver); + showClearButton.addSource(isPrivateSession, mShowClearButtonObserver); + showClearButton.addSource(isResizeMode, mShowClearButtonObserver); + showClearButton.addSource(isFullscreen, mShowClearButtonObserver); + showClearButton.addSource(isWindowVisible, mShowClearButtonObserver); + showClearButton.setValue(new ObservableBoolean(false)); + + isInsecure = new MutableLiveData<>(new ObservableBoolean(false)); + isActiveWindow = new MutableLiveData<>(new ObservableBoolean(false)); + + isTitleBarVisible = new MediatorLiveData<>(); + isTitleBarVisible.addSource(isFullscreen, mIsTitleBarVisibleObserver); + isTitleBarVisible.addSource(isResizeMode, mIsTitleBarVisibleObserver); + isTitleBarVisible.addSource(isActiveWindow, mIsTitleBarVisibleObserver); + isTitleBarVisible.addSource(isWindowVisible, mIsTitleBarVisibleObserver); + isTitleBarVisible.addSource(isOnlyWindow, mIsTitleBarVisibleObserver); + isTitleBarVisible.setValue(new ObservableBoolean(false)); + + isBookmarksVisible = new MutableLiveData<>(new ObservableBoolean(false)); + isHistoryVisible = new MutableLiveData<>(new ObservableBoolean(false)); + + isLibraryVisible = new MediatorLiveData<>(); + isLibraryVisible.addSource(isBookmarksVisible, mIsLibraryVisibleObserver); + isLibraryVisible.addSource(isHistoryVisible, mIsLibraryVisibleObserver); + isLibraryVisible.setValue(new ObservableBoolean(false)); + + isLoading = new MutableLiveData<>(new ObservableBoolean(false)); + isMicrophoneEnabled = new MutableLiveData<>(new ObservableBoolean(true)); + isBookmarked = new MutableLiveData<>(new ObservableBoolean(false)); + isFocused = new MutableLiveData<>(new ObservableBoolean(false)); + isSpecialUrl = new MutableLiveData<>(new ObservableBoolean(false)); + isUrlEmpty = new MutableLiveData<>(new ObservableBoolean(false)); + isPopUpAvailable = new MutableLiveData<>(new ObservableBoolean(false)); + canGoForward = new MutableLiveData<>(new ObservableBoolean(false)); + canGoBack = new MutableLiveData<>(new ObservableBoolean(false)); + isInVRVideo = new MutableLiveData<>(new ObservableBoolean(false)); + autoEnteredVRVideo = new MutableLiveData<>(new ObservableBoolean(false)); + + isServoAvailable = new MediatorLiveData<>(); + isServoAvailable.addSource(url, mIsServoAvailableObserver); + isServoAvailable.setValue(new ObservableBoolean(false)); + + titleBarUrl = new MediatorLiveData<>(); + titleBarUrl.addSource(url, mTitleBarUrlObserver); + titleBarUrl.setValue(""); + + isInsecureVisible = new MediatorLiveData<>(); + isInsecureVisible.addSource(isInsecure, mIsInsecureVisibleObserver); + isInsecureVisible.addSource(isPrivateSession, mIsInsecureVisibleObserver); + isInsecureVisible.addSource(isLibraryVisible, mIsInsecureVisibleObserver); + isInsecureVisible.setValue(new ObservableBoolean(false)); + + isMediaAvailable = new MutableLiveData<>(new ObservableBoolean(false)); + isMediaPlaying = new MutableLiveData<>(new ObservableBoolean(false)); + + navigationBarUrl = new MediatorLiveData<>(); + navigationBarUrl.addSource(url, mNavigationBarUrlObserver); + navigationBarUrl.setValue(""); + } + + private Observer mIsTopBarVisibleObserver = new Observer() { + @Override + public void onChanged(ObservableBoolean o) { + if (isFullscreen.getValue().get() || isResizeMode.getValue().get()) { + isTopBarVisible.setValue(new ObservableBoolean(false)); + + } else if (isPrivateSession.getValue().get() && isOnlyWindow.getValue().get()) { + isTopBarVisible.setValue(new ObservableBoolean(true)); + + } else { + isTopBarVisible.setValue(new ObservableBoolean(isWindowVisible.getValue().get() && !isOnlyWindow.getValue().get())); + } + } + }; + + private Observer mShowClearButtonObserver = new Observer() { + @Override + public void onChanged(ObservableBoolean o) { + showClearButton.setValue(new ObservableBoolean(isWindowVisible.getValue().get() && + isPrivateSession.getValue().get() && isOnlyWindow.getValue().get() && + !isResizeMode.getValue().get() && !isFullscreen.getValue().get())); + } + }; + + private Observer mIsTitleBarVisibleObserver = new Observer() { + @Override + public void onChanged(ObservableBoolean o) { + if (isFullscreen.getValue().get() || isResizeMode.getValue().get() || isActiveWindow.getValue().get()) { + isTitleBarVisible.setValue(new ObservableBoolean(false)); + + } else { + isTitleBarVisible.setValue(new ObservableBoolean(isWindowVisible.getValue().get() && !isOnlyWindow.getValue().get())); + } + } + }; + + private Observer mIsLibraryVisibleObserver = new Observer() { + @Override + public void onChanged(ObservableBoolean o) { + isLibraryVisible.setValue(new ObservableBoolean(isBookmarksVisible.getValue().get() || isHistoryVisible.getValue().get())); + + // We use this to force dispatch a title bar and navigation bar URL refresh when library is opened + url.setValue(url.getValue()); + } + }; + + private Observer mIsServoAvailableObserver = new Observer() { + @Override + public void onChanged(Spannable url) { + boolean isPrefEnabled = SettingsStore.getInstance(getApplication()).isServoEnabled(); + boolean isUrlWhiteListed = ServoUtils.isUrlInServoWhiteList(getApplication(), url.toString()); + isServoAvailable.postValue(new ObservableBoolean(isPrefEnabled && isUrlWhiteListed)); + } + }; + + private Observer mTitleBarUrlObserver = new Observer() { + @Override + public void onChanged(Spannable aUrl) { + String url = aUrl.toString(); + if (isBookmarksVisible.getValue().get()) { + url = getApplication().getString(R.string.url_bookmarks_title); + + } else if (isHistoryVisible.getValue().get()) { + url = getApplication().getString(R.string.url_history_title); + + } else { + if (UrlUtils.isPrivateAboutPage(getApplication(), url) || + (UrlUtils.isDataUri(url) && isPrivateSession.getValue().get())) { + url = getApplication().getString(R.string.private_browsing_title); + + } else if (UrlUtils.isHomeUri(getApplication(), aUrl.toString())) { + url = getApplication().getString(R.string.url_home_title, getApplication().getString(R.string.app_name)); + + } else if (UrlUtils.isBlankUri(getApplication(), aUrl.toString())) { + url = ""; + } + } + + titleBarUrl.setValue(UrlUtils.titleBarUrl(url)); + } + }; + + private Observer mIsInsecureVisibleObserver = new Observer() { + @Override + public void onChanged(ObservableBoolean o) { + String aUrl = url.getValue().toString(); + if (isInsecure.getValue().get()) { + if (UrlUtils.isPrivateAboutPage(getApplication(), aUrl) || + (UrlUtils.isDataUri(aUrl) && isPrivateSession.getValue().get()) || + UrlUtils.isHomeUri(getApplication(), aUrl) || + isLibraryVisible.getValue().get() || + UrlUtils.isBlankUri(getApplication(), aUrl)) { + isInsecureVisible.setValue(new ObservableBoolean(false)); + + } else { + isInsecureVisible.setValue(new ObservableBoolean(true)); + } + + } else { + isInsecureVisible.setValue(new ObservableBoolean(false)); + } + } + }; + + private Observer mNavigationBarUrlObserver = new Observer() { + @Override + public void onChanged(Spannable aUrl) { + String url = aUrl.toString(); + if (UrlUtils.isPrivateAboutPage(getApplication(), url) || + (UrlUtils.isDataUri(url) && isPrivateSession.getValue().get()) || + UrlUtils.isHomeUri(getApplication(), aUrl.toString()) || + isLibraryVisible.getValue().get() || + UrlUtils.isBlankUri(getApplication(), aUrl.toString())) { + navigationBarUrl.setValue(""); + + } else { + navigationBarUrl.setValue(UrlUtils.titleBarUrl(url)); + } + + if (isBookmarksVisible.getValue().get()) { + hint.setValue(getApplication().getString(R.string.url_bookmarks_title)); + + } else if (isHistoryVisible.getValue().get()) { + hint.setValue(getApplication().getString(R.string.url_history_title)); + + } else { + hint.setValue(getApplication().getString(R.string.search_placeholder)); + } + } + }; + + public void refresh() { + url.postValue(url.getValue()); + isWindowVisible.postValue(isWindowVisible.getValue()); + placement.postValue(placement.getValue()); + isOnlyWindow.postValue(isOnlyWindow.getValue()); + isFullscreen.postValue(isFullscreen.getValue()); + isResizeMode.postValue(isResizeMode.getValue()); + isPrivateSession.postValue(isPrivateSession.getValue()); + isInsecure.postValue(isInsecure.getValue()); + isLoading.postValue(isLoading.getValue()); + isMicrophoneEnabled.postValue(isMicrophoneEnabled.getValue()); + isBookmarked.postValue(isBookmarked.getValue()); + isFocused.postValue(isFocused.getValue()); + isSpecialUrl.postValue(isSpecialUrl.getValue()); + isUrlEmpty.postValue(isUrlEmpty.getValue()); + isPopUpAvailable.postValue(isPopUpAvailable.getValue()); + canGoForward.postValue(canGoForward.getValue()); + canGoBack.postValue(canGoBack.getValue()); + isInVRVideo.postValue(isInVRVideo.getValue()); + autoEnteredVRVideo.postValue(autoEnteredVRVideo.getValue()); + isMediaAvailable.postValue(isMediaAvailable.getValue()); + isMediaPlaying.postValue(isMediaPlaying.getValue()); + } + + @NonNull + public MutableLiveData getUrl() { + if (url == null) { + url = new MutableLiveData<>(new SpannableString("")); + } + return url; + } + + public void setUrl(@Nullable String url) { + if (url != null) { + this.url.setValue(new SpannableString(url)); + } + } + + public void setUrl(@Nullable Spannable url) { + if (url == null) { + return; + } + + String aURL = url.toString(); + + if (isLibraryVisible.getValue().get()) { + return; + } + + if (StringUtils.isEmpty(aURL)) { + setIsBookmarked(false); + + } else { + SessionStore.get().getBookmarkStore().isBookmarked(aURL).thenAcceptAsync(this::setIsBookmarked, mUIThreadExecutor).exceptionally(throwable -> { + throwable.printStackTrace(); + return null; + }); + } + + int index = -1; + try { + aURL = URLDecoder.decode(aURL, "UTF-8"); + + } catch (UnsupportedEncodingException | IllegalArgumentException e) { + e.printStackTrace(); + aURL = ""; + } + if (aURL.startsWith("jar:")) { + return; + + } else if (aURL.startsWith("resource:") || UrlUtils.isHomeUri(getApplication().getBaseContext(), aURL)) { + aURL = ""; + + } else if (aURL.startsWith("data:") && isPrivateSession.getValue().get()) { + aURL = ""; + + } else if (aURL.startsWith(getApplication().getBaseContext().getString(R.string.about_blank))) { + aURL = ""; + + } else { + index = aURL.indexOf("://"); + } + + // Update the URL bar only if the URL is different than the current one and + // the URL bar is not focused to avoid override user input + if (!getUrl().getValue().toString().equalsIgnoreCase(aURL) && !getIsFocused().getValue().get()) { + this.url.setValue(new SpannableString(aURL)); + if (index > 0) { + SpannableString spannable = new SpannableString(aURL); + ForegroundColorSpan color1 = new ForegroundColorSpan(mURLProtocolColor); + ForegroundColorSpan color2 = new ForegroundColorSpan(mURLWebsiteColor); + spannable.setSpan(color1, 0, index + 3, 0); + spannable.setSpan(color2, index + 3, aURL.length(), 0); + this.url.setValue(url); + + } else { + this.url.setValue(url); + } + } + + setIsSpecialUrl(aURL.isEmpty()); + + this.url.setValue(url); + } + + @NonNull + public MutableLiveData getHint() { + if (hint == null) { + hint = new MutableLiveData<>(""); + } + return hint; + } + + @NonNull + public MutableLiveData getIsWindowVisible() { + return isWindowVisible; + } + + public void setIsWindowVisible(boolean isWindowVisible) { + this.isWindowVisible.postValue(new ObservableBoolean(isWindowVisible)); + } + + @NonNull + public MutableLiveData getPlacement() { + return placement; + } + + public void setPlacement(Windows.WindowPlacement placement) { + this.placement.postValue(placement); + } + + @NonNull + public MutableLiveData getIsOnlyWindow() { + return isOnlyWindow; + } + + public void setIsOnlyWindow(boolean isOnlyWindow) { + this.isOnlyWindow.postValue(new ObservableBoolean(isOnlyWindow)); + } + + @NonNull + public MutableLiveData getIsFullscreen() { + return isFullscreen; + } + + public void setIsFullscreen(boolean isFullscreen) { + this.isFullscreen.postValue(new ObservableBoolean(isFullscreen)); + } + + @NonNull + public MediatorLiveData getIsTopBarVisible() { + return isTopBarVisible; + } + + public void setIsTopBarVisible(boolean isTopBarVisible) { + this.isTopBarVisible.postValue(new ObservableBoolean(isTopBarVisible)); + } + + @NonNull + public MutableLiveData getIsResizeMode() { + return isResizeMode; + } + + public void setIsResizeMode(boolean isResizeMode) { + this.isResizeMode.postValue(new ObservableBoolean(isResizeMode)); + } + + @NonNull + public MutableLiveData getIsPrivateSession() { + return isPrivateSession; + } + + public void setIsPrivateSession(boolean isPrivateSession) { + this.isPrivateSession.postValue(new ObservableBoolean(isPrivateSession)); + } + + @NonNull + public MutableLiveData getShowClearButton() { + return showClearButton; + } + + @NonNull + public MutableLiveData getIsInsecure() { + return isInsecure; + } + + public void setIsInsecure(boolean isInsecure) { + this.isInsecure.postValue(new ObservableBoolean(isInsecure)); + } + + @NonNull + public MediatorLiveData getIsTitleBarVisible() { + return isTitleBarVisible; + } + + public void setIsTitleBarVisible(boolean isTitleBarVisible) { + this.isTitleBarVisible.postValue(new ObservableBoolean(isTitleBarVisible)); + } + + @NonNull + public MutableLiveData getIsActiveWindow() { + return isActiveWindow; + } + + public void setIsActiveWindow(boolean isActiveWindow) { + this.isActiveWindow.postValue(new ObservableBoolean(isActiveWindow)); + } + + @NonNull + public MutableLiveData getIsBookmraksVisible() { + return isBookmarksVisible; + } + + public void setIsBookmarksVisible(boolean isBookmarksVisible) { + this.isBookmarksVisible.postValue(new ObservableBoolean(isBookmarksVisible)); + } + + @NonNull + public MutableLiveData getIsHistoryVisible() { + return isHistoryVisible; + } + + public void setIsHistoryVisible(boolean isHistoryVisible) { + this.isHistoryVisible.postValue(new ObservableBoolean(isHistoryVisible)); + } + + @NonNull + public MutableLiveData getIsLibraryVisible() { + return isLibraryVisible; + } + + @NonNull + public MutableLiveData getIsLoading() { + return isLoading; + } + + public void setIsLoading(boolean isLoading) { + this.isLoading.postValue(new ObservableBoolean(isLoading)); + } + + @NonNull + public MutableLiveData getIsMicrophoneEnabled() { + return isMicrophoneEnabled; + } + + public void setIsMicrophoneEnabled(boolean isMicrophoneEnabled) { + this.isMicrophoneEnabled.postValue(new ObservableBoolean(isMicrophoneEnabled)); + } + + @NonNull + public MutableLiveData getIsBookmarked() { + return isBookmarked; + } + + public void setIsBookmarked(boolean isBookmarked) { + this.isBookmarked.setValue(new ObservableBoolean(isBookmarked)); + } + + @NonNull + public MutableLiveData getIsFocused() { + return isFocused; + } + + public void setIsFocused(boolean isFocused) { + this.isFocused.postValue(new ObservableBoolean(isFocused)); + } + + @NonNull + public MutableLiveData getIsSpecialUrl() { + return isSpecialUrl; + } + + public void setIsSpecialUrl(boolean isSpecialUrl) { + this.isSpecialUrl.postValue(new ObservableBoolean(isSpecialUrl)); + } + + @NonNull + public MutableLiveData getIsUrlEmpty() { + return isUrlEmpty; + } + + public void setIsUrlEmpty(boolean isUrlEmpty) { + this.isUrlEmpty.postValue(new ObservableBoolean(isUrlEmpty)); + } + + @NonNull + public MutableLiveData getIsPopUpAvailable() { + return isPopUpAvailable; + } + + public void setIsPopUpAvailable(boolean isPopUpAvailable) { + this.isPopUpAvailable.postValue(new ObservableBoolean(isPopUpAvailable)); + } + + @NonNull + public MutableLiveData getCanGoForward() { + return canGoForward; + } + + public void setCanGoForward(boolean canGoForward) { + this.canGoForward.postValue(new ObservableBoolean(canGoForward)); + } + + @NonNull + public MutableLiveData getCanGoBack() { + return canGoBack; + } + + public void setCanGoBack(boolean canGoBack) { + this.canGoBack.postValue(new ObservableBoolean(canGoBack)); + } + + @NonNull + public MutableLiveData getIsInVRVideo() { + return isInVRVideo; + } + + public void setIsInVRVideo(boolean isInVRVideo) { + this.isInVRVideo.postValue(new ObservableBoolean(isInVRVideo)); + } + + @NonNull + public MutableLiveData getAutoEnteredVRVideo() { + return autoEnteredVRVideo; + } + + public void setAutoEnteredVRVideo(boolean autoEnteredVRVideo) { + this.autoEnteredVRVideo.postValue(new ObservableBoolean(autoEnteredVRVideo)); + } + + @NonNull + public MutableLiveData getIsServoAvailable() { + return isServoAvailable; + } + + @NonNull + public MediatorLiveData getTitleBarUrl() { + return titleBarUrl; + } + + @NonNull + public MediatorLiveData getIsInsecureVisible() { + return isInsecureVisible; + } + + @NonNull + public MutableLiveData getIsMediaAvailable() { + return isMediaAvailable; + } + + public void setIsMediaAvailable(boolean isMediaAvailable) { + this.isMediaAvailable.postValue(new ObservableBoolean(isMediaAvailable)); + } + + @NonNull + public MutableLiveData getIsMediaPlaying() { + return isMediaPlaying; + } + + public void setIsMediaPlaying(boolean isMediaPlaying) { + this.isMediaPlaying.postValue(new ObservableBoolean(isMediaPlaying)); + } + + @NonNull + public MutableLiveData getNavigationBarUrl() { + return navigationBarUrl; + } +} 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 cd82489b6..d5eea7517 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 @@ -81,18 +81,33 @@ public BookmarksView(Context aContext, AttributeSet aAttrs, int aDefStyle) { initialize(aContext); } - @SuppressLint("ClickableViewAccessibility") private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); - mUIThreadExecutor = ((VRBrowserApplication)getContext().getApplicationContext()).getExecutors().mainThread(); mBookmarksViewListeners = new ArrayList<>(); + mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); + if (ACCOUNTS_UI_ENABLED) { + mAccounts.addAccountListener(mAccountListener); + mAccounts.addSyncListener(mSyncListener); + } + + SessionStore.get().getBookmarkStore().addListener(this); + + updateUI(); + } + + @SuppressLint("ClickableViewAccessibility") + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.bookmarks, this, true); + mBinding.setCallback(mBookmarksCallback); - mBookmarkAdapter = new BookmarkAdapter(mBookmarkItemCallback, aContext); + mBookmarkAdapter = new BookmarkAdapter(mBookmarkItemCallback, getContext()); mBinding.bookmarksList.setAdapter(mBookmarkAdapter); mBinding.bookmarksList.setOnTouchListener((v, event) -> { v.requestFocusFromTouch(); @@ -108,12 +123,6 @@ private void initialize(Context aContext) { mBinding.setIsLoading(true); - mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); - if (ACCOUNTS_UI_ENABLED) { - mAccounts.addAccountListener(mAccountListener); - mAccounts.addSyncListener(mSyncListener); - } - mBinding.setIsSignedIn(mAccounts.isSignedIn()); boolean isSyncEnabled = mAccounts.isEngineEnabled(SyncEngine.Bookmarks.INSTANCE); mBinding.setIsSyncEnabled(isSyncEnabled); @@ -126,7 +135,6 @@ private void initialize(Context aContext) { mBinding.executePendingBindings(); updateBookmarks(); - SessionStore.get().getBookmarkStore().addListener(this); setVisibility(GONE); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HistoryView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HistoryView.java index c94ce2445..938f8507e 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HistoryView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HistoryView.java @@ -86,18 +86,32 @@ public HistoryView(Context aContext, AttributeSet aAttrs, int aDefStyle) { initialize(aContext); } - @SuppressLint("ClickableViewAccessibility") private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); - mUIThreadExecutor = ((VRBrowserApplication)getContext().getApplicationContext()).getExecutors().mainThread(); mHistoryViewListeners = new ArrayList<>(); + mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); + if (ACCOUNTS_UI_ENABLED) { + mAccounts.addAccountListener(mAccountListener); + mAccounts.addSyncListener(mSyncListener); + } + + SessionStore.get().getHistoryStore().addListener(this); + + updateUI(); + } + + @SuppressLint("ClickableViewAccessibility") + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.history, this, true); mBinding.setCallback(mHistoryCallback); - mHistoryAdapter = new HistoryAdapter(mHistoryItemCallback, aContext); + mHistoryAdapter = new HistoryAdapter(mHistoryItemCallback, getContext()); mBinding.historyList.setAdapter(mHistoryAdapter); mBinding.historyList.setOnTouchListener((v, event) -> { v.requestFocusFromTouch(); @@ -111,12 +125,6 @@ private void initialize(Context aContext) { mBinding.setIsLoading(true); - mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); - if (ACCOUNTS_UI_ENABLED) { - mAccounts.addAccountListener(mAccountListener); - mAccounts.addSyncListener(mSyncListener); - } - mBinding.setIsSignedIn(mAccounts.isSignedIn()); boolean isSyncEnabled = mAccounts.isEngineEnabled(SyncEngine.History.INSTANCE); mBinding.setIsSyncEnabled(isSyncEnabled); @@ -129,7 +137,6 @@ private void initialize(Context aContext) { mBinding.executePendingBindings(); updateHistory(); - SessionStore.get().getHistoryStore().addListener(this); setVisibility(GONE); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java index 9f2b50a97..cb6d81c0d 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java @@ -9,14 +9,10 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.content.res.Resources; import android.text.Editable; -import android.text.SpannableString; import android.text.TextWatcher; -import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; import android.util.Log; -import android.util.TypedValue; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -27,11 +23,14 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; -import androidx.annotation.StringRes; import androidx.databinding.DataBindingUtil; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; import org.mozilla.geckoview.GeckoSession; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserActivity; import org.mozilla.vrbrowser.VRBrowserApplication; import org.mozilla.vrbrowser.audio.AudioEngine; import org.mozilla.vrbrowser.browser.BookmarksStore; @@ -41,17 +40,17 @@ import org.mozilla.vrbrowser.search.SearchEngineWrapper; import org.mozilla.vrbrowser.telemetry.GleanMetricsService; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; +import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel; import org.mozilla.vrbrowser.ui.widgets.UIWidget; +import org.mozilla.vrbrowser.ui.widgets.WindowWidget; import org.mozilla.vrbrowser.ui.widgets.dialogs.SelectionActionWidget; import org.mozilla.vrbrowser.utils.StringUtils; import org.mozilla.vrbrowser.utils.SystemUtils; import org.mozilla.vrbrowser.utils.UrlUtils; import org.mozilla.vrbrowser.utils.ViewUtils; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URL; -import java.net.URLDecoder; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.Executor; @@ -65,10 +64,9 @@ public class NavigationURLBar extends FrameLayout { private static final String LOGTAG = SystemUtils.createLogtag(NavigationURLBar.class); + private WindowViewModel mViewModel; private NavigationUrlBinding mBinding; private Animation mLoadingAnimation; - private int mURLProtocolColor; - private int mURLWebsiteColor; private NavigationURLBarDelegate mDelegate; private ShippedDomainsProvider mAutocompleteProvider; private AudioEngine mAudio; @@ -116,14 +114,15 @@ private void initialize(Context aContext) { mSession = SessionStore.get().getActiveSession(); - LayoutInflater inflater = LayoutInflater.from(aContext); + mLoadingAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.loading); - // Inflate this data binding layout - mBinding = DataBindingUtil.inflate(inflater, R.layout.navigation_url, this, true); + // Layout setup + mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.navigation_url, this, true); + mBinding.setLifecycleOwner((VRBrowserActivity)getContext()); // Use Domain autocomplete provider from components mAutocompleteProvider = new ShippedDomainsProvider(); - mAutocompleteProvider.initialize(aContext); + mAutocompleteProvider.initialize(getContext()); mBinding.urlEditText.clearFocus(); mBinding.urlEditText.setShowSoftInputOnFocus(false); @@ -138,9 +137,9 @@ private void initialize(Context aContext) { mBinding.urlEditText.setOnFocusChangeListener((view, focused) -> { boolean isUrlEmpty = mBinding.urlEditText.getText().length() == 0; - setMicrophoneEnabled(!focused || isUrlEmpty); - mBinding.setIsFocused(focused); - mBinding.setIsUrlEmpty(isUrlEmpty); + mViewModel.setIsMicrophoneEnabled(!focused || isUrlEmpty); + mViewModel.setIsFocused(focused); + mViewModel.setIsUrlEmpty(isUrlEmpty); if (!focused) { hideSelectionMenu(); } else { @@ -231,47 +230,49 @@ private void initialize(Context aContext) { mBinding.popup.setOnClickListener(mPopUpListener); - mLoadingAnimation = AnimationUtils.loadAnimation(aContext, R.anim.loading); - - TypedValue typedValue = new TypedValue(); - Resources.Theme theme = aContext.getTheme(); - theme.resolveAttribute(R.attr.urlProtocolColor, typedValue, true); - mURLProtocolColor = typedValue.data; - theme.resolveAttribute(R.attr.urlWebsiteColor, typedValue, true); - mURLWebsiteColor = typedValue.data; - // Bookmarks mBinding.bookmarkButton.setOnClickListener(v -> { v.requestFocusFromTouch(); handleBookmarkClick(); }); - // Initialize bindings - mBinding.setIsLibraryVisible(false); - mBinding.setIsLoading(false); - mBinding.setIsInsecure(false); - mBinding.setIsMicrophoneEnabled(true); - mBinding.setIsFocused(false); - mBinding.setIsSpecialUrl(false); - mBinding.setIsUrlEmpty(true); - mBinding.setIsPopUpAvailable(false); - mBinding.executePendingBindings(); - clearFocus(); } + public void detachFromWindow() { + if (mViewModel != null) { + mViewModel.getIsLoading().removeObserver(mIsLoadingObserver); + mViewModel.getIsBookmarked().removeObserver(mIsBookmarkedObserver); + mViewModel.getHint().removeObserver(mHintObserver); + mViewModel = null; + } + } + + public void attachToWindow(@NonNull WindowWidget aWindow) { + mViewModel = new ViewModelProvider( + (VRBrowserActivity)getContext(), + ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication())) + .get(String.valueOf(aWindow.hashCode()), WindowViewModel.class); + + mBinding.setViewmodel(mViewModel); + + mViewModel.getIsLoading().observe((VRBrowserActivity)getContext(), mIsLoadingObserver); + mViewModel.getIsBookmarked().observe((VRBrowserActivity)getContext(), mIsBookmarkedObserver); + mViewModel.getHint().observe((VRBrowserActivity)getContext(), mHintObserver); + } + public void setSession(Session session) { mSession = session; } public void onPause() { - if (mBinding.getIsLoading()) { + if (mViewModel.getIsLoading().getValue().get()) { mBinding.loadingView.clearAnimation(); } } public void onResume() { - if (mBinding.getIsLoading()) { + if (mViewModel.getIsLoading().getValue().get()) { mBinding.loadingView.startAnimation(mLoadingAnimation); } } @@ -293,11 +294,12 @@ private void handleBookmarkClick() { bookmarkStore.isBookmarked(url).thenAcceptAsync(bookmarked -> { if (!bookmarked) { bookmarkStore.addBookmark(url, mSession.getCurrentTitle()); - setIsBookmarked(true); + mViewModel.setIsBookmarked(true); + } else { // Delete bookmarkStore.deleteBookmarkByURL(url); - setIsBookmarked(false); + mViewModel.setIsBookmarked(false); } }, mUIThreadExecutor).exceptionally(throwable -> { Log.d(LOGTAG, "Error checking bookmark: " + throwable.getLocalizedMessage()); @@ -307,76 +309,17 @@ private void handleBookmarkClick() { } - public void setHint(@StringRes int aHint) { - mBinding.urlEditText.setHint(aHint); - } - - public void setURL(String aURL) { - if (mBinding.getIsLibraryVisible()) { - return; - } - mBinding.urlEditText.removeTextChangedListener(mURLTextWatcher); - if (StringUtils.isEmpty(aURL)) { - setIsBookmarked(false); + private Observer mIsLoadingObserver = aBoolean -> { + if (aBoolean.get()) { + mBinding.loadingView.startAnimation(mLoadingAnimation); } else { - SessionStore.get().getBookmarkStore().isBookmarked(aURL).thenAcceptAsync(this::setIsBookmarked, mUIThreadExecutor).exceptionally(throwable -> { - Log.d(LOGTAG, "Error getting the bookmarked status: " + throwable.getLocalizedMessage()); - throwable.printStackTrace(); - return null; - }); - } - - int index = -1; - if (aURL != null) { - try { - aURL = URLDecoder.decode(aURL, "UTF-8"); - - } catch (UnsupportedEncodingException | IllegalArgumentException e) { - e.printStackTrace(); - aURL = ""; - } - if (aURL.startsWith("jar:")) { - return; - - } else if (aURL.startsWith("resource:") || mSession.isHomeUri(aURL)) { - aURL = ""; - - } else if (aURL.startsWith("data:") && mSession.isPrivateMode()) { - aURL = ""; - - } else if (aURL.startsWith(getContext().getString(R.string.about_blank))) { - aURL = ""; - - } else { - index = aURL.indexOf("://"); - } - - // Update the URL bar only if the URL is different than the current one and - // the URL bar is not focused to avoid override user input - if (!mBinding.urlEditText.getText().toString().equalsIgnoreCase(aURL) && !mBinding.urlEditText.isFocused()) { - mBinding.urlEditText.setText(aURL); - if (index > 0) { - SpannableString spannable = new SpannableString(aURL); - ForegroundColorSpan color1 = new ForegroundColorSpan(mURLProtocolColor); - ForegroundColorSpan color2 = new ForegroundColorSpan(mURLWebsiteColor); - spannable.setSpan(color1, 0, index + 3, 0); - spannable.setSpan(color2, index + 3, aURL.length(), 0); - mBinding.urlEditText.setText(spannable); - - } else { - mBinding.urlEditText.setText(aURL); - } - } - - mBinding.setIsSpecialUrl(aURL.isEmpty()); + mBinding.loadingView.clearAnimation(); } + }; - mBinding.urlEditText.addTextChangedListener(mURLTextWatcher); - } + private Observer mIsBookmarkedObserver = aBoolean -> mBinding.bookmarkButton.clearFocus(); - private boolean isEmptyUrl(@NonNull String aURL) { - return aURL.length() == 0 || aURL.startsWith("about://"); - } + private Observer mHintObserver = hint -> mBinding.urlEditText.setHint(hint); public String getText() { return mBinding.urlEditText.getText().toString(); @@ -391,49 +334,11 @@ public String getOriginalText() { } } - public void setIsLibraryVisible(boolean isLibraryVisible) { - mBinding.setIsLibraryVisible(isLibraryVisible); - } - - public void setIsInsecure(boolean aIsInsecure) { - mBinding.setIsInsecure(aIsInsecure); - } - - public void setIsLoading(boolean aIsLoading) { - mBinding.setIsLoading(aIsLoading); - if (aIsLoading) { - mBinding.loadingView.startAnimation(mLoadingAnimation); - } else { - mBinding.loadingView.clearAnimation(); - } - } - - public void setMicrophoneEnabled(boolean enabled) { - mBinding.setIsMicrophoneEnabled(enabled); - } - - private void setIsBookmarked(boolean aValue) { - mBinding.setIsBookmarked(aValue); - mBinding.bookmarkButton.clearFocus(); - } - - public void setPrivateMode(boolean isEnabled) { - mBinding.bookmarkButton.setPrivateMode(isEnabled); - mBinding.microphoneButton.setPrivateMode(isEnabled); - mBinding.clearButton.setPrivateMode(isEnabled); - - mBinding.setIsPrivateMode(isEnabled); - } - - public void setIsPopUpAvailable(boolean isAvailable) { - mBinding.setIsPopUpAvailable(isAvailable); - } - public UIButton getPopUpButton() { return mBinding.popup; } - public void handleURLEdit(String text) { + public void handleURLEdit(String text) { text = text.trim(); URI uri = null; try { @@ -476,7 +381,7 @@ public void handleURLEdit(String text) { } } - setMicrophoneEnabled(!text.isEmpty()); + mViewModel.setIsMicrophoneEnabled(!text.isEmpty()); clearFocus(); } @@ -528,9 +433,9 @@ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { String aURL = mBinding.urlEditText.getText().toString(); - boolean empty = isEmptyUrl(aURL); - mBinding.setIsUrlEmpty(empty); - setMicrophoneEnabled(empty); + boolean empty = aURL.length() == 0 || aURL.startsWith("about://"); + mViewModel.setIsUrlEmpty(empty); + mViewModel.setIsMicrophoneEnabled(empty); } @Override @@ -607,7 +512,7 @@ public void onAction(String action) { if (action.equals(GeckoSession.SelectionActionDelegate.ACTION_CUT) && selectionValid) { String selectedText = mBinding.urlEditText.getText().toString().substring(startSelection, endSelection); clipboard.setPrimaryClip(ClipData.newPlainText("text", selectedText)); - mBinding.urlEditText.setText(StringUtils.removeRange(mBinding.urlEditText.getText().toString(), startSelection, endSelection)); + mViewModel.setUrl(StringUtils.removeRange(mBinding.urlEditText.getText().toString(), startSelection, endSelection)); mBinding.urlEditText.setSelection(startSelection); } else if (action.equals(GeckoSession.SelectionActionDelegate.ACTION_COPY) && selectionValid) { @@ -617,7 +522,7 @@ public void onAction(String action) { } else if (action.equals(GeckoSession.SelectionActionDelegate.ACTION_PASTE) && clipboard.hasPrimaryClip()) { ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); if (selectionValid) { - mBinding.urlEditText.setText(StringUtils.removeRange(mBinding.urlEditText.getText().toString(), startSelection, endSelection)); + mViewModel.setUrl(StringUtils.removeRange(mBinding.urlEditText.getText().toString(), startSelection, endSelection)); mBinding.urlEditText.setSelection(startSelection); } if (item != null && item.getText() != null) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java index 2cdf8dd40..f5913559e 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java @@ -1129,7 +1129,7 @@ public void OnVoiceSearchError() { private void exitVoiceInputMode() { if (mIsInVoiceInput && mVoiceSearchWidget != null) { - mVoiceSearchWidget.hide(REMOVE_WIDGET); + mVoiceSearchWidget.hide(KEEP_WIDGET); mWidgetPlacement.visible = true; mWidgetManager.updateWidget(this); mIsInVoiceInput = false; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java index 459826af2..84409bb00 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java @@ -7,25 +7,27 @@ import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Rect; -import android.net.Uri; import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; +import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.EditText; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; -import org.mozilla.geckoview.AllowOrDeny; -import org.mozilla.geckoview.GeckoResult; import org.mozilla.geckoview.GeckoSession; import org.mozilla.geckoview.GeckoSessionSettings; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserActivity; import org.mozilla.vrbrowser.VRBrowserApplication; import org.mozilla.vrbrowser.audio.AudioEngine; import org.mozilla.vrbrowser.browser.Media; @@ -33,9 +35,10 @@ import org.mozilla.vrbrowser.browser.SessionChangeListener; import org.mozilla.vrbrowser.browser.SettingsStore; import org.mozilla.vrbrowser.browser.engine.Session; +import org.mozilla.vrbrowser.databinding.NavigationBarBinding; import org.mozilla.vrbrowser.search.suggestions.SuggestionsProvider; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; -import org.mozilla.vrbrowser.ui.views.CustomUIButton; +import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel; import org.mozilla.vrbrowser.ui.views.NavigationURLBar; import org.mozilla.vrbrowser.ui.views.UIButton; import org.mozilla.vrbrowser.ui.views.UITextButton; @@ -47,54 +50,29 @@ import org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget; import org.mozilla.vrbrowser.utils.AnimationHelper; import org.mozilla.vrbrowser.utils.ConnectivityReceiver; -import org.mozilla.vrbrowser.utils.ServoUtils; import org.mozilla.vrbrowser.utils.UrlUtils; -import java.util.ArrayList; -import java.util.Arrays; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import static org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget.VIDEO_PROJECTION_NONE; public class NavigationBarWidget extends UIWidget implements GeckoSession.NavigationDelegate, - GeckoSession.ProgressDelegate, GeckoSession.ContentDelegate, WidgetManagerDelegate.WorldClickListener, + GeckoSession.ContentDelegate, WidgetManagerDelegate.WorldClickListener, WidgetManagerDelegate.UpdateListener, SessionChangeListener, NavigationURLBar.NavigationURLBarDelegate, VoiceSearchWidget.VoiceSearchDelegate, SharedPreferences.OnSharedPreferenceChangeListener, SuggestionsWidget.URLBarPopupDelegate, - WindowWidget.BookmarksViewDelegate, WindowWidget.HistoryViewDelegate, TrayListener, WindowWidget.WindowListener { + TrayListener, WindowWidget.WindowListener { private static final int NOTIFICATION_DURATION = 3000; + private WindowViewModel mViewModel; + private NavigationBarBinding mBinding; private AudioEngine mAudio; - private UIButton mBackButton; - private UIButton mForwardButton; - private UIButton mReloadButton; - private UIButton mHomeButton; - private UIButton mServoButton; - private NavigationURLBar mURLBar; - private ViewGroup mNavigationContainer; - private ViewGroup mFullScreenModeContainer; - private ViewGroup mResizeModeContainer; private WindowWidget mAttachedWindow; - private boolean mIsLoading; - private boolean mIsInVRVideo; - private boolean mAutoEnteredVRVideo; private Runnable mResizeBackHandler; private Runnable mFullScreenBackHandler; private Runnable mVRVideoBackHandler; - private UIButton mResizeExitButton; - private UIButton mMenuButton; - private UIButton mFullScreenExitButton; - private UIButton mBrightnessButton; - private UIButton mFullScreenResizeButton; - private UIButton mProjectionButton; - private UITextButton mPreset0; - private UITextButton mPreset1; - private UITextButton mPreset15; - private UITextButton mPreset2; - private UITextButton mPreset3; - private ArrayList mButtons; private VoiceSearchWidget mVoiceSearchWidget; private Context mAppContext; private SharedPreferences mPrefs; @@ -128,37 +106,45 @@ public NavigationBarWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) } private void initialize(@NonNull Context aContext) { + updateUI(); + mAppContext = aContext.getApplicationContext(); - inflate(aContext, R.layout.navigation_bar, this); mUIThreadExecutor = ((VRBrowserApplication)aContext.getApplicationContext()).getExecutors().mainThread(); mAudio = AudioEngine.fromContext(aContext); - mBackButton = findViewById(R.id.backButton); - mForwardButton = findViewById(R.id.forwardButton); - mReloadButton = findViewById(R.id.reloadButton); - mHomeButton = findViewById(R.id.homeButton); - mServoButton = findViewById(R.id.servoButton); - mURLBar = findViewById(R.id.urlBar); - mNavigationContainer = findViewById(R.id.navigationBarContainer); - mFullScreenModeContainer = findViewById(R.id.fullScreenModeContainer); - mResizeModeContainer = findViewById(R.id.resizeModeContainer); - mFullScreenExitButton = findViewById(R.id.fullScreenExitButton); - mBrightnessButton = findViewById(R.id.brightnessButton); - mFullScreenResizeButton = findViewById(R.id.fullScreenResizeEnterButton); - mProjectionButton = findViewById(R.id.projectionButton); mResizeBackHandler = () -> exitResizeMode(ResizeAction.RESTORE_SIZE); mFullScreenBackHandler = this::exitFullScreenMode; mVRVideoBackHandler = () -> { exitVRVideo(); - if (mAutoEnteredVRVideo) { + if (mViewModel.getAutoEnteredVRVideo().getValue().get()) { exitFullScreenMode(); } }; - mBackButton.setOnClickListener(v -> { + mWidgetManager.addUpdateListener(this); + mWidgetManager.addWorldClickListener(this); + mWidgetManager.addConnectivityListener(mConnectivityDelegate); + + mSuggestionsProvider = new SuggestionsProvider(getContext()); + + mPrefs = PreferenceManager.getDefaultSharedPreferences(mAppContext); + mPrefs.registerOnSharedPreferenceChangeListener(this); + } + + private void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.navigation_bar, this, true); + mBinding.setLifecycleOwner((VRBrowserActivity)getContext()); + mBinding.setViewmodel(mViewModel); + + mBinding.navigationBarNavigation.backButton.setOnClickListener(v -> { v.requestFocusFromTouch(); if (getSession().canGoBack()) { @@ -170,7 +156,7 @@ private void initialize(@NonNull Context aContext) { } }); - mForwardButton.setOnClickListener(v -> { + mBinding.navigationBarNavigation.forwardButton.setOnClickListener(v -> { v.requestFocusFromTouch(); getSession().goForward(); if (mAudio != null) { @@ -178,9 +164,9 @@ private void initialize(@NonNull Context aContext) { } }); - mReloadButton.setOnClickListener(v -> { + mBinding.navigationBarNavigation.reloadButton.setOnClickListener(v -> { v.requestFocusFromTouch(); - if (mIsLoading) { + if (mViewModel.getIsLoading().getValue().get()) { getSession().stop(); } else { getSession().reload(); @@ -190,7 +176,7 @@ private void initialize(@NonNull Context aContext) { } }); - mHomeButton.setOnClickListener(v -> { + mBinding.navigationBarNavigation.homeButton.setOnClickListener(v -> { v.requestFocusFromTouch(); getSession().loadUri(getSession().getHomeUri()); if (mAudio != null) { @@ -198,7 +184,7 @@ private void initialize(@NonNull Context aContext) { } }); - mServoButton.setOnClickListener(v -> { + mBinding.navigationBarNavigation.servoButton.setOnClickListener(v -> { v.requestFocusFromTouch(); getSession().toggleServo(); if (mAudio != null) { @@ -206,15 +192,7 @@ private void initialize(@NonNull Context aContext) { } }); - mMenuButton = findViewById(R.id.menuButton); - mResizeExitButton = findViewById(R.id.resizeExitButton); - mPreset0 = findViewById(R.id.resizePreset0); - mPreset1 = findViewById(R.id.resizePreset1); - mPreset15 = findViewById(R.id.resizePreset15); - mPreset2 = findViewById(R.id.resizePreset2); - mPreset3 = findViewById(R.id.resizePreset3); - - mMenuButton.setOnClickListener(view -> { + mBinding.navigationBarNavigation.menuButton.setOnClickListener(view -> { view.requestFocusFromTouch(); showMenu(); @@ -224,7 +202,7 @@ private void initialize(@NonNull Context aContext) { } }); - mResizeExitButton.setOnClickListener(view -> { + mBinding.navigationBarMenu.resizeExitButton.setOnClickListener(view -> { view.requestFocusFromTouch(); exitResizeMode(ResizeAction.KEEP_SIZE); @@ -233,7 +211,7 @@ private void initialize(@NonNull Context aContext) { } }); - mFullScreenResizeButton.setOnClickListener(view -> { + mBinding.navigationBarFullscreen.fullScreenResizeEnterButton.setOnClickListener(view -> { view.requestFocusFromTouch(); enterResizeMode(); if (mAudio != null) { @@ -241,7 +219,7 @@ private void initialize(@NonNull Context aContext) { } }); - mFullScreenExitButton.setOnClickListener(view -> { + mBinding.navigationBarFullscreen.fullScreenExitButton.setOnClickListener(view -> { view.requestFocusFromTouch(); exitFullScreenMode(); if (mAudio != null) { @@ -249,8 +227,7 @@ private void initialize(@NonNull Context aContext) { } }); - mProjectionButton.setOnClickListener(view -> { - view.requestFocusFromTouch(); + mBinding.navigationBarFullscreen.projectionButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -265,24 +242,33 @@ private void initialize(@NonNull Context aContext) { if (!wasVisible) { mProjectionMenu.show(REQUEST_FOCUS); } + + if (!mProjectionMenu.isVisible()) { + view.requestFocusFromTouch(); + } }); - mBrightnessButton.setOnClickListener(view -> { - view.requestFocusFromTouch(); + mBinding.navigationBarFullscreen.brightnessButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } + boolean wasVisible = mBrightnessWidget.isVisible(); closeFloatingMenus(); + if (!wasVisible) { - float anchor = 0.5f + (float)mBrightnessButton.getMeasuredWidth() / (float)NavigationBarWidget.this.getMeasuredWidth(); + float anchor = 0.5f + (float)mBinding.navigationBarFullscreen.brightnessButton.getMeasuredWidth() / (float)NavigationBarWidget.this.getMeasuredWidth(); mBrightnessWidget.getPlacement().parentAnchorX = anchor; mBrightnessWidget.setVisible(true); } + + if (!mBrightnessWidget.isVisible()) { + view.requestFocusFromTouch(); + } }); - mPreset0.setOnClickListener(view -> { + mBinding.navigationBarMenu.resizePreset0.setOnClickListener(view -> { view.requestFocusFromTouch(); setResizePreset(0.5f); if (mAudio != null) { @@ -290,7 +276,7 @@ private void initialize(@NonNull Context aContext) { } }); - mPreset1.setOnClickListener(view -> { + mBinding.navigationBarMenu.resizePreset1.setOnClickListener(view -> { view.requestFocusFromTouch(); setResizePreset(1.0f); if (mAudio != null) { @@ -298,7 +284,7 @@ private void initialize(@NonNull Context aContext) { } }); - mPreset15.setOnClickListener(view -> { + mBinding.navigationBarMenu.resizePreset15.setOnClickListener(view -> { view.requestFocusFromTouch(); setResizePreset(1.5f); if (mAudio != null) { @@ -306,7 +292,7 @@ private void initialize(@NonNull Context aContext) { } }); - mPreset2.setOnClickListener(view -> { + mBinding.navigationBarMenu.resizePreset2.setOnClickListener(view -> { view.requestFocusFromTouch(); setResizePreset(2.0f); if (mAudio != null) { @@ -314,7 +300,7 @@ private void initialize(@NonNull Context aContext) { } }); - mPreset3.setOnClickListener(view -> { + mBinding.navigationBarMenu.resizePreset3.setOnClickListener(view -> { view.requestFocusFromTouch(); setResizePreset(3.0f); if (mAudio != null) { @@ -322,36 +308,30 @@ private void initialize(@NonNull Context aContext) { } }); - mButtons = new ArrayList<>(); - mButtons.addAll(Arrays.asList( - mBackButton, mForwardButton, mReloadButton, mHomeButton, mMenuButton, - mServoButton, mPreset0, mPreset1, mPreset15, mPreset2, mPreset3, mResizeExitButton)); - - mURLBar.setDelegate(this); - - mWidgetManager.addUpdateListener(this); - mWidgetManager.addWorldClickListener(this); - mWidgetManager.addConnectivityListener(mConnectivityDelegate); + mBinding.navigationBarNavigation.urlBar.setDelegate(this); - mVoiceSearchWidget = createChild(VoiceSearchWidget.class, false); - mVoiceSearchWidget.setDelegate(this); + if (mAttachedWindow != null) { + mBinding.navigationBarNavigation.urlBar.attachToWindow(mAttachedWindow); + } + } - mSuggestionsProvider = new SuggestionsProvider(getContext()); + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - mPrefs = PreferenceManager.getDefaultSharedPreferences(mAppContext); - mPrefs.registerOnSharedPreferenceChangeListener(this); + updateUI(); } @Override public void onPause() { super.onPause(); - mURLBar.onPause(); + mBinding.navigationBarNavigation.urlBar.onPause(); } @Override public void onResume() { super.onResume(); - mURLBar.onResume(); + mBinding.navigationBarNavigation.urlBar.onResume(); } @Override @@ -395,7 +375,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { @Override public void detachFromWindow() { - hideNotification(mURLBar.getPopUpButton()); + hideNotification(mBinding.navigationBarNavigation.urlBar.getPopUpButton()); if (mAttachedWindow != null && mAttachedWindow.isResizing()) { exitResizeMode(ResizeAction.RESTORE_SIZE); @@ -408,8 +388,6 @@ public void detachFromWindow() { cleanSession(getSession()); } if (mAttachedWindow != null) { - mAttachedWindow.removeBookmarksViewListener(this); - mAttachedWindow.removeHistoryViewListener(this); mAttachedWindow.removeWindowListener(this); mAttachedWindow.setPopUpDelegate(null); } @@ -417,6 +395,13 @@ public void detachFromWindow() { if (mAwesomeBar != null && mAwesomeBar.isVisible()) { mAwesomeBar.hideNoAnim(UIWidget.KEEP_WIDGET); } + + mBinding.navigationBarNavigation.urlBar.detachFromWindow(); + + if (mViewModel != null) { + mViewModel.getIsFullscreen().removeObserver(mIsFullscreenObserver); + mViewModel = null; + } } @Override @@ -426,10 +411,19 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { } detachFromWindow(); - mWidgetPlacement.parentHandle = aWindow.getHandle(); mAttachedWindow = aWindow; - mAttachedWindow.addBookmarksViewListener(this); - mAttachedWindow.addHistoryViewListener(this); + mWidgetPlacement.parentHandle = aWindow.getHandle(); + + mViewModel = new ViewModelProvider( + (VRBrowserActivity)getContext(), + ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication())) + .get(String.valueOf(mAttachedWindow.hashCode()), WindowViewModel.class); + + mBinding.setViewmodel(mViewModel); + + mViewModel.getIsFullscreen().observe((VRBrowserActivity)getContext(), mIsFullscreenObserver); + mBinding.navigationBarNavigation.urlBar.attachToWindow(mAttachedWindow); + mAttachedWindow.addWindowListener(this); mAttachedWindow.setPopUpDelegate(mPopUpDelegate); @@ -439,24 +433,6 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { setUpSession(getSession()); } handleWindowResize(); - - if (mAttachedWindow != null) { - mURLBar.setIsLibraryVisible(mAttachedWindow.isBookmarksVisible() || mAttachedWindow.isHistoryVisible()); - if (mAttachedWindow.isBookmarksVisible()) { - mURLBar.setHint(R.string.url_bookmarks_title); - mURLBar.setIsLibraryVisible(true); - - } else if (mAttachedWindow.isHistoryVisible()) { - mURLBar.setHint(R.string.url_history_title); - mURLBar.setIsLibraryVisible(true); - - } else { - mURLBar.setURL(mAttachedWindow.getSession().getCurrentUri()); - mURLBar.setHint(R.string.search_placeholder); - mURLBar.setIsLibraryVisible(false); - } - mURLBar.setIsPopUpAvailable(mAttachedWindow.hasPendingPopUps()); - } } private Session getSession() { @@ -469,23 +445,19 @@ private Session getSession() { private void setUpSession(@NonNull Session aSession) { aSession.addSessionChangeListener(this); aSession.addNavigationListener(this); - aSession.addProgressListener(this); aSession.addContentListener(this); - mURLBar.setSession(getSession()); - updateServoButton(); - handleSessionState(); + mBinding.navigationBarNavigation.urlBar.setSession(getSession()); } private void cleanSession(@NonNull Session aSession) { aSession.removeSessionChangeListener(this); aSession.removeNavigationListener(this); - aSession.removeProgressListener(this); aSession.removeContentListener(this); } @Override public void onSessionChanged(@NonNull Session aOldSession, @NonNull Session aSession) { - mURLBar.setIsPopUpAvailable(mAttachedWindow.hasPendingPopUps()); + mViewModel.setIsPopUpAvailable(mAttachedWindow.hasPendingPopUps()); cleanSession(aOldSession); setUpSession(aSession); @@ -497,15 +469,11 @@ protected void onDraw(Canvas canvas) { } private void enterFullScreenMode() { - if (mAttachedWindow.isFullScreen()) { - return; - } - mWidgetManager.pushBackHandler(mFullScreenBackHandler); mAttachedWindow.setIsFullScreen(true); - AnimationHelper.fadeIn(mFullScreenModeContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); + AnimationHelper.fadeIn(mBinding.navigationBarFullscreen.fullScreenModeContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); - AnimationHelper.fadeOut(mNavigationContainer, 0, null); + AnimationHelper.fadeOut(mBinding.navigationBarNavigation.navigationBarContainer, 0, null); mWidgetManager.pushWorldBrightness(this, WidgetManagerDelegate.DEFAULT_DIM_BRIGHTNESS); @@ -517,7 +485,7 @@ private void enterFullScreenMode() { mProjectionMenuPlacement = new WidgetPlacement(getContext()); mWidgetManager.addWidget(mProjectionMenu); mProjectionMenu.setDelegate((projection)-> { - if (mIsInVRVideo) { + if (mViewModel.getIsInVRVideo().getValue().get()) { // Reproject while reproducing VRVideo mWidgetManager.showVRVideo(mAttachedWindow.getHandle(), projection); closeFloatingMenus(); @@ -536,6 +504,10 @@ private void enterFullScreenMode() { } private void exitFullScreenMode() { + if (mAttachedWindow == null) { + return; + } + if (!mAttachedWindow.isFullScreen()) { mWidgetManager.setTrayVisible(true); return; @@ -554,10 +526,10 @@ private void exitFullScreenMode() { mAttachedWindow.setIsFullScreen(false); mWidgetManager.popBackHandler(mFullScreenBackHandler); - AnimationHelper.fadeIn(mNavigationContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); + AnimationHelper.fadeIn(mBinding.navigationBarNavigation.navigationBarContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); mWidgetManager.popWorldBrightness(this); - AnimationHelper.fadeOut(mFullScreenModeContainer, 0, null); + AnimationHelper.fadeOut(mBinding.navigationBarFullscreen.fullScreenModeContainer, 0, null); mWidgetManager.setTrayVisible(true); closeFloatingMenus(); @@ -571,11 +543,11 @@ private void enterResizeMode() { mAttachedWindow.setIsResizing(true); mAttachedWindow.saveBeforeResizePlacement(); startWidgetResize(); - AnimationHelper.fadeIn(mResizeModeContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); + AnimationHelper.fadeIn(mBinding.navigationBarMenu.resizeModeContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); if (mAttachedWindow.isFullScreen()) { - AnimationHelper.fadeOut(mFullScreenModeContainer, 0, null); + AnimationHelper.fadeOut(mBinding.navigationBarFullscreen.fullScreenModeContainer, 0, null); } else { - AnimationHelper.fadeOut(mNavigationContainer, 0, null); + AnimationHelper.fadeOut(mBinding.navigationBarNavigation.navigationBarContainer, 0, null); } mWidgetManager.pushBackHandler(mResizeBackHandler); mWidgetManager.setTrayVisible(false); @@ -586,12 +558,16 @@ private void enterResizeMode() { maxScale = mAttachedWindow.getMaxWindowScale(); } - mPreset3.setVisibility(maxScale >= 3.0f ? View.VISIBLE : View.GONE); - mPreset2.setVisibility(maxScale >= 2.0f ? View.VISIBLE : View.GONE); - mPreset15.setVisibility(maxScale == 1.5f ? View.VISIBLE: View.GONE); + mBinding.navigationBarMenu.resizePreset3.setVisibility(maxScale >= 3.0f ? View.VISIBLE : View.GONE); + mBinding.navigationBarMenu.resizePreset2.setVisibility(maxScale >= 2.0f ? View.VISIBLE : View.GONE); + mBinding.navigationBarMenu.resizePreset15.setVisibility(maxScale == 1.5f ? View.VISIBLE: View.GONE); // Update visible presets - UITextButton[] presets = { mPreset3, mPreset2, mPreset15, mPreset1}; + UITextButton[] presets = { + mBinding.navigationBarMenu.resizePreset3, + mBinding.navigationBarMenu.resizePreset2, + mBinding.navigationBarMenu.resizePreset15, + mBinding.navigationBarMenu.resizePreset1}; boolean fistVisible = true; for (UITextButton preset: presets) { if (fistVisible) { @@ -630,11 +606,11 @@ private void exitResizeMode(ResizeAction aResizeAction) { mAttachedWindow.setIsResizing(false); finishWidgetResize(); if (mAttachedWindow.isFullScreen()) { - AnimationHelper.fadeIn(mFullScreenModeContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); + AnimationHelper.fadeIn(mBinding.navigationBarFullscreen.fullScreenModeContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); } else { - AnimationHelper.fadeIn(mNavigationContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); + AnimationHelper.fadeIn(mBinding.navigationBarNavigation.navigationBarContainer, AnimationHelper.FADE_ANIMATION_DURATION, null); } - AnimationHelper.fadeOut(mResizeModeContainer, 0, () -> onWidgetUpdate(mAttachedWindow)); + AnimationHelper.fadeOut(mBinding.navigationBarMenu.resizeModeContainer, 0, () -> onWidgetUpdate(mAttachedWindow)); mWidgetManager.popBackHandler(mResizeBackHandler); mWidgetManager.setTrayVisible(!mAttachedWindow.isFullScreen()); closeFloatingMenus(); @@ -645,10 +621,10 @@ private void exitResizeMode(ResizeAction aResizeAction) { } private void enterVRVideo(@VideoProjectionMenuWidget.VideoProjectionFlags int aProjection) { - if (mIsInVRVideo) { + if (mViewModel.getIsInVRVideo().getValue().get()) { return; } - mIsInVRVideo = true; + mViewModel.setIsInVRVideo(true); mWidgetManager.pushBackHandler(mVRVideoBackHandler); mProjectionMenu.setSelectedProjection(aProjection); // Backup the placement because the same widget is reused in FullScreen & MediaControl menus @@ -691,13 +667,13 @@ private void enterVRVideo(@VideoProjectionMenuWidget.VideoProjectionFlags int aP } private void exitVRVideo() { - if (!mIsInVRVideo) { + if (!mViewModel.getIsInVRVideo().getValue().get()) { return; } if (mFullScreenMedia != null) { mFullScreenMedia.setResizeDelegate(null); } - mIsInVRVideo = false; + mViewModel.setIsInVRVideo(false); mWidgetManager.popBackHandler(mVRVideoBackHandler); mWidgetManager.hideVRVideo(); boolean composited = mProjectionMenu.getPlacement().composited; @@ -723,31 +699,7 @@ private void setResizePreset(float aMultiplier) { } public void showVoiceSearch() { - mURLBar.setMicrophoneEnabled(true); - } - - public void updateServoButton() { - // We show the Servo button if: - // 1. the current session is using Servo. No matter what, we need the toggle button to go back to Gecko. - // 2. Or, if the pref is enabled and the current url is white listed. - boolean show = false; - boolean isServoSession = false; - if (getSession() != null){ - GeckoSession currentSession = getSession().getGeckoSession(); - if (currentSession != null) { - String currentUri = getSession().getCurrentUri(); - boolean isPrefEnabled = SettingsStore.getInstance(mAppContext).isServoEnabled(); - boolean isUrlWhiteListed = ServoUtils.isUrlInServoWhiteList(mAppContext, currentUri); - isServoSession = ServoUtils.isInstanceOfServoSession(currentSession); - show = isServoSession || (isPrefEnabled && isUrlWhiteListed); - } - if (show) { - mServoButton.setVisibility(View.VISIBLE); - mServoButton.setImageResource(isServoSession ? R.drawable.ic_icon_gecko : R.drawable.ic_icon_servo); - } else { - mServoButton.setVisibility(View.GONE); - } - } + mViewModel.setIsMicrophoneEnabled(true); } private void closeFloatingMenus() { @@ -759,115 +711,15 @@ private void closeFloatingMenus() { } } - private void handleSessionState() { - if (getSession() != null) { - boolean isPrivateMode = getSession().isPrivateMode(); - - mURLBar.setPrivateMode(isPrivateMode); - for (CustomUIButton button : mButtons) { - button.setPrivateMode(isPrivateMode); - } - } - } - - @Override - public void onLocationChange(GeckoSession session, String url) { - if (mURLBar != null && !mAttachedWindow.isBookmarksVisible() && !mAttachedWindow.isHistoryVisible()) { - Log.d(LOGTAG, "Got location change"); - mURLBar.setURL(url); - mURLBar.setHint(R.string.search_placeholder); - mReloadButton.setEnabled(true); - } - updateServoButton(); - } - - @Override - public void onCanGoBack(GeckoSession aSession, boolean canGoBack) { - if (mBackButton != null) { - Log.d(LOGTAG, "Got onCanGoBack: " + (canGoBack ? "true" : "false")); - mBackButton.setEnabled(canGoBack); - mBackButton.setHovered(false); - mBackButton.setClickable(canGoBack); - } - } - - @Override - public void onCanGoForward(GeckoSession aSession, boolean canGoForward) { - if (mForwardButton != null) { - Log.d(LOGTAG, "Got onCanGoForward: " + (canGoForward ? "true" : "false")); - mForwardButton.setEnabled(canGoForward); - mForwardButton.setHovered(false); - mForwardButton.setClickable(canGoForward); - } - } - - @Override - public @Nullable GeckoResult onLoadRequest(GeckoSession aSession, @NonNull LoadRequest aRequest) { - final GeckoResult result = new GeckoResult<>(); - - Uri uri = Uri.parse(aRequest.uri); - if ("file".equalsIgnoreCase(uri.getScheme()) && - !mWidgetManager.isPermissionGranted(android.Manifest.permission.READ_EXTERNAL_STORAGE)) { - mWidgetManager.requestPermission( - aRequest.uri, - android.Manifest.permission.READ_EXTERNAL_STORAGE, - new GeckoSession.PermissionDelegate.Callback() { - @Override - public void grant() { - result.complete(AllowOrDeny.ALLOW); - } - - @Override - public void reject() { - result.complete(AllowOrDeny.DENY); - } - }); - return result; - } - - result.complete(AllowOrDeny.ALLOW); - return result; - } - - // Progress Listener - @Override - public void onPageStart(GeckoSession aSession, String aUri) { - if (mURLBar != null) { - Log.d(LOGTAG, "Got onPageStart"); - mURLBar.setURL(aUri); - mURLBar.setHint(R.string.search_placeholder); - } - mIsLoading = true; - mURLBar.setIsLoading(true); - if (mReloadButton != null) { - mReloadButton.setImageResource(R.drawable.ic_icon_exit); - mReloadButton.setTooltip(getResources().getString(R.string.stop_tooltip)); - } - } - - @Override - public void onPageStop(GeckoSession aSession, boolean b) { - mIsLoading = false; - mURLBar.setIsLoading(false); - if (mReloadButton != null) { - mReloadButton.setImageResource(R.drawable.ic_icon_reload); - mReloadButton.setTooltip(getResources().getString(R.string.refresh_tooltip)); - } - } + // Content delegate @Override - public void onSecurityChange(GeckoSession geckoSession, SecurityInformation securityInformation) { - if (mURLBar != null) { - boolean isSecure = securityInformation.isSecure; - mURLBar.setIsInsecure(!isSecure); - } + public void onFullScreen(@NonNull GeckoSession session, boolean aFullScreen) { + mViewModel.setIsFullscreen(aFullScreen); } - // Content delegate - - @Override - public void onFullScreen(GeckoSession session, boolean aFullScreen) { - if (aFullScreen) { + private Observer mIsFullscreenObserver = isFullScreen -> { + if (isFullScreen.get()) { if (!mAttachedWindow.isFullScreen()) { enterFullScreenMode(); } @@ -877,21 +729,21 @@ public void onFullScreen(GeckoSession session, boolean aFullScreen) { AtomicBoolean autoEnter = new AtomicBoolean(false); mAutoSelectedProjection = VideoProjectionMenuWidget.getAutomaticProjection(getSession().getCurrentUri(), autoEnter); if (mAutoSelectedProjection != VIDEO_PROJECTION_NONE && autoEnter.get()) { - mAutoEnteredVRVideo = true; + mViewModel.setAutoEnteredVRVideo(true); postDelayed(() -> enterVRVideo(mAutoSelectedProjection), 300); } else { - mAutoEnteredVRVideo = false; + mViewModel.setAutoEnteredVRVideo(false); if (mProjectionMenu != null) { mProjectionMenu.setSelectedProjection(mAutoSelectedProjection); } } } else { - if (mIsInVRVideo) { + if (mViewModel.getIsInVRVideo().getValue().get()) { exitVRVideo(); } exitFullScreenMode(); } - } + }; // WidgetManagerDelegate.UpdateListener @Override @@ -921,8 +773,6 @@ private void handleWindowResize() { @Override public void onCurrentSessionChange(GeckoSession aOldSession, GeckoSession aSession) { - handleSessionState(); - boolean isFullScreen = getSession().isInFullScreen(); if (isFullScreen && !mAttachedWindow.isFullScreen()) { enterFullScreenMode(); @@ -936,13 +786,13 @@ public void onCurrentSessionChange(GeckoSession aOldSession, GeckoSession aSessi @Override public void onVoiceSearchClicked() { - if (mVoiceSearchWidget.isVisible()) { - mVoiceSearchWidget.hide(REMOVE_WIDGET); - - } else { - mVoiceSearchWidget.getPlacement().parentHandle = mAttachedWindow.getHandle(); - mVoiceSearchWidget.show(REQUEST_FOCUS); + if (mVoiceSearchWidget == null) { + mVoiceSearchWidget = new VoiceSearchWidget(getContext()); + mVoiceSearchWidget.setDelegate(this); } + + mVoiceSearchWidget.getPlacement().parentHandle = mAttachedWindow.getHandle(); + mVoiceSearchWidget.show(REQUEST_FOCUS); } @@ -953,8 +803,8 @@ public void onShowAwesomeBar() { mAwesomeBar.setURLBarPopupDelegate(this); } - final String text = mURLBar.getText().trim(); - final String originalText = mURLBar.getOriginalText().trim(); + final String text = mBinding.navigationBarNavigation.urlBar.getText().trim(); + final String originalText = mBinding.navigationBarNavigation.urlBar.getOriginalText().trim(); if (originalText.length() <= 0) { mAwesomeBar.hide(UIWidget.KEEP_WIDGET); return; @@ -964,12 +814,12 @@ public void onShowAwesomeBar() { mSuggestionsProvider.setFilterText(originalText); mSuggestionsProvider.getSuggestions() .whenCompleteAsync((items, ex) -> { - if (mURLBar.hasFocus()) { + if (mBinding.navigationBarNavigation.urlBar.hasFocus()) { mAwesomeBar.updateItems(items); mAwesomeBar.setHighlightedText(originalText); if (!mAwesomeBar.isVisible()) { - mAwesomeBar.updatePlacement((int) WidgetPlacement.convertPixelsToDp(getContext(), mURLBar.getWidth())); + mAwesomeBar.updatePlacement((int) WidgetPlacement.convertPixelsToDp(getContext(), mBinding.navigationBarNavigation.urlBar.getWidth())); mAwesomeBar.show(CLEAR_FOCUS); } } @@ -1009,15 +859,12 @@ public void onPopUpButtonClicked() { @Override public void OnVoiceSearchResult(String transcription, float confidance) { - mURLBar.handleURLEdit(transcription); + mBinding.navigationBarNavigation.urlBar.handleURLEdit(transcription); } @Override public void onSharedPreferenceChanged(@NonNull SharedPreferences sharedPreferences, String key) { - if (key.equals(mAppContext.getString(R.string.settings_key_servo))) { - updateServoButton(); - - } else if (key.equals(mAppContext.getString(R.string.settings_key_user_agent_version))) { + if (key.equals(mAppContext.getString(R.string.settings_key_user_agent_version))) { if (mHamburgerMenu != null) { mHamburgerMenu.setUAMode(SettingsStore.getInstance(getContext()).getUaMode()); } @@ -1027,7 +874,7 @@ public void onSharedPreferenceChanged(@NonNull SharedPreferences sharedPreferenc // WorldClickListener @Override public void onWorldClick() { - if (mIsInVRVideo && mMediaControlsWidget != null) { + if (mViewModel.getIsInVRVideo().getValue().get() && mMediaControlsWidget != null) { mMediaControlsWidget.setVisible(!mMediaControlsWidget.isVisible()); if (mProjectionMenu.getSelectedProjection() != VideoProjectionMenuWidget.VIDEO_PROJECTION_3D_SIDE_BY_SIDE) { if (mMediaControlsWidget.isVisible()) { @@ -1050,51 +897,7 @@ public void onWorldClick() { @Override public void OnItemClicked(SuggestionsWidget.SuggestionItem item) { - mURLBar.handleURLEdit(item.url); - } - - // BookmarksViewListener - - @Override - public void onBookmarksShown(WindowWidget aWindow) { - if (mAttachedWindow == aWindow) { - mURLBar.setURL(""); - mURLBar.setHint(R.string.url_bookmarks_title); - mURLBar.setIsLibraryVisible(true); - } - - hideNotifications(); - } - - @Override - public void onBookmarksHidden(WindowWidget aWindow) { - if (mAttachedWindow == aWindow) { - mURLBar.setIsLibraryVisible(false); - mURLBar.setURL(getSession().getCurrentUri()); - mURLBar.setHint(R.string.search_placeholder); - } - } - - // HistoryViewListener - - @Override - public void onHistoryViewShown(WindowWidget aWindow) { - if (mAttachedWindow == aWindow) { - mURLBar.setURL(""); - mURLBar.setHint(R.string.url_history_title); - mURLBar.setIsLibraryVisible(true); - } - - hideNotifications(); - } - - @Override - public void onHistoryViewHidden(WindowWidget aWindow) { - if (mAttachedWindow == aWindow) { - mURLBar.setIsLibraryVisible(false); - mURLBar.setURL(getSession().getCurrentUri()); - mURLBar.setHint(R.string.search_placeholder); - } + mBinding.navigationBarNavigation.urlBar.handleURLEdit(item.url); } // TrayListener @@ -1107,7 +910,7 @@ public void onBookmarksClicked() { } else if (mAttachedWindow.isFullScreen()) { exitFullScreenMode(); - } else if (mIsInVRVideo) { + } else if (mViewModel.getIsInVRVideo().getValue().get()) { exitVRVideo(); } } @@ -1125,7 +928,7 @@ public void onHistoryClicked() { } else if (mAttachedWindow.isFullScreen()) { exitFullScreenMode(); - } else if (mIsInVRVideo) { + } else if (mViewModel.getIsInVRVideo().getValue().get()) { exitVRVideo(); } } @@ -1153,43 +956,38 @@ private void showMenu() { return; } - if (mHamburgerMenu == null) { - mHamburgerMenu = new HamburgerMenuWidget(getContext()); - mHamburgerMenu.getPlacement().parentHandle = getHandle(); - mHamburgerMenu.setMenuDelegate(new HamburgerMenuWidget.MenuDelegate() { - @Override - public void onSendTab() { - hideMenu(); + mHamburgerMenu = new HamburgerMenuWidget(getContext()); + mHamburgerMenu.getPlacement().parentHandle = getHandle(); + mHamburgerMenu.setMenuDelegate(new HamburgerMenuWidget.MenuDelegate() { + @Override + public void onSendTab() { + hideMenu(); - showSendTabDialog(); - } + showSendTabDialog(); + } - @Override - public void onResize() { - hideMenu(); + @Override + public void onResize() { + hideMenu(); - enterResizeMode(); - } + enterResizeMode(); + } - @Override - public void onSwitchMode() { - if (mAttachedWindow.getSession() != null) { - int uaMode = mAttachedWindow.getSession().getUaMode(); - if (uaMode == GeckoSessionSettings.USER_AGENT_MODE_DESKTOP) { - mHamburgerMenu.setUAMode(GeckoSessionSettings.USER_AGENT_MODE_MOBILE); - mAttachedWindow.getSession().setUaMode(GeckoSessionSettings.USER_AGENT_MODE_MOBILE); - - } else { - mHamburgerMenu.setUAMode(GeckoSessionSettings.USER_AGENT_MODE_DESKTOP); - mAttachedWindow.getSession().setUaMode(GeckoSessionSettings.USER_AGENT_MODE_DESKTOP); - } - } + @Override + public void onSwitchMode() { + int uaMode = mAttachedWindow.getSession().getUaMode(); + if (uaMode == GeckoSessionSettings.USER_AGENT_MODE_DESKTOP) { + mHamburgerMenu.setUAMode(GeckoSessionSettings.USER_AGENT_MODE_MOBILE); + mAttachedWindow.getSession().setUaMode(GeckoSessionSettings.USER_AGENT_MODE_MOBILE); - hideMenu(); + } else { + mHamburgerMenu.setUAMode(GeckoSessionSettings.USER_AGENT_MODE_DESKTOP); + mAttachedWindow.getSession().setUaMode(GeckoSessionSettings.USER_AGENT_MODE_DESKTOP); } - }); - } + hideMenu(); + } + }); mHamburgerMenu.setSendTabEnabled(!UrlUtils.isPrivateAboutPage(getContext(), mAttachedWindow.getSession().getCurrentUri())); mHamburgerMenu.setUAMode(mAttachedWindow.getSession().getUaMode()); mHamburgerMenu.show(UIWidget.KEEP_FOCUS); @@ -1214,12 +1012,12 @@ public void showSendTabDialog() { @Override public void onPopUpAvailable() { showPopUpsBlockedNotification(); - mURLBar.setIsPopUpAvailable(true); + mViewModel.setIsPopUpAvailable(true); } @Override public void onPopUpsCleared() { - mURLBar.setIsPopUpAvailable(false); + mViewModel.setIsPopUpAvailable(false); hidePopUpsBlockedNotification(); } }; @@ -1230,7 +1028,7 @@ public void showPopUpsBlockedNotification() { final int currentCount = mBlockedCount; postDelayed(() -> { if (currentCount == mBlockedCount) { - showNotification(mURLBar.getPopUpButton(), R.string.popup_tooltip); + showNotification(mBinding.navigationBarNavigation.urlBar.getPopUpButton(), R.string.popup_tooltip); } }, POP_UP_NOTIFICATION_DELAY); } @@ -1240,7 +1038,7 @@ public void hidePopUpsBlockedNotification() { final int currentCount = mBlockedCount; post(() -> { if (currentCount == mBlockedCount) { - hideNotification(mURLBar.getPopUpButton()); + hideNotification(mBinding.navigationBarNavigation.urlBar.getPopUpButton()); } }); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java index ce842c687..be4804a8a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java @@ -3,6 +3,7 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; @@ -67,11 +68,7 @@ public SuggestionsWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { } private void initialize(Context aContext) { - inflate(aContext, R.layout.list_popup_window, this); - - mWidgetManager.addFocusChangeListener(this); - - mList = findViewById(R.id.list); + updateUI(); mScaleUpAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.popup_scaleup); mScaleDownAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.popup_scaledown); @@ -92,22 +89,35 @@ public void onAnimationRepeat(Animation animation) { } }); + mAudio = AudioEngine.fromContext(aContext); + mClipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + + mHighlightedText = ""; + } + + public void updateUI() { + removeAllViews(); + + inflate(getContext(), R.layout.list_popup_window, this); + + mList = findViewById(R.id.list); + mAdapter = new SuggestionsAdapter(getContext(), R.layout.list_popup_window_item, new ArrayList<>()); mList.setAdapter(mAdapter); mList.setOnItemClickListener(mClickListener); mList.setOnItemLongClickListener(mLongClickListener); mList.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> hideMenu()); + } - mAudio = AudioEngine.fromContext(aContext); - mClipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - mHighlightedText = ""; + updateUI(); } @Override public void releaseWidget() { - mWidgetManager.removeFocusChangeListener(this); - super.releaseWidget(); } @@ -128,12 +138,14 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { @Override public void show(@ShowFlags int aShowFlags) { super.show(aShowFlags); + mWidgetManager.addFocusChangeListener(this); mList.startAnimation(mScaleUpAnimation); mList.post(() -> mList.setSelectionAfterHeaderView()); } @Override public void hide(@HideFlags int aHideFlags) { + mWidgetManager.removeFocusChangeListener(this); mList.startAnimation(mScaleDownAnimation); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TabsWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TabsWidget.java index 008354366..47d70b46d 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TabsWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TabsWidget.java @@ -1,6 +1,7 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.view.LayoutInflater; import android.view.View; @@ -72,6 +73,12 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { } private void initialize() { + updateUI(); + } + + public void updateUI() { + removeAllViews(); + inflate(getContext(), R.layout.tabs, this); mTabsList = findViewById(R.id.tabsRecyclerView); @@ -137,6 +144,13 @@ private void initialize() { }); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + public void attachToWindow(WindowWidget aWindow) { mPrivateMode = aWindow.getSession().isPrivateMode(); mWidgetPlacement.parentHandle = aWindow.getHandle(); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TitleBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TitleBarWidget.java index e03c2e934..992e5b326 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TitleBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TitleBarWidget.java @@ -6,26 +6,23 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.res.Configuration; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.View; -import android.webkit.URLUtil; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.StringRes; import androidx.databinding.DataBindingUtil; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; -import org.mozilla.geckoview.MediaElement; import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.browser.Media; +import org.mozilla.vrbrowser.VRBrowserActivity; import org.mozilla.vrbrowser.databinding.TitleBarBinding; +import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; - -public class TitleBarWidget extends UIWidget implements WidgetManagerDelegate.UpdateListener { +public class TitleBarWidget extends UIWidget { public interface Delegate { void onTitleClicked(@NonNull TitleBarWidget titleBar); @@ -33,11 +30,11 @@ public interface Delegate { void onMediaPauseClicked(@NonNull TitleBarWidget titleBar); } + private WindowViewModel mViewModel; private TitleBarBinding mBinding; private WindowWidget mAttachedWindow; - private boolean mVisible = false; - private Media mMedia; private boolean mWidgetAdded = false; + private Delegate mDelegate; public TitleBarWidget(Context aContext) { super(aContext); @@ -55,17 +52,31 @@ public TitleBarWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { } private void initialize(@NonNull Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + private void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); mBinding = DataBindingUtil.inflate(inflater, R.layout.title_bar, this, true); mBinding.setWidget(this); - mBinding.executePendingBindings(); + mBinding.setDelegate(mDelegate); + mBinding.setLifecycleOwner((VRBrowserActivity)getContext()); + mBinding.setViewmodel(mViewModel); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - mWidgetManager.addUpdateListener(this); + updateUI(); } public void setDelegate(Delegate delegate) { - mBinding.setDelegate(delegate); + mDelegate = delegate; + mBinding.setDelegate(mDelegate); } public @Nullable @@ -77,8 +88,6 @@ WindowWidget getAttachedWindow() { public void releaseWidget() { detachFromWindow(); - mWidgetManager.removeUpdateListener(this); - mAttachedWindow = null; super.releaseWidget(); } @@ -104,6 +113,11 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { @Override public void detachFromWindow() { mAttachedWindow = null; + + if (mViewModel != null) { + mViewModel.getIsTitleBarVisible().removeObserver(mIsVisibleObserver); + mViewModel = null; + } } @Override @@ -116,117 +130,25 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { mWidgetPlacement.parentHandle = aWindow.getHandle(); mAttachedWindow = aWindow; - setPrivateMode(aWindow.getSession().isPrivateMode()); - } - - @Override - public void setVisible(boolean aIsVisible) { - if (mVisible == aIsVisible || mWidgetManager == null) { - return; - } - mVisible = aIsVisible; - getPlacement().visible = aIsVisible; - if (!mWidgetAdded) { - mWidgetManager.addWidget(this); - mWidgetAdded = true; - } else { - mWidgetManager.updateWidget(this); - } - } - - private void setPrivateMode(boolean aPrivateMode) { - mBinding.titleBar.setBackground(getContext().getDrawable(aPrivateMode ? R.drawable.title_bar_background_private : R.drawable.title_bar_background)); - mBinding.mediaButton.setPrivateMode(aPrivateMode); - } - - public void setURL(@StringRes int id) { - setURL(getResources().getString(id)); - } - - public void setURL(String urlString) { - if (urlString == null) { - return; - } - - if (URLUtil.isValidUrl(urlString)) { - try { - URI uri = URI.create(urlString); - URL url = new URL( - uri.getScheme() != null ? uri.getScheme() : "", - uri.getAuthority() != null ? uri.getAuthority() : "", - ""); - mBinding.url.setText(url.toString()); - - } catch (MalformedURLException | IllegalArgumentException e) { - mBinding.url.setText(""); - } - - } else { - mBinding.url.setText(urlString); - } - } + // ModelView creation and observers setup + mViewModel = new ViewModelProvider( + (VRBrowserActivity)getContext(), + ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication())) + .get(String.valueOf(mAttachedWindow.hashCode()), WindowViewModel.class); - public void setIsInsecure(boolean aIsInsecure) { - if (mAttachedWindow != null && mAttachedWindow.getSession() != null && - mAttachedWindow.getSession().getCurrentUri() != null && - !(mAttachedWindow.getSession().getCurrentUri().startsWith("data") && - mAttachedWindow.getSession().isPrivateMode())) { - mBinding.insecureIcon.setVisibility(aIsInsecure ? View.VISIBLE : View.GONE); - } - } + mBinding.setViewmodel(mViewModel); - public void setInsecureVisibility(int visibility) { - mBinding.insecureIcon.setVisibility(visibility); + mViewModel.getIsTitleBarVisible().observe((VRBrowserActivity)getContext(), mIsVisibleObserver); } - public void mediaAvailabilityChanged(boolean available) { - if (mMedia != null) { - mMedia.removeMediaListener(mMediaDelegate); - } - if (available && mAttachedWindow != null && mAttachedWindow.getSession() != null) { - mMedia = mAttachedWindow.getSession().getFullScreenVideo(); - if (mMedia != null) { - mMedia.addMediaListener(mMediaDelegate); - if (mMedia.isPlayed()) { - mBinding.setIsMediaAvailable(true); - mBinding.setIsMediaPlaying(true); - } - } + Observer mIsVisibleObserver = isVisible -> { + mWidgetPlacement.visible = isVisible.get(); + if (!mWidgetAdded) { + mWidgetManager.addWidget(TitleBarWidget.this); + mWidgetAdded = true; } else { - mMedia = null; - mBinding.setIsMediaAvailable(false); - } - } - - public void updateMediaStatus() { - if (mMedia != null) { - mBinding.setIsMediaAvailable(mMedia.isPlayed()); - mBinding.setIsMediaPlaying(mMedia.isPlaying()); - } - } - - MediaElement.Delegate mMediaDelegate = new MediaElement.Delegate() { - @Override - public void onPlaybackStateChange(@NonNull MediaElement mediaElement, int state) { - switch(state) { - case MediaElement.MEDIA_STATE_PLAY: - case MediaElement.MEDIA_STATE_PLAYING: - mBinding.setIsMediaAvailable(true); - mBinding.setIsMediaPlaying(true); - break; - case MediaElement.MEDIA_STATE_PAUSE: - mBinding.setIsMediaAvailable(true); - mBinding.setIsMediaPlaying(false); - } + mWidgetManager.updateWidget(TitleBarWidget.this); } }; - // WidgetManagerDelegate.UpdateListener - @Override - public void onWidgetUpdate(Widget aWidget) { - if (aWidget == mWidgetManager.getFocusedWindow()) { - mWidgetManager.updateWidget(this); - } - } - } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TooltipWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TooltipWidget.java index bd0cb5656..a831cbb31 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TooltipWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TooltipWidget.java @@ -1,6 +1,7 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.res.Configuration; import android.view.ViewGroup; import android.widget.TextView; @@ -15,6 +16,7 @@ public class TooltipWidget extends UIWidget { protected TextView mText; protected ViewGroup mLayout; + protected int mLayoutRes; public TooltipWidget(@NonNull Context aContext, @NonNull @LayoutRes int layoutRes) { super(aContext); @@ -29,10 +31,8 @@ public TooltipWidget(Context aContext) { } private void initialize(@NonNull @LayoutRes int layoutRes) { - inflate(getContext(), layoutRes, this); - - mLayout = findViewById(R.id.layout); - mText = findViewById(R.id.tooltipText); + mLayoutRes = layoutRes; + updateUI(); } @Override @@ -47,6 +47,22 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.tooltip_z_distance); } + public void updateUI() { + removeAllViews(); + + inflate(getContext(), mLayoutRes, this); + + mLayout = findViewById(R.id.layout); + mText = findViewById(R.id.tooltipText); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + @Override public void show(@ShowFlags int aShowFlags) { measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java index 418f5955d..5695e8042 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java @@ -6,28 +6,30 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.res.Configuration; import android.util.AttributeSet; -import android.widget.LinearLayout; +import android.view.LayoutInflater; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserActivity; import org.mozilla.vrbrowser.audio.AudioEngine; -import org.mozilla.vrbrowser.ui.views.UIButton; -import org.mozilla.vrbrowser.ui.views.UITextButton; +import org.mozilla.vrbrowser.databinding.TopBarBinding; +import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel; -public class TopBarWidget extends UIWidget implements WidgetManagerDelegate.UpdateListener { +public class TopBarWidget extends UIWidget { - private UIButton mCloseButton; - private UIButton mMoveLeftButton; - private UIButton mMoveRightButton; - private UITextButton mClearButton; + private WindowViewModel mViewModel; + private TopBarBinding mBinding; private AudioEngine mAudio; private WindowWidget mAttachedWindow; private TopBarWidget.Delegate mDelegate; - private LinearLayout mMultiWindowControlsContainer; - private boolean mVisible = false; private boolean mWidgetAdded = false; public TopBarWidget(Context aContext) { @@ -52,12 +54,36 @@ public interface Delegate { } private void initialize(Context aContext) { - inflate(aContext, R.layout.top_bar, this); + mAudio = AudioEngine.fromContext(aContext); + + updateUI(); + } + + @Override + protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { + Context context = getContext(); + aPlacement.width = WidgetPlacement.dpDimension(context, R.dimen.top_bar_width); + aPlacement.height = WidgetPlacement.dpDimension(context, R.dimen.top_bar_height); + aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width) * aPlacement.width/getWorldWidth(); + aPlacement.translationY = WidgetPlacement.dpDimension(context, R.dimen.top_bar_window_margin); + aPlacement.anchorX = 0.5f; + aPlacement.anchorY = 0.0f; + aPlacement.parentAnchorX = 0.5f; + aPlacement.parentAnchorY = 1.0f; + aPlacement.opaque = false; + } + + private void updateUI() { + removeAllViews(); - mMultiWindowControlsContainer = findViewById(R.id.multiWindowControlsContainer); + LayoutInflater inflater = LayoutInflater.from(getContext()); - mCloseButton = findViewById(R.id.closeWindowButton); - mCloseButton.setOnClickListener(view -> { + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.top_bar, this, true); + mBinding.setLifecycleOwner((VRBrowserActivity)getContext()); + mBinding.setViewmodel(mViewModel); + + mBinding.closeWindowButton.setOnClickListener(view -> { view.requestFocusFromTouch(); if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); @@ -67,8 +93,7 @@ private void initialize(Context aContext) { } }); - mMoveLeftButton = findViewById(R.id.moveWindowLeftButton); - mMoveLeftButton.setOnClickListener(view -> { + mBinding.moveWindowLeftButton.setOnClickListener(view -> { view.requestFocusFromTouch(); if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); @@ -78,8 +103,7 @@ private void initialize(Context aContext) { } }); - mMoveRightButton = findViewById(R.id.moveWindowRightButton); - mMoveRightButton.setOnClickListener(view -> { + mBinding.moveWindowRightButton.setOnClickListener(view -> { view.requestFocusFromTouch(); if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); @@ -89,8 +113,7 @@ private void initialize(Context aContext) { } }); - mClearButton = findViewById(R.id.clearButton); - mClearButton.setOnClickListener(view -> { + mBinding.clearButton.setOnClickListener(view -> { view.requestFocusFromTouch(); if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); @@ -99,36 +122,23 @@ private void initialize(Context aContext) { mDelegate.onCloseClicked(TopBarWidget.this); } }); - - mAudio = AudioEngine.fromContext(aContext); - - mWidgetManager.addUpdateListener(this); } @Override - protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { - Context context = getContext(); - aPlacement.width = WidgetPlacement.dpDimension(context, R.dimen.top_bar_width); - aPlacement.height = WidgetPlacement.dpDimension(context, R.dimen.top_bar_height); - aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width) * aPlacement.width/getWorldWidth(); - aPlacement.translationY = WidgetPlacement.dpDimension(context, R.dimen.top_bar_window_margin); - aPlacement.anchorX = 0.5f; - aPlacement.anchorY = 0.0f; - aPlacement.parentAnchorX = 0.5f; - aPlacement.parentAnchorY = 1.0f; - aPlacement.opaque = false; - } - - @Override - public void releaseWidget() { - mWidgetManager.removeUpdateListener(this); + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - super.releaseWidget(); + updateUI(); } @Override public void detachFromWindow() { mAttachedWindow = null; + + if (mViewModel != null) { + mViewModel.getIsTopBarVisible().removeObserver(mIsVisible); + mViewModel = null; + } } @Override @@ -136,65 +146,46 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { if (mAttachedWindow == aWindow) { return; } + detachFromWindow(); + mWidgetPlacement.parentHandle = aWindow.getHandle(); mAttachedWindow = aWindow; - setPrivateMode(aWindow.getSession().isPrivateMode()); + // ModelView creation and observers setup + mViewModel = new ViewModelProvider( + (VRBrowserActivity)getContext(), + ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication())) + .get(String.valueOf(mAttachedWindow.hashCode()), WindowViewModel.class); + + mBinding.setViewmodel(mViewModel); + mViewModel.getIsTopBarVisible().observe((VRBrowserActivity)getContext(), mIsVisible); } public @Nullable WindowWidget getAttachedWindow() { return mAttachedWindow; } - private void setPrivateMode(boolean aPrivateMode) { - mCloseButton.setPrivateMode(aPrivateMode); - mMoveLeftButton.setPrivateMode(aPrivateMode); - mMoveRightButton.setPrivateMode(aPrivateMode); - mCloseButton.setBackground(getContext().getDrawable(aPrivateMode ? R.drawable.fullscreen_button_private : R.drawable.fullscreen_button)); - mMoveLeftButton.setBackground(getContext().getDrawable(aPrivateMode ? R.drawable.fullscreen_button_private_first : R.drawable.fullscreen_button_first)); - mMoveRightButton.setBackground(getContext().getDrawable(aPrivateMode ? R.drawable.fullscreen_button_private_last : R.drawable.fullscreen_button_last)); + @Override + public void releaseWidget() { + detachFromWindow(); + + mAttachedWindow = null; + super.releaseWidget(); } - @Override - public void setVisible(boolean aIsVisible) { - if (mVisible == aIsVisible || mWidgetManager == null) { - return; - } - mVisible = aIsVisible; - getPlacement().visible = aIsVisible; + Observer mIsVisible = isVisible -> { + mWidgetPlacement.visible = isVisible.get(); if (!mWidgetAdded) { - mWidgetManager.addWidget(this); + mWidgetManager.addWidget(TopBarWidget.this); mWidgetAdded = true; } else { - mWidgetManager.updateWidget(this); + mWidgetManager.updateWidget(TopBarWidget.this); } - } - - public void setClearMode(boolean showClear) { - mMultiWindowControlsContainer.setVisibility(showClear ? GONE : VISIBLE); - mClearButton.setVisibility(showClear ? VISIBLE : GONE); - } + }; public void setDelegate(TopBarWidget.Delegate aDelegate) { mDelegate = aDelegate; } - public void setMoveLeftButtonEnabled(boolean aEnabled) { - mMoveLeftButton.setEnabled(aEnabled); - } - - public void setMoveRightButtonEnabled(boolean aEnabled) { - mMoveRightButton.setEnabled(aEnabled); - } - - // WidgetManagerDelegate.UpdateListener - - @Override - public void onWidgetUpdate(Widget aWidget) { - if (aWidget != mAttachedWindow) { - return; - } - } - } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java index afea26143..f153cfe19 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java @@ -8,23 +8,32 @@ import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import androidx.annotation.NonNull; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ObservableBoolean; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.geckoview.GeckoSession; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserActivity; import org.mozilla.vrbrowser.audio.AudioEngine; import org.mozilla.vrbrowser.browser.BookmarksStore; import org.mozilla.vrbrowser.browser.SessionChangeListener; import org.mozilla.vrbrowser.browser.engine.Session; import org.mozilla.vrbrowser.browser.engine.SessionStore; +import org.mozilla.vrbrowser.databinding.TrayBinding; +import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel; import org.mozilla.vrbrowser.ui.views.UIButton; import org.mozilla.vrbrowser.ui.widgets.settings.SettingsWidget; @@ -32,18 +41,13 @@ import java.util.Arrays; import java.util.List; -public class TrayWidget extends UIWidget implements SessionChangeListener, WindowWidget.BookmarksViewDelegate, - WindowWidget.HistoryViewDelegate, WidgetManagerDelegate.UpdateListener { +public class TrayWidget extends UIWidget implements SessionChangeListener, WidgetManagerDelegate.UpdateListener { private static final int ICON_ANIMATION_DURATION = 200; private static final int LIBRARY_NOTIFICATION_DURATION = 3000; - private UIButton mAddWindowButton; - private UIButton mSettingsButton; - private UIButton mPrivateButton; - private UIButton mBookmarksButton; - private UIButton mHistoryButton; - private UIButton mTabsButton; + private WindowViewModel mViewModel; + private TrayBinding mBinding; private AudioEngine mAudio; private int mSettingsDialogHandle = -1; private boolean mIsLastSessionPrivate; @@ -55,6 +59,7 @@ public class TrayWidget extends UIWidget implements SessionChangeListener, Windo private Session mSession; private WindowWidget mAttachedWindow; private TooltipWidget mLibraryNotification; + private boolean mAddWindowVisible; public TrayWidget(Context aContext) { super(aContext); @@ -72,16 +77,29 @@ public TrayWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { } private void initialize(Context aContext) { - inflate(aContext, R.layout.tray, this); + updateUI(); mTrayListeners = new ArrayList<>(); mMinPadding = WidgetPlacement.pixelDimension(getContext(), R.dimen.tray_icon_padding_min); mMaxPadding = WidgetPlacement.pixelDimension(getContext(), R.dimen.tray_icon_padding_max); - mPrivateButton = findViewById(R.id.privateButton); - mPrivateButton.setOnHoverListener(mButtonScaleHoverListener); - mPrivateButton.setOnClickListener(view -> { + mAudio = AudioEngine.fromContext(aContext); + + mIsLastSessionPrivate = false; + + mWidgetManager.addUpdateListener(this); + } + + public void updateUI() { + LayoutInflater inflater = LayoutInflater.from(getContext()); + + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.tray, this, true); + mBinding.setLifecycleOwner((VRBrowserActivity)getContext()); + + mBinding.privateButton.setOnHoverListener(mButtonScaleHoverListener); + mBinding.privateButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -89,11 +107,10 @@ private void initialize(Context aContext) { notifyPrivateBrowsingClicked(); view.requestFocusFromTouch(); }); - mPrivateButton.setCurvedTooltip(false); + mBinding.privateButton.setCurvedTooltip(false); - mSettingsButton = findViewById(R.id.settingsButton); - mSettingsButton.setOnHoverListener(mButtonScaleHoverListener); - mSettingsButton.setOnClickListener(view -> { + mBinding.settingsButton.setOnHoverListener(mButtonScaleHoverListener); + mBinding.settingsButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -103,11 +120,10 @@ private void initialize(Context aContext) { view.requestFocusFromTouch(); } }); - mSettingsButton.setCurvedTooltip(false); + mBinding.settingsButton.setCurvedTooltip(false); - mBookmarksButton = findViewById(R.id.bookmarksButton); - mBookmarksButton.setOnHoverListener(mButtonScaleHoverListener); - mBookmarksButton.setOnClickListener(view -> { + mBinding.bookmarksButton.setOnHoverListener(mButtonScaleHoverListener); + mBinding.bookmarksButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -115,11 +131,10 @@ private void initialize(Context aContext) { notifyBookmarksClicked(); view.requestFocusFromTouch(); }); - mBookmarksButton.setCurvedTooltip(false); + mBinding.bookmarksButton.setCurvedTooltip(false); - mHistoryButton = findViewById(R.id.historyButton); - mHistoryButton.setOnHoverListener(mButtonScaleHoverListener); - mHistoryButton.setOnClickListener(view -> { + mBinding.historyButton.setOnHoverListener(mButtonScaleHoverListener); + mBinding.historyButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -127,11 +142,10 @@ private void initialize(Context aContext) { notifyHistoryClicked(); view.requestFocusFromTouch(); }); - mHistoryButton.setCurvedTooltip(false); + mBinding.historyButton.setCurvedTooltip(false); - mTabsButton = findViewById(R.id.tabsButton); - mTabsButton.setOnHoverListener(mButtonScaleHoverListener); - mTabsButton.setOnClickListener(view -> { + mBinding.tabsButton.setOnHoverListener(mButtonScaleHoverListener); + mBinding.tabsButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -139,11 +153,10 @@ private void initialize(Context aContext) { view.requestFocusFromTouch(); notifyTabsClicked(); }); - mHistoryButton.setCurvedTooltip(false); + mBinding.tabsButton.setCurvedTooltip(false); - mAddWindowButton = findViewById(R.id.addwindowButton); - mAddWindowButton.setOnHoverListener(mButtonScaleHoverListener); - mAddWindowButton.setOnClickListener(view -> { + mBinding.addwindowButton.setOnHoverListener(mButtonScaleHoverListener); + mBinding.addwindowButton.setOnClickListener(view -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); } @@ -152,13 +165,16 @@ private void initialize(Context aContext) { notifyAddWindowClicked(); }); - mAddWindowButton.setCurvedTooltip(false); + mBinding.addwindowButton.setCurvedTooltip(false); - mAudio = AudioEngine.fromContext(aContext); + updateState(); + } - mIsLastSessionPrivate = false; + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - mWidgetManager.addUpdateListener(this); + updateUI(); } private OnHoverListener mButtonScaleHoverListener = (view, motionEvent) -> { @@ -254,9 +270,9 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.height = WidgetPlacement.dpDimension(context, R.dimen.tray_height); aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.tray_world_width); aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.tray_world_y) - - WidgetPlacement.unitFromMeters(context, R.dimen.window_world_y); + WidgetPlacement.unitFromMeters(context, R.dimen.window_world_y); aPlacement.translationZ = WidgetPlacement.unitFromMeters(context, R.dimen.tray_world_z) - - WidgetPlacement.unitFromMeters(context, R.dimen.window_world_z); + WidgetPlacement.unitFromMeters(context, R.dimen.window_world_z); aPlacement.anchorX = 0.5f; aPlacement.anchorY = 0.5f; aPlacement.parentAnchorX = 0.5f; @@ -290,8 +306,8 @@ public void show(@ShowFlags int aShowFlags) { @Override public void hide(@HideFlags int aHideFlags) { - hideNotification(mBookmarksButton); - hideNotification(mTabsButton); + hideNotification(mBinding.bookmarksButton); + hideNotification(mBinding.tabsButton); if (mWidgetPlacement.visible) { mWidgetPlacement.visible = false; @@ -305,22 +321,47 @@ public void hide(@HideFlags int aHideFlags) { @Override public void detachFromWindow() { - hideNotification(mBookmarksButton); - hideNotification(mTabsButton); - + hideNotification(mBinding.bookmarksButton); + hideNotification(mBinding.tabsButton); + if (mSession != null) { mSession.removeSessionChangeListener(this); mSession = null; } if (mAttachedWindow != null) { SessionStore.get().getBookmarkStore().addListener(mBookmarksListener); - mAttachedWindow.removeBookmarksViewListener(this); - mAttachedWindow.removeHistoryViewListener(this); } mWidgetPlacement.parentHandle = -1; + if (mViewModel != null) { + mViewModel.getIsBookmraksVisible().removeObserver(mBookmarksVisibleObserver); + mViewModel.getIsHistoryVisible().removeObserver(mHistoryVisibleObserver); + mViewModel = null; + } } + Observer mBookmarksVisibleObserver = isBookmarksVisible -> { + if (isBookmarksVisible.get()) { + mBinding.bookmarksButton.setTooltip(getResources().getString(R.string.close_bookmarks_tooltip)); + mBinding.bookmarksButton.setActiveMode(true); + + } else { + mBinding.bookmarksButton.setTooltip(getResources().getString(R.string.open_bookmarks_tooltip)); + mBinding.bookmarksButton.setActiveMode(false); + } + }; + + Observer mHistoryVisibleObserver = isHistoryVisible -> { + if (isHistoryVisible.get()) { + mBinding.historyButton.setTooltip(getResources().getString(R.string.close_history_tooltip)); + mBinding.historyButton.setActiveMode(true); + + } else { + mBinding.historyButton.setTooltip(getResources().getString(R.string.open_history_tooltip)); + mBinding.historyButton.setActiveMode(false); + } + }; + @Override public void attachToWindow(@NonNull WindowWidget aWindow) { if (mAttachedWindow == aWindow) { @@ -330,27 +371,24 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { mAttachedWindow = aWindow; mWidgetPlacement.parentHandle = aWindow.getHandle(); - mAttachedWindow.addBookmarksViewListener(this); - mAttachedWindow.addHistoryViewListener(this); + + // ModelView creation and observers setup + mViewModel = new ViewModelProvider( + (VRBrowserActivity)getContext(), + ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication())) + .get(String.valueOf(mAttachedWindow.hashCode()), WindowViewModel.class); + + mBinding.setViewmodel(mViewModel); + + mViewModel.getIsBookmraksVisible().observe((VRBrowserActivity)getContext(), mBookmarksVisibleObserver); + mViewModel.getIsHistoryVisible().observe((VRBrowserActivity)getContext(), mHistoryVisibleObserver); SessionStore.get().getBookmarkStore().addListener(mBookmarksListener); mSession = aWindow.getSession(); if (mSession != null) { mSession.addSessionChangeListener(this); - handleSessionState(); - } - - if (mAttachedWindow.isBookmarksVisible()) { - onBookmarksShown(aWindow); - } else { - onBookmarksHidden(aWindow); - } - - if (mAttachedWindow.isHistoryVisible()) { - onHistoryViewShown(aWindow); - } else { - onHistoryViewHidden(aWindow); + handleSessionState(false); } } @@ -358,24 +396,33 @@ public void attachToWindow(@NonNull WindowWidget aWindow) { @Override public void onCurrentSessionChange(GeckoSession aOldSession, GeckoSession aSession) { - handleSessionState(); + handleSessionState(false); + } + + private void updateState() { + handleSessionState(true); + setAddWindowVisible(mAddWindowVisible); } - private void handleSessionState() { + private void handleSessionState(boolean refresh) { if (mSession != null) { boolean isPrivateMode = mSession.isPrivateMode(); - if (isPrivateMode != mIsLastSessionPrivate) { - mPrivateButton.setPrivateMode(isPrivateMode); + if (isPrivateMode != mIsLastSessionPrivate || refresh) { + mBinding.privateButton.setPrivateMode(isPrivateMode); if (isPrivateMode) { - mWidgetManager.pushWorldBrightness(this, WidgetManagerDelegate.DEFAULT_DIM_BRIGHTNESS); - mPrivateButton.setImageResource(R.drawable.ic_icon_tray_private_browsing_on_v2); - mPrivateButton.setTooltip(getResources().getString(R.string.private_browsing_exit_tooltip)); + if (!refresh) { + mWidgetManager.pushWorldBrightness(this, WidgetManagerDelegate.DEFAULT_DIM_BRIGHTNESS); + } + mBinding.privateButton.setImageResource(R.drawable.ic_icon_tray_private_browsing_on_v2); + mBinding.privateButton.setTooltip(getResources().getString(R.string.private_browsing_exit_tooltip)); } else { - mWidgetManager.popWorldBrightness(this); - mPrivateButton.setImageResource(R.drawable.ic_icon_tray_private_browsing_v2); - mPrivateButton.setTooltip(getResources().getString(R.string.private_browsing_enter_tooltip)); + if (!refresh) { + mWidgetManager.popWorldBrightness(this); + } + mBinding.privateButton.setImageResource(R.drawable.ic_icon_tray_private_browsing_v2); + mBinding.privateButton.setTooltip(getResources().getString(R.string.private_browsing_enter_tooltip)); } } @@ -398,7 +445,7 @@ public void toggleSettingsDialog(@NonNull SettingsWidget.SettingDialog settingDi widget.getPlacement().parentHandle = mAttachedWindow.getHandle(); } if (widget.isVisible()) { - widget.hide(REMOVE_WIDGET); + widget.hide(KEEP_WIDGET); } else { ((SettingsWidget)widget).show(REQUEST_FOCUS, settingDialog); } @@ -445,46 +492,20 @@ public boolean isDialogOpened(int aHandle) { } public void setAddWindowVisible(boolean aVisible) { - mAddWindowButton.setVisibility(aVisible ? View.VISIBLE : View.GONE); + mAddWindowVisible = aVisible; + + mBinding.addwindowButton.setVisibility(aVisible ? View.VISIBLE : View.GONE); if (aVisible) { - mTabsButton.updateBackgrounds(R.drawable.tray_background_unchecked_middle, + mBinding.tabsButton.updateBackgrounds(R.drawable.tray_background_unchecked_middle, R.drawable.tray_background_middle_private, R.drawable.tray_background_checked_middle); } else { - mTabsButton.updateBackgrounds(R.drawable.tray_background_unchecked_start, + mBinding.tabsButton.updateBackgrounds(R.drawable.tray_background_unchecked_start, R.drawable.tray_background_start_private, R.drawable.tray_background_checked_start); } } - // BookmarksViewListener - - @Override - public void onBookmarksShown(WindowWidget aWindow) { - mBookmarksButton.setTooltip(getResources().getString(R.string.close_bookmarks_tooltip)); - mBookmarksButton.setActiveMode(true); - } - - @Override - public void onBookmarksHidden(WindowWidget aWindow) { - mBookmarksButton.setTooltip(getResources().getString(R.string.open_bookmarks_tooltip)); - mBookmarksButton.setActiveMode(false); - } - - // HistoryViewListener - - @Override - public void onHistoryViewShown(WindowWidget aWindow) { - mHistoryButton.setTooltip(getResources().getString(R.string.close_history_tooltip)); - mHistoryButton.setActiveMode(true); - } - - @Override - public void onHistoryViewHidden(WindowWidget aWindow) { - mHistoryButton.setTooltip(getResources().getString(R.string.open_history_tooltip)); - mHistoryButton.setActiveMode(false); - } - // WidgetManagerDelegate.UpdateListener @Override @@ -501,13 +522,13 @@ public void onWidgetUpdate(Widget aWidget) { } public void showTabAddedNotification() { - mTabsButton.setNotificationMode(true); - ThreadUtils.postToUiThread(() -> showNotification(mTabsButton, R.string.tab_added_notification)); + mBinding.tabsButton.setNotificationMode(true); + ThreadUtils.postToUiThread(() -> showNotification(mBinding.tabsButton, R.string.tab_added_notification)); } public void showTabSentNotification() { - mTabsButton.setNotificationMode(true); - ThreadUtils.postToUiThread(() -> showNotification(mTabsButton, R.string.tab_sent_notification)); + mBinding.tabsButton.setNotificationMode(true); + ThreadUtils.postToUiThread(() -> showNotification(mBinding.tabsButton, R.string.tab_sent_notification)); } private BookmarksStore.BookmarkListener mBookmarksListener = new BookmarksStore.BookmarkListener() { @@ -518,8 +539,8 @@ public void onBookmarksUpdated() { @Override public void onBookmarkAdded() { - mBookmarksButton.setNotificationMode(true); - ThreadUtils.postToUiThread(() -> showNotification(mBookmarksButton, R.string.bookmarks_saved_notification)); + mBinding.bookmarksButton.setNotificationMode(true); + ThreadUtils.postToUiThread(() -> showNotification(mBinding.bookmarksButton, R.string.bookmarks_saved_notification)); } }; @@ -551,7 +572,6 @@ private void showNotification(UIButton button, int stringRes) { private void hideNotification(UIButton button) { if (mLibraryNotification != null) { mLibraryNotification.hide(UIWidget.REMOVE_WIDGET); - mLibraryNotification = null; } button.setNotificationMode(false); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java index 4affab3ec..0c3a38cd6 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.SurfaceTexture; @@ -17,6 +18,9 @@ import android.view.ViewParent; import android.widget.FrameLayout; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; + import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.browser.SettingsStore; import org.mozilla.vrbrowser.utils.SystemUtils; @@ -24,9 +28,6 @@ import java.lang.reflect.Constructor; import java.util.HashMap; -import androidx.annotation.IntDef; -import androidx.annotation.NonNull; - public abstract class UIWidget extends FrameLayout implements Widget { protected final String LOGTAG = SystemUtils.createLogtag(this.getClass()); @@ -57,6 +58,7 @@ public UIWidget(Context aContext) { initialize(); } + public UIWidget(Context aContext, AttributeSet aAttrs) { super(aContext, aAttrs); initialize(); @@ -94,6 +96,10 @@ public void onPause() { public void onResume() { } + @Override + public void onConfigurationChanged(Configuration newConfig) { + } + @Override public void resizeByMultiplier(float aspect, float multiplier) { // To be implemented by inheriting widgets diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java index f96fa4974..b812515c1 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java @@ -5,6 +5,7 @@ package org.mozilla.vrbrowser.ui.widgets; +import android.content.res.Configuration; import android.graphics.SurfaceTexture; import android.view.MotionEvent; import android.view.Surface; @@ -17,6 +18,7 @@ public interface Widget { void onPause(); void onResume(); + void onConfigurationChanged(Configuration newConfig); void setSurfaceTexture(SurfaceTexture aTexture, final int aWidth, final int aHeight, Runnable aFirstDrawCallback); void setSurface(Surface aSurface, final int aWidth, final int aHeight, Runnable aFirstDrawCallback); void resizeSurface(final int aWidth, final int aHeight); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java index 7b9437386..03a01565b 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java @@ -1,5 +1,6 @@ package org.mozilla.vrbrowser.ui.widgets; +import android.content.Context; import android.view.View; import androidx.annotation.IntDef; @@ -88,4 +89,5 @@ interface WorldClickListener { void addConnectivityListener(ConnectivityReceiver.Delegate aListener); void removeConnectivityListener(ConnectivityReceiver.Delegate aListener); void saveState(); + void updateLocale(@NonNull Context context); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java index 0c6cd4935..2b8d6c19f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PointF; @@ -27,12 +28,17 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.UiThread; +import androidx.lifecycle.ViewModelProvider; +import org.mozilla.geckoview.AllowOrDeny; import org.mozilla.geckoview.GeckoResult; import org.mozilla.geckoview.GeckoSession; +import org.mozilla.geckoview.MediaElement; import org.mozilla.geckoview.PanZoomController; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserActivity; import org.mozilla.vrbrowser.VRBrowserApplication; +import org.mozilla.vrbrowser.browser.Media; import org.mozilla.vrbrowser.browser.PromptDelegate; import org.mozilla.vrbrowser.browser.SessionChangeListener; import org.mozilla.vrbrowser.browser.SettingsStore; @@ -45,6 +51,7 @@ import org.mozilla.vrbrowser.ui.callbacks.BookmarksCallback; import org.mozilla.vrbrowser.ui.callbacks.HistoryCallback; import org.mozilla.vrbrowser.ui.callbacks.LibraryItemContextMenuClickCallback; +import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel; import org.mozilla.vrbrowser.ui.views.BookmarksView; import org.mozilla.vrbrowser.ui.views.HistoryView; import org.mozilla.vrbrowser.ui.widgets.dialogs.ClearHistoryDialogWidget; @@ -55,7 +62,6 @@ import org.mozilla.vrbrowser.ui.widgets.settings.SettingsWidget; import org.mozilla.vrbrowser.utils.ViewUtils; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -75,16 +81,6 @@ public class WindowWidget extends UIWidget implements SessionChangeListener, GeckoSession.ContentDelegate, GeckoSession.NavigationDelegate, VideoAvailabilityListener, GeckoSession.HistoryDelegate, GeckoSession.ProgressDelegate, GeckoSession.SelectionActionDelegate { - public interface HistoryViewDelegate { - default void onHistoryViewShown(WindowWidget aWindow) {} - default void onHistoryViewHidden(WindowWidget aWindow) {} - } - - public interface BookmarksViewDelegate { - default void onBookmarksShown(WindowWidget aWindow) {} - default void onBookmarksHidden(WindowWidget aWindow) {} - } - @IntDef(value = { SESSION_RELEASE_DISPLAY, SESSION_DO_NOT_RELEASE_DISPLAY}) public @interface OldSessionDisplayAction {} public static final int SESSION_RELEASE_DISPLAY = 0; @@ -116,8 +112,6 @@ default void onBookmarksHidden(WindowWidget aWindow) {} private int mWindowId; private BookmarksView mBookmarksView; private HistoryView mHistoryView; - private ArrayList mBookmarksViewListeners; - private ArrayList mHistoryViewListeners; private Windows.WindowPlacement mWindowPlacement = Windows.WindowPlacement.FRONT; private Windows.WindowPlacement mWindowPlacementBeforeFullscreen = Windows.WindowPlacement.FRONT; private float mMaxWindowScale = 3; @@ -136,6 +130,7 @@ default void onBookmarksHidden(WindowWidget aWindow) {} private boolean mCaptureOnPageStop; private PromptDelegate mPromptDelegate; private Executor mUIThreadExecutor; + private WindowViewModel mViewModel; public interface WindowListener { default void onFocusRequest(@NonNull WindowWidget aWindow) {} @@ -163,6 +158,13 @@ private void initialize(Context aContext) { mWidgetManager = (WidgetManagerDelegate) aContext; mBorderWidth = SettingsStore.getInstance(aContext).getTransparentBorderWidth(); + // ModelView creation and observers setup + mViewModel = new ViewModelProvider( + (VRBrowserActivity)getContext(), + ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication())) + .get(String.valueOf(hashCode()), WindowViewModel.class); + mViewModel.setIsPrivateSession(mSession.isPrivateMode()); + mUIThreadExecutor = ((VRBrowserApplication)getContext().getApplicationContext()).getExecutors().mainThread(); mListeners = new CopyOnWriteArrayList<>(); @@ -170,11 +172,9 @@ private void initialize(Context aContext) { mBookmarksView = new BookmarksView(aContext); mBookmarksView.addBookmarksListener(mBookmarksListener); - mBookmarksViewListeners = new ArrayList<>(); mHistoryView = new HistoryView(aContext); mHistoryView.addHistoryListener(mHistoryListener); - mHistoryViewListeners = new ArrayList<>(); mHandle = ((WidgetManagerDelegate)aContext).newWidgetHandle(); mWidgetPlacement = new WidgetPlacement(aContext); @@ -308,6 +308,22 @@ public void onResume() { } } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + mHistoryView.updateUI(); + mBookmarksView.updateUI(); + + if (mView != null) { + View temp = mView; + unsetView(mView, false); + setView(temp, false); + } + + mViewModel.refresh(); + } + public void close() { TelemetryWrapper.closeWindowEvent(mWindowId); GleanMetricsService.closeWindowEvent(mWindowId); @@ -315,12 +331,16 @@ public void close() { releaseWidget(); mBookmarksView.onDestroy(); mHistoryView.onDestroy(); + mViewModel.setIsTopBarVisible(false); + mViewModel.setIsTitleBarVisible(false); SessionStore.get().destroySession(mSession); if (mTopBar != null) { mWidgetManager.removeWidget(mTopBar); + mTopBar.setDelegate((TopBarWidget.Delegate) null); } if (mTitleBar != null) { mWidgetManager.removeWidget(mTitleBar); + mTitleBar.setDelegate((TitleBarWidget.Delegate) null); } mListeners.clear(); } @@ -411,22 +431,6 @@ public int getWindowHeight() { return mWidgetPlacement.height; } - public void addBookmarksViewListener(@NonNull BookmarksViewDelegate listener) { - mBookmarksViewListeners.add(listener); - } - - public void removeBookmarksViewListener(@NonNull BookmarksViewDelegate listener) { - mBookmarksViewListeners.remove(listener); - } - - public void addHistoryViewListener(@NonNull HistoryViewDelegate listener) { - mHistoryViewListeners.add(listener); - } - - public void removeHistoryViewListener(@NonNull HistoryViewDelegate listener) { - mHistoryViewListeners.remove(listener); - } - public void switchBookmarks() { if (isHistoryVisible()) { hideHistory(false); @@ -448,13 +452,9 @@ public void showBookmarks(boolean switchSurface) { if (mView == null) { setView(mBookmarksView, switchSurface); mBookmarksView.onShow(); - for (BookmarksViewDelegate listener : mBookmarksViewListeners) { - listener.onBookmarksShown(this); - } + mViewModel.setIsBookmarksVisible(true); mIsBookmarksVisible = true; } - - updateTitleBar(); } public void hideBookmarks() { @@ -464,9 +464,7 @@ public void hideBookmarks() { public void hideBookmarks(boolean switchSurface) { if (mView != null) { unsetView(mBookmarksView, switchSurface); - for (BookmarksViewDelegate listener : mBookmarksViewListeners) { - listener.onBookmarksHidden(this); - } + mViewModel.setIsBookmarksVisible(false); mIsBookmarksVisible = false; } } @@ -500,9 +498,7 @@ public void showHistory(boolean switchSurface) { if (mView == null) { setView(mHistoryView, switchSurface); mHistoryView.onShow(); - for (HistoryViewDelegate listener : mHistoryViewListeners) { - listener.onHistoryViewShown(this); - } + mViewModel.setIsHistoryVisible(true); mIsHistoryVisible = true; } } @@ -514,9 +510,7 @@ public void hideHistory() { public void hideHistory(boolean switchSurface) { if (mView != null) { unsetView(mHistoryView, switchSurface); - for (HistoryViewDelegate listener : mHistoryViewListeners) { - listener.onHistoryViewHidden(this); - } + mViewModel.setIsHistoryVisible(false); mIsHistoryVisible = false; } } @@ -580,12 +574,18 @@ public void setWindowPlacement(@NonNull Windows.WindowPlacement aPlacement) { mWindowPlacement = aPlacement; + mViewModel.setPlacement(mWindowPlacement); + if (mActive) { TelemetryWrapper.activePlacementEvent(mWindowPlacement.getValue(), true); } } - public @NonNull Windows.WindowPlacement getmWindowPlacementBeforeFullscreen() { + public void setIsOnlyWindow(boolean isOnlyWindow) { + mViewModel.setIsOnlyWindow(isOnlyWindow); + } + + public @NonNull Windows.WindowPlacement getWindowPlacementBeforeFullscreen() { return mWindowPlacementBeforeFullscreen; } @@ -626,59 +626,14 @@ public void setActiveWindow(boolean active) { session.getTextInput().setView(this); } mSession.updateLastUse(); - } else { - updateTitleBar(); } - updateTitleBarMediaStatus(); hideContextMenus(); TelemetryWrapper.activePlacementEvent(mWindowPlacement.getValue(), mActive); updateBorder(); - } - - private void updateTitleBar() { - if (isBookmarksVisible()) { - updateTitleBarUrl(getResources().getString(R.string.url_bookmarks_title)); - - } else if (isHistoryVisible()) { - updateTitleBarUrl(getResources().getString(R.string.url_history_title)); - - } else { - updateTitleBarUrl(mSession.getCurrentUri()); - } - } - - private void updateTitleBarUrl(String url) { - if (mTitleBar != null && url != null) { - mTitleBar.setIsInsecure(!mSession.isSecure()); - if (url.startsWith("data") && mSession.isPrivateMode()) { - mTitleBar.setInsecureVisibility(GONE); - mTitleBar.setURL(getResources().getString(R.string.private_browsing_title)); - - } else if (url.equals(mSession.getHomeUri())) { - mTitleBar.setInsecureVisibility(GONE); - mTitleBar.setURL(getResources().getString(R.string.url_home_title, getResources().getString(R.string.app_name))); - - } else if (url.equals(getResources().getString(R.string.url_bookmarks_title)) || - url.equals(getResources().getString(R.string.url_history_title))) { - mTitleBar.setInsecureVisibility(GONE); - mTitleBar.setURL(url); - - } else if (url.equals(getResources().getString(R.string.about_blank))) { - mTitleBar.setInsecureVisibility(GONE); - mTitleBar.setURL(""); - - } else { - mTitleBar.setURL(url); - } - } - } - public void updateTitleBarMediaStatus() { - if (mTitleBar != null) { - mTitleBar.updateMediaStatus(); - } + mViewModel.setIsActiveWindow(active); } @Nullable @@ -697,6 +652,10 @@ public void setTopBar(TopBarWidget aWidget) { } } + public void setResizeMode(boolean resizing) { + mViewModel.setIsResizeMode(resizing); + } + public TitleBarWidget getTitleBar() { return mTitleBar; } @@ -894,6 +853,7 @@ public boolean isResizing() { public void setIsFullScreen(boolean isFullScreen) { if (isFullScreen != mIsFullScreen) { mIsFullScreen = isFullScreen; + mViewModel.setIsFullscreen(isFullScreen); for (WindowListener listener: mListeners) { listener.onFullScreen(this, isFullScreen); } @@ -1021,6 +981,8 @@ public void setVisible(boolean aVisible) { if (!aVisible) { clearFocus(); } + + mViewModel.setIsWindowVisible(aVisible); } @Override @@ -1045,6 +1007,8 @@ public void setSession(@NonNull Session aSession, @OldSessionDisplayAction int a } mSession = aSession; + mViewModel.setIsPrivateSession(mSession.isPrivateMode()); + if (oldSession != null) { onCurrentSessionChange(oldSession.getGeckoSession(), aSession.getGeckoSession()); } else { @@ -1084,12 +1048,8 @@ public void onCurrentSessionChange(GeckoSession aOldSession, GeckoSession aSessi callSurfaceChanged(); aSession.getTextInput().setView(this); - boolean isPrivateMode = aSession.getSettings().getUsePrivateMode(); - if (isPrivateMode) { - setPrivateBrowsingEnabled(true); - } else { - setPrivateBrowsingEnabled(false); - } + mViewModel.setIsPrivateSession(aSession.getSettings().getUsePrivateMode()); + waitForFirstPaint(); } @@ -1200,9 +1160,6 @@ public boolean onGenericMotionEvent(MotionEvent aEvent) { } } - private void setPrivateBrowsingEnabled(boolean isEnabled) { - } - public void showAlert(String title, @NonNull String msg, @Nullable PromptDialogWidget.Delegate callback) { if (mAlertDialog == null) { mAlertDialog = new PromptDialogWidget(getContext()); @@ -1219,6 +1176,8 @@ public void showAlert(String title, @NonNull String msg, @Nullable PromptDialogW if (callback != null) { callback.onButtonClicked(index); } + mAlertDialog.releaseWidget(); + mAlertDialog = null; }); mAlertDialog.show(REQUEST_FOCUS); } @@ -1226,7 +1185,7 @@ public void showAlert(String title, @NonNull String msg, @Nullable PromptDialogW public void showConfirmPrompt(String title, @NonNull String msg, @NonNull String[] btnMsg, @Nullable PromptDialogWidget.Delegate callback) { if (mConfirmDialog == null) { mConfirmDialog = new PromptDialogWidget(getContext()); - mAlertDialog.setButtons(new int[] { + mConfirmDialog.setButtons(new int[] { R.string.cancel_button, R.string.ok_button }); @@ -1236,11 +1195,13 @@ public void showConfirmPrompt(String title, @NonNull String msg, @NonNull String mConfirmDialog.setTitle(title); mConfirmDialog.setBody(msg); mConfirmDialog.setButtons(btnMsg); - mAlertDialog.setButtonsDelegate(index -> { - mAlertDialog.hide(REMOVE_WIDGET); + mConfirmDialog.setButtonsDelegate(index -> { + mConfirmDialog.hide(REMOVE_WIDGET); if (callback != null) { callback.onButtonClicked(index); } + mConfirmDialog.releaseWidget(); + mConfirmDialog = null; }); mConfirmDialog.show(REQUEST_FOCUS); } @@ -1259,12 +1220,15 @@ public void showDialog(@NonNull String title, @NonNull @StringRes int descripti if (buttonsCallback != null) { buttonsCallback.onButtonClicked(index); } + mAppDialog.releaseWidget(); }); mAppDialog.setLinkDelegate(() -> { mAppDialog.hide(REMOVE_WIDGET); if (linkCallback != null) { linkCallback.run(); } + mAppDialog.releaseWidget(); + mAppDialog = null; }); mAppDialog.show(REQUEST_FOCUS); } @@ -1532,22 +1496,68 @@ public void onFirstContentfulPaint(@NonNull GeckoSession session) { // VideoAvailabilityListener + private Media mMedia; + @Override public void onVideoAvailabilityChanged(boolean aVideosAvailable) { - if (mTitleBar != null) { - mTitleBar.mediaAvailabilityChanged(aVideosAvailable); + boolean mediaAvailable; + if (mSession != null) { + if (mMedia != null) { + mMedia.removeMediaListener(mMediaDelegate); + } + + mMedia = mSession.getFullScreenVideo(); + if (aVideosAvailable && mMedia != null) { + mMedia.addMediaListener(mMediaDelegate); + mediaAvailable = true; + + } else { + mediaAvailable = false; + } + + } else { + mediaAvailable = false; } - for (WindowListener listener: mListeners) { - listener.onVideoAvailabilityChanged(this); + if (mediaAvailable) { + if (mSession.getFullScreenVideo().isPlayed()) { + mViewModel.setIsMediaAvailable(true); + mViewModel.setIsMediaPlaying(true); + } + + } else { + mMedia = null; + mViewModel.setIsMediaAvailable(false); + mViewModel.setIsMediaPlaying(false); } } + MediaElement.Delegate mMediaDelegate = new MediaElement.Delegate() { + @Override + public void onPlaybackStateChange(@NonNull MediaElement mediaElement, int state) { + switch(state) { + case MediaElement.MEDIA_STATE_PLAY: + case MediaElement.MEDIA_STATE_PLAYING: + mViewModel.setIsMediaAvailable(true); + mViewModel.setIsMediaPlaying(true); + break; + case MediaElement.MEDIA_STATE_PAUSE: + mViewModel.setIsMediaAvailable(true); + mViewModel.setIsMediaPlaying(false); + break; + case MediaElement.MEDIA_STATE_ABORT: + case MediaElement.MEDIA_STATE_EMPTIED: + mViewModel.setIsMediaAvailable(false); + mViewModel.setIsMediaPlaying(false); + } + } + }; + // GeckoSession.NavigationDelegate @Override - public void onPageStart(@NonNull GeckoSession geckoSession, @NonNull String s) { + public void onPageStart(@NonNull GeckoSession geckoSession, @NonNull String aUri) { mCaptureOnPageStop = true; if (isHistoryVisible()) { @@ -1557,6 +1567,9 @@ public void onPageStart(@NonNull GeckoSession geckoSession, @NonNull String s) { if (isBookmarksVisible()) { hideBookmarks(); } + + mViewModel.setUrl(aUri); + mViewModel.setIsLoading(true); } @Override @@ -1565,6 +1578,8 @@ public void onPageStop(@NonNull GeckoSession aSession, boolean b) { mCaptureOnPageStop = false; captureImage(); } + + mViewModel.setIsLoading(false); } public void captureImage() { @@ -1573,7 +1588,45 @@ public void captureImage() { @Override public void onLocationChange(@NonNull GeckoSession session, @Nullable String url) { - updateTitleBarUrl(url); + mViewModel.setUrl(url); + } + + @Override + public void onCanGoBack(@NonNull GeckoSession geckoSession, boolean canGoBack) { + mViewModel.setCanGoBack(canGoBack); + } + + @Override + public void onCanGoForward(@NonNull GeckoSession geckoSession, boolean canGoForward) { + mViewModel.setCanGoForward(canGoForward); + } + + @Override + public @Nullable GeckoResult onLoadRequest(GeckoSession aSession, @NonNull LoadRequest aRequest) { + final GeckoResult result = new GeckoResult<>(); + + Uri uri = Uri.parse(aRequest.uri); + if ("file".equalsIgnoreCase(uri.getScheme()) && + !mWidgetManager.isPermissionGranted(android.Manifest.permission.READ_EXTERNAL_STORAGE)) { + mWidgetManager.requestPermission( + aRequest.uri, + android.Manifest.permission.READ_EXTERNAL_STORAGE, + new GeckoSession.PermissionDelegate.Callback() { + @Override + public void grant() { + result.complete(AllowOrDeny.ALLOW); + } + + @Override + public void reject() { + result.complete(AllowOrDeny.DENY); + } + }); + return result; + } + + result.complete(AllowOrDeny.ALLOW); + return result; } // GeckoSession.HistoryDelegate @@ -1706,9 +1759,7 @@ public GeckoResult getVisited(@NonNull GeckoSession geckoSession, @No @Override public void onSecurityChange(GeckoSession geckoSession, SecurityInformation securityInformation) { - if (mTitleBar != null) { - mTitleBar.setIsInsecure(!securityInformation.isSecure); - } + mViewModel.setIsInsecure(!securityInformation.isSecure); } // GeckoSession.SelectionActionDelegate diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java index cfdf2e296..bdd52fdc9 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java @@ -65,7 +65,7 @@ public void load(WindowWidget aWindow, WindowsState aState, int aTabIndex) { WidgetPlacement widgetPlacement; if (aWindow.isFullScreen()) { widgetPlacement = aWindow.getBeforeFullscreenPlacement(); - placement = aWindow.getmWindowPlacementBeforeFullscreen(); + placement = aWindow.getWindowPlacementBeforeFullscreen(); } else if (aWindow.isResizing()) { widgetPlacement = aWindow.getBeforeResizePlacement(); placement = aWindow.getWindowPlacement(); @@ -156,7 +156,7 @@ public void saveState() { try (Writer writer = new FileWriter(file)) { WindowsState state = new WindowsState(); state.privateMode = mPrivateMode; - state.focusedWindowPlacement = mFocusedWindow.isFullScreen() ? mFocusedWindow.getmWindowPlacementBeforeFullscreen() : mFocusedWindow.getWindowPlacement(); + state.focusedWindowPlacement = mFocusedWindow.isFullScreen() ? mFocusedWindow.getWindowPlacementBeforeFullscreen() : mFocusedWindow.getWindowPlacement(); ArrayList sessions = SessionStore.get().getSortedSessions(false); state.tabs = sessions.stream().map(Session::getSessionState).collect(Collectors.toCollection(ArrayList::new)); for (WindowWidget window : mRegularWindows) { @@ -207,7 +207,7 @@ public WindowWidget getFocusedWindow() { return mFocusedWindow; } - @NonNull + @Nullable public WindowWidget addWindow() { if (getCurrentWindows().size() >= MAX_WINDOWS) { return null; @@ -389,11 +389,7 @@ public void focusWindow(@Nullable WindowWidget aWindow) { mFocusedWindow = aWindow; if (prev != null && getCurrentWindows().contains(prev)) { prev.setActiveWindow(false); - if (prev.isVisible()) { - prev.getTitleBar().setVisible(true); - } } - mFocusedWindow.getTitleBar().setVisible(false); mFocusedWindow.setActiveWindow(true); if (mDelegate != null) { mDelegate.onFocusedWindowChanged(mFocusedWindow, prev); @@ -518,7 +514,9 @@ public void enterPrivateMode() { if (mPrivateWindows.size() == 0) { WindowWidget window = addWindow(); - window.loadHome(); + if (window != null) { + window.loadHome(); + } } else { focusWindow(getWindowWithPlacement(mPrivateWindowPlacement)); @@ -662,11 +660,7 @@ private void removeWindow(@NonNull WindowWidget aWindow) { mWidgetManager.removeWidget(aWindow); mRegularWindows.remove(aWindow); mPrivateWindows.remove(aWindow); - aWindow.getTopBar().setVisible(false); - aWindow.getTopBar().setDelegate((TopBarWidget.Delegate) null); aWindow.removeWindowListener(this); - aWindow.getTitleBar().setVisible(false); - aWindow.getTitleBar().setDelegate((TitleBarWidget.Delegate) null); aWindow.close(); updateMaxWindowScales(); updateCurvedMode(true); @@ -683,8 +677,6 @@ private void setWindowVisible(@NonNull WindowWidget aWindow, boolean aVisible) { setFirstPaint(aWindow, aWindow.getSession()); } aWindow.setVisible(aVisible); - aWindow.getTopBar().setVisible(aVisible); - aWindow.getTitleBar().setVisible(aVisible); } private void placeWindow(@NonNull WindowWidget aWindow, WindowPlacement aPosition) { @@ -804,10 +796,11 @@ private void updateViews() { frontWindow.getPlacement().parentHandle = -1; } - updateTopBars(); - updateTitleBars(); - ArrayList windows = getCurrentWindows(); + for (WindowWidget window: windows) { + window.setIsOnlyWindow(windows.size() == 1); + } + // Sort windows so frontWindow is the first one. Required for proper native matrix updates. windows.sort((o1, o2) -> o1 == frontWindow ? -1 : 0); for (WindowWidget window: getCurrentWindows()) { @@ -817,44 +810,6 @@ private void updateViews() { } } - private void updateTopBars() { - ArrayList windows = getCurrentWindows(); - WindowWidget leftWindow = getLeftWindow(); - WindowWidget rightWindow = getRightWindow(); - boolean visible = mFullscreenWindow == null && (windows.size() > 1 || isInPrivateMode()); - for (WindowWidget window: windows) { - window.getTopBar().setVisible(visible); - window.getTopBar().setClearMode((windows.size() == 1 && isInPrivateMode())); - if (visible) { - window.getTopBar().setMoveLeftButtonEnabled(window != leftWindow); - window.getTopBar().setMoveRightButtonEnabled(window != rightWindow); - } - } - if (isInPrivateMode() && mPrivateWindows.size() == 1) { - if (mFocusedWindow != null) { - mFocusedWindow.getTopBar().setMoveLeftButtonEnabled(false); - mFocusedWindow.getTopBar().setMoveRightButtonEnabled(false); - } - } - } - - private void updateTitleBars() { - ArrayList windows = getCurrentWindows(); - for (WindowWidget window: windows) { - if (window == mFocusedWindow) { - window.getTitleBar().setVisible(false); - - } else { - if (mFullscreenWindow != null) { - window.getTitleBar().setVisible(false); - - } else { - window.getTitleBar().setVisible(true); - } - } - } - } - @NonNull private WindowWidget createWindow(@Nullable Session aSession) { int newWindowId = sIndex++; @@ -884,7 +839,7 @@ private WindowWidget createWindow(@Nullable Session aSession) { public void enterResizeMode() { if (mFullscreenWindow == null) { for (WindowWidget window : getCurrentWindows()) { - window.getTopBar().setVisible(false); + window.setResizeMode(true); } } } @@ -892,9 +847,7 @@ public void enterResizeMode() { public void exitResizeMode() { if (mFullscreenWindow == null) { for (WindowWidget window : getCurrentWindows()) { - if (getCurrentWindows().size() > 1 || isInPrivateMode()) { - window.getTopBar().setVisible(true); - } + window.setResizeMode(false); } } } @@ -1309,6 +1262,8 @@ public void onTabsReceived(@NonNull List aTabs) { mNoInternetDialog.setBody(R.string.no_internet_message); mNoInternetDialog.setButtonsDelegate(index -> { mNoInternetDialog.hide(UIWidget.REMOVE_WIDGET); + mNoInternetDialog.releaseWidget(); + mNoInternetDialog = null; }); } @@ -1317,6 +1272,8 @@ public void onTabsReceived(@NonNull List aTabs) { } else if (connected && mNoInternetDialog.isVisible()) { mNoInternetDialog.hide(UIWidget.REMOVE_WIDGET); + mNoInternetDialog.releaseWidget(); + mNoInternetDialog = null; } }; } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/ClearHistoryDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/ClearHistoryDialogWidget.java index aebda99a5..54e605392 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/ClearHistoryDialogWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/ClearHistoryDialogWidget.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets.dialogs; import android.content.Context; +import android.content.res.Configuration; import android.view.LayoutInflater; import androidx.databinding.DataBindingUtil; @@ -36,7 +37,28 @@ public ClearHistoryDialogWidget(Context aContext) { protected void initialize(Context aContext) { super.initialize(aContext); - LayoutInflater inflater = LayoutInflater.from(aContext); + + } + + @Override + public void show(int aShowFlags) { + super.show(aShowFlags); + + mClearHistoryBinding.clearHistoryRadio.setChecked(0, false); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + + @Override + public void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mClearHistoryBinding = DataBindingUtil.inflate(inflater, R.layout.clear_history_dialog, mBinding.content, true); @@ -75,11 +97,4 @@ protected void initialize(Context aContext) { onDismiss(); })); } - - @Override - public void show(int aShowFlags) { - super.show(aShowFlags); - - mClearHistoryBinding.clearHistoryRadio.setChecked(0, false); - } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PromptDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PromptDialogWidget.java index 239e28043..ba360d336 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PromptDialogWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/PromptDialogWidget.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets.dialogs; import android.content.Context; +import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; @@ -40,7 +41,13 @@ public PromptDialogWidget(Context aContext) { } protected void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.prompt_dialog, this, true); @@ -57,6 +64,13 @@ protected void initialize(Context aContext) { }); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + @Override protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { // We align it at the same position as the settings panel diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java index 5986a852f..ad8b2d616 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SelectionActionWidget.java @@ -1,6 +1,7 @@ package org.mozilla.vrbrowser.ui.widgets.dialogs; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Point; import android.graphics.RectF; import android.view.View; @@ -42,13 +43,25 @@ public SelectionActionWidget(Context aContext) { } private void initialize() { - inflate(getContext(), R.layout.selection_action_menu, this); - mContainer = findViewById(R.id.selectionMenuContainer); + updateUI(); + mMinButtonWidth = WidgetPlacement.pixelDimension(getContext(), R.dimen.selection_action_item_min_width); mMaxButtonWidth = WidgetPlacement.pixelDimension(getContext(), R.dimen.selection_action_item_max_width); - mBackHandler = () -> { - onDismiss(); - }; + mBackHandler = this::onDismiss; + } + + public void updateUI() { + removeAllViews(); + + inflate(getContext(), R.layout.selection_action_menu, this); + mContainer = findViewById(R.id.selectionMenuContainer); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); } @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SendTabDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SendTabDialogWidget.java index 7ed0ca98f..d71e2a519 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SendTabDialogWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SendTabDialogWidget.java @@ -6,6 +6,7 @@ package org.mozilla.vrbrowser.ui.widgets.dialogs; import android.content.Context; +import android.content.res.Configuration; import android.view.LayoutInflater; import android.view.View; @@ -53,21 +54,35 @@ public SendTabDialogWidget(@NonNull Context aContext) { protected void initialize(@NonNull Context aContext) { super.initialize(aContext); - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + + mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); + } + + @Override + public void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mSendTabsDialogBinding = DataBindingUtil.inflate(inflater, R.layout.send_tabs_display, mBinding.content, true); mSendTabsDialogBinding.setIsSyncing(false); mSendTabsDialogBinding.setIsEmpty(false); - - mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); - + mBinding.headerLayout.setTitle(getResources().getString(R.string.send_tab_dialog_title)); mBinding.headerLayout.setDescription(R.string.send_tab_dialog_description); mBinding.footerLayout.setFooterButtonText(R.string.send_tab_dialog_button); mBinding.footerLayout.setFooterButtonClickListener(this::sendTabButtonClick); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + @Override public void show(int aShowFlags) { mAccounts.addAccountListener(this); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SettingDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SettingDialogWidget.java index f4da4982d..421e7e5e3 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SettingDialogWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/SettingDialogWidget.java @@ -1,6 +1,7 @@ package org.mozilla.vrbrowser.ui.widgets.dialogs; import android.content.Context; +import android.content.res.Configuration; import android.view.LayoutInflater; import androidx.databinding.DataBindingUtil; @@ -19,16 +20,7 @@ public SettingDialogWidget(Context aContext) { } protected void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); - - // Inflate this data binding layout - mBinding = DataBindingUtil.inflate(inflater, R.layout.setting_dialog, this, true); - - // Header - mBinding.headerLayout.setBackClickListener(view -> onDismiss()); - - // Footer - mBinding.footerLayout.setFooterButtonClickListener(v -> onFooterButton()); + updateUI(); } @Override @@ -57,4 +49,25 @@ protected void onFooterButton() { } + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.setting_dialog, this, true); + + // Header + mBinding.headerLayout.setBackClickListener(view -> onDismiss()); + + // Footer + mBinding.footerLayout.setFooterButtonClickListener(v -> onFooterButton()); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java index 714556073..2479ddc2d 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java @@ -5,6 +5,7 @@ import android.app.Application; import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.graphics.drawable.ClipDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; @@ -80,22 +81,13 @@ public VoiceSearchWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); - - // Inflate this data binding layout - mBinding = DataBindingUtil.inflate(inflater, R.layout.voice_search_dialog, this, true); + updateUI(); mWidgetManager.addPermissionListener(this); mMozillaSpeechService = MozillaSpeechService.getInstance(); mMozillaSpeechService.setProductTag(getContext().getString(R.string.voice_app_id)); - Drawable mVoiceInputBackgroundDrawable = getResources().getDrawable(R.drawable.ic_voice_search_volume_input_black, getContext().getTheme()); - mVoiceInputClipDrawable = new ClipDrawable(getContext().getDrawable(R.drawable.ic_voice_search_volume_input_clip), Gravity.START, ClipDrawable.HORIZONTAL); - Drawable[] layers = new Drawable[] {mVoiceInputBackgroundDrawable, mVoiceInputClipDrawable }; - mBinding.voiceSearchAnimationListening.setImageDrawable(new LayerDrawable(layers)); - mVoiceInputClipDrawable.setLevel(0); - mSearchingAnimation = new RotateAnimation(0, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); @@ -104,12 +96,34 @@ private void initialize(Context aContext) { mSearchingAnimation.setDuration(ANIMATION_DURATION); mSearchingAnimation.setRepeatCount(Animation.INFINITE); - mBinding.closeButton.setOnClickListener(view -> onDismiss()); - mMozillaSpeechService.addListener(mVoiceSearchListener); ((Application)aContext.getApplicationContext()).registerActivityLifecycleCallbacks(this); } + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.voice_search_dialog, this, true); + + Drawable mVoiceInputBackgroundDrawable = getResources().getDrawable(R.drawable.ic_voice_search_volume_input_black, getContext().getTheme()); + mVoiceInputClipDrawable = new ClipDrawable(getContext().getDrawable(R.drawable.ic_voice_search_volume_input_clip), Gravity.START, ClipDrawable.HORIZONTAL); + Drawable[] layers = new Drawable[] {mVoiceInputBackgroundDrawable, mVoiceInputClipDrawable }; + mBinding.voiceSearchAnimationListening.setImageDrawable(new LayerDrawable(layers)); + mVoiceInputClipDrawable.setLevel(0); + + mBinding.closeButton.setOnClickListener(view -> hide(KEEP_WIDGET)); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + public void setDelegate(VoiceSearchDelegate delegate) { mDelegate = delegate; } @@ -175,7 +189,7 @@ public void onSpeechStatusChanged(final MozillaSpeechService.SpeechState aState, if (mDelegate != null) { mDelegate.OnVoiceSearchResult(transcription, confidence); } - hide(REMOVE_WIDGET); + hide(KEEP_WIDGET); break; case START_LISTEN: // Handle when the api successfully opened the microphone and started listening diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/BrightnessMenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/BrightnessMenuWidget.java index 9338e86c6..819665ea6 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/BrightnessMenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/BrightnessMenuWidget.java @@ -1,10 +1,13 @@ package org.mozilla.vrbrowser.ui.widgets.menus; import android.content.Context; +import android.content.res.Configuration; +import android.view.View; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.ui.widgets.UIWidget; import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement; +import org.mozilla.vrbrowser.utils.ViewUtils; import java.util.ArrayList; @@ -13,7 +16,8 @@ public class BrightnessMenuWidget extends MenuWidget { ArrayList mItems; public BrightnessMenuWidget(Context aContext) { super(aContext, R.layout.menu); - createMenuItems(); + + updateUI(); } @Override @@ -28,6 +32,20 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.translationZ = 2.0f; } + @Override + public void updateUI() { + super.updateUI(); + + createMenuItems(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + public void setParentWidget(UIWidget aParent) { mWidgetPlacement.parentHandle = aParent.getHandle(); } @@ -63,4 +81,11 @@ private void handleClick() { mWidgetPlacement.visible = false; mWidgetManager.updateWidget(this); } + + @Override + public void onGlobalFocusChanged(View oldFocus, View newFocus) { + if (!ViewUtils.isEqualOrChildrenOf(this, newFocus) && isVisible()) { + hide(KEEP_WIDGET); + } + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/ContextMenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/ContextMenuWidget.java index 704a1f5bc..a28730454 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/ContextMenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/ContextMenuWidget.java @@ -8,8 +8,8 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.res.Configuration; import android.net.Uri; -import android.view.View; import org.mozilla.geckoview.GeckoSession; import org.mozilla.vrbrowser.R; @@ -17,11 +17,10 @@ import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate; import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement; import org.mozilla.vrbrowser.utils.StringUtils; -import org.mozilla.vrbrowser.utils.ViewUtils; import java.util.ArrayList; -public class ContextMenuWidget extends MenuWidget implements WidgetManagerDelegate.FocusChangeListener { +public class ContextMenuWidget extends MenuWidget { ArrayList mItems; private Runnable mDismissCallback; @@ -31,12 +30,7 @@ public ContextMenuWidget(Context aContext) { } private void initialize() { - mAdapter.updateBackgrounds(R.drawable.context_menu_item_background_first, - R.drawable.context_menu_item_background_last, - R.drawable.context_menu_item_background, - R.drawable.context_menu_item_background_single); - mAdapter.updateLayoutId(R.layout.context_menu_item); - menuContainer.setBackground(getContext().getDrawable(R.drawable.context_menu_background)); + updateUI(); } @Override @@ -51,16 +45,22 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { } @Override - public void show(@ShowFlags int aShowFlags) { - mWidgetManager.addFocusChangeListener(ContextMenuWidget.this); - super.show(aShowFlags); + public void updateUI() { + super.updateUI(); + + mAdapter.updateBackgrounds(R.drawable.context_menu_item_background_first, + R.drawable.context_menu_item_background_last, + R.drawable.context_menu_item_background, + R.drawable.context_menu_item_background_single); + mAdapter.updateLayoutId(R.layout.context_menu_item); + menuContainer.setBackground(getContext().getDrawable(R.drawable.context_menu_background)); } @Override - public void hide(@HideFlags int aHideFlags) { - super.hide(aHideFlags); + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - mWidgetManager.removeFocusChangeListener(this); + updateUI(); } @Override @@ -121,13 +121,4 @@ public void setContextElement(GeckoSession.ContentDelegate.ContextElement aConte mWidgetPlacement.height += 10.0f; // Link separator } - // WidgetManagerDelegate.FocusChangeListener - - @Override - public void onGlobalFocusChanged(View oldFocus, View newFocus) { - if (!ViewUtils.isEqualOrChildrenOf(this, newFocus) && isVisible()) { - onDismiss(); - } - } - } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/HamburgerMenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/HamburgerMenuWidget.java index 2607ce48f..122a977b2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/HamburgerMenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/HamburgerMenuWidget.java @@ -2,22 +2,20 @@ import android.annotation.SuppressLint; import android.content.Context; -import android.view.View; +import android.content.res.Configuration; import androidx.annotation.IntDef; import org.mozilla.geckoview.GeckoSessionSettings; import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate; import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement; import org.mozilla.vrbrowser.utils.AnimationHelper; -import org.mozilla.vrbrowser.utils.ViewUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.Optional; -public class HamburgerMenuWidget extends MenuWidget implements WidgetManagerDelegate.FocusChangeListener { +public class HamburgerMenuWidget extends MenuWidget { public interface MenuDelegate { void onSendTab(); @@ -42,6 +40,13 @@ public HamburgerMenuWidget(Context aContext) { } private void initialize() { + updateUI(); + } + + @Override + public void updateUI() { + super.updateUI(); + mAdapter.updateBackgrounds(R.drawable.context_menu_item_background_first, R.drawable.context_menu_item_background_last, R.drawable.context_menu_item_background, @@ -51,18 +56,23 @@ private void initialize() { updateMenuItems(); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + @Override public void show(int aShowFlags) { super.show(aShowFlags); AnimationHelper.scaleIn(findViewById(R.id.menuContainer), 100, 0, null); - mWidgetManager.addFocusChangeListener(this); } @Override public void hide(int aHideFlags) { AnimationHelper.scaleOut(findViewById(R.id.menuContainer), 100, 0, () -> HamburgerMenuWidget.super.hide(aHideFlags)); - mWidgetManager.removeFocusChangeListener(this); } @Override @@ -131,12 +141,4 @@ public void setSendTabEnabled(boolean value) { updateMenuItems(); } - // FocusChangeListener - - @Override - public void onGlobalFocusChanged(View oldFocus, View newFocus) { - if (!ViewUtils.isEqualOrChildrenOf(this, newFocus)) { - onDismiss(); - } - } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/LibraryMenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/LibraryMenuWidget.java index b7bd67399..7f937b14a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/LibraryMenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/LibraryMenuWidget.java @@ -1,21 +1,19 @@ package org.mozilla.vrbrowser.ui.widgets.menus; import android.content.Context; -import android.view.View; +import android.content.res.Configuration; import androidx.annotation.NonNull; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.ui.callbacks.LibraryItemContextMenuClickCallback; -import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate; import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement; import org.mozilla.vrbrowser.utils.AnimationHelper; -import org.mozilla.vrbrowser.utils.ViewUtils; import java.util.ArrayList; import java.util.Optional; -public class LibraryMenuWidget extends MenuWidget implements WidgetManagerDelegate.FocusChangeListener { +public class LibraryMenuWidget extends MenuWidget { public enum LibraryItemType { BOOKMARKS, @@ -62,6 +60,13 @@ public LibraryMenuWidget(Context aContext, LibraryContextMenuItem item, boolean } private void initialize() { + updateUI(); + } + + @Override + public void updateUI() { + super.updateUI(); + mAdapter.updateBackgrounds( R.drawable.library_context_menu_item_background_top, R.drawable.library_context_menu_item_background_bottom, @@ -70,18 +75,23 @@ private void initialize() { mAdapter.updateLayoutId(R.layout.library_menu_item); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); + } + @Override public void show(int aShowFlags) { super.show(aShowFlags); AnimationHelper.scaleIn(findViewById(R.id.menuContainer), 100, 0, null); - mWidgetManager.addFocusChangeListener(this); } @Override public void hide(int aHideFlags) { AnimationHelper.scaleOut(findViewById(R.id.menuContainer), 100, 0, () -> LibraryMenuWidget.super.hide(aHideFlags)); - mWidgetManager.removeFocusChangeListener(this); } @Override @@ -136,12 +146,4 @@ private void createMenuItems(boolean canOpenWindows, boolean isBookmarked) { mWidgetPlacement.height += mBorderWidth * 2; } - // FocusChangeListener - - @Override - public void onGlobalFocusChanged(View oldFocus, View newFocus) { - if (!ViewUtils.isEqualOrChildrenOf(this, newFocus)) { - onDismiss(); - } - } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/MenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/MenuWidget.java index 5b14e4a33..770c046a0 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/MenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/MenuWidget.java @@ -20,14 +20,16 @@ import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.ui.widgets.UIWidget; +import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate; import org.mozilla.vrbrowser.utils.ViewUtils; import java.util.ArrayList; -public abstract class MenuWidget extends UIWidget { +public abstract class MenuWidget extends UIWidget implements WidgetManagerDelegate.FocusChangeListener { protected MenuAdapter mAdapter; protected ListView mListView; protected View menuContainer; + protected int mLayoutRes; public MenuWidget(Context aContext, @LayoutRes int layout) { super(aContext); @@ -40,17 +42,39 @@ public MenuWidget(Context aContext, @LayoutRes int layout, ArrayList a } private void initialize(Context aContext, @LayoutRes int layout, ArrayList aItems) { - inflate(aContext, layout, this); + mLayoutRes = layout; + updateUI(); + } + + public void updateUI() { + removeAllViews(); + + inflate(getContext(), mLayoutRes, this); mListView = findViewById(R.id.menuListView); menuContainer = findViewById(R.id.menuContainer); - mAdapter = new MenuAdapter(aContext, aItems); + mAdapter = new MenuAdapter(getContext(), null); mListView.setAdapter(mAdapter); mListView.setVerticalScrollBarEnabled(false); mListView.setFastScrollAlwaysVisible(false); } + + @Override + public void show(@ShowFlags int aShowFlags) { + super.show(aShowFlags); + + mWidgetManager.addFocusChangeListener(this); + } + + @Override + public void hide(@HideFlags int aHideFlags) { + super.hide(aHideFlags); + + mWidgetManager.removeFocusChangeListener(this); + } + public void updateMenuItems(ArrayList aItems) { mAdapter.mItems = aItems; mAdapter.notifyDataSetChanged(); @@ -207,4 +231,11 @@ public boolean onHover(View view, MotionEvent event) { } } + @Override + public void onGlobalFocusChanged(View oldFocus, View newFocus) { + if (!ViewUtils.isEqualOrChildrenOf(this, newFocus) && isVisible()) { + onDismiss(); + } + } + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/VideoProjectionMenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/VideoProjectionMenuWidget.java index ab2091c99..81f89b81a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/VideoProjectionMenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/menus/VideoProjectionMenuWidget.java @@ -1,6 +1,7 @@ package org.mozilla.vrbrowser.ui.widgets.menus; import android.content.Context; +import android.content.res.Configuration; import android.net.Uri; import android.view.View; @@ -9,7 +10,6 @@ import org.mozilla.vrbrowser.R; 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.utils.ViewUtils; @@ -17,7 +17,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.IntStream; -public class VideoProjectionMenuWidget extends MenuWidget implements WidgetManagerDelegate.FocusChangeListener { +public class VideoProjectionMenuWidget extends MenuWidget { @IntDef(value = { VIDEO_PROJECTION_NONE, VIDEO_PROJECTION_3D_SIDE_BY_SIDE, VIDEO_PROJECTION_360, VIDEO_PROJECTION_360_STEREO, VIDEO_PROJECTION_180, @@ -50,7 +50,8 @@ public ProjectionMenuItem(@VideoProjectionFlags int aProjection, String aString, public VideoProjectionMenuWidget(Context aContext) { super(aContext, R.layout.menu); - createMenuItems(); + + updateUI(); } @Override @@ -66,17 +67,17 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { } @Override - public void show(@ShowFlags int aShowFlags) { - super.show(aShowFlags); + public void updateUI() { + super.updateUI(); - mWidgetManager.addFocusChangeListener(VideoProjectionMenuWidget.this); + createMenuItems(); } @Override - public void hide(@HideFlags int aHideFlags) { - super.hide(aHideFlags); + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); - mWidgetManager.removeFocusChangeListener(this); + updateUI(); } public void setParentWidget(UIWidget aParent) { @@ -176,7 +177,7 @@ public void setSelectedProjection(@VideoProjectionFlags int aProjection) { @Override public void onGlobalFocusChanged(View oldFocus, View newFocus) { if (!ViewUtils.isEqualOrChildrenOf(this, newFocus) && isVisible()) { - onDismiss(); + hide(KEEP_WIDGET); } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ContentLanguageOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ContentLanguageOptionsView.java index a3ac3e156..50774893b 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ContentLanguageOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ContentLanguageOptionsView.java @@ -39,8 +39,6 @@ public ContentLanguageOptionsView(Context aContext, WidgetManagerDelegate aWidge } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); - // Preferred languages adapter mPreferredAdapter = new LanguagesAdapter(getContext(), mLanguageItemCallback, true); mPreferredAdapter.setLanguageList(LocaleUtils.getPreferredLanguages(getContext())); @@ -49,6 +47,17 @@ private void initialize(Context aContext) { mAvailableAdapter = new LanguagesAdapter(getContext(), mLanguageItemCallback, false); mAvailableAdapter.setLanguageList(LocaleUtils.getAvailableLanguages()); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_language_content, this, true); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ControllerOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ControllerOptionsView.java index 1fdf0ea25..6929ce1a3 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ControllerOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/ControllerOptionsView.java @@ -26,7 +26,14 @@ public ControllerOptionsView(Context aContext, WidgetManagerDelegate aWidgetMana } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_controller, this, true); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java index 491f23fd8..becaa48d5 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java @@ -31,7 +31,14 @@ public DeveloperOptionsView(Context aContext, WidgetManagerDelegate aWidgetManag } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_developer, this, true); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayLanguageOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayLanguageOptionsView.java index d8d6670ec..0050d558b 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayLanguageOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayLanguageOptionsView.java @@ -30,7 +30,14 @@ public DisplayLanguageOptionsView(Context aContext, WidgetManagerDelegate aWidge } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_language_display, this, true); @@ -94,9 +101,7 @@ private void setLanguage(int checkedId, boolean doApply) { String locale = LocaleUtils.getSupportedLocaleForIndex(checkedId); LocaleUtils.setDisplayLocale(getContext(), locale); - if (mDelegate != null) { - mDelegate.showRestartDialog(); - } + mWidgetManager.updateLocale(LocaleUtils.setLocale(getContext())); } } @@ -105,4 +110,5 @@ public Point getDimensions() { return new Point( WidgetPlacement.dpDimension(getContext(), R.dimen.settings_dialog_width), WidgetPlacement.dpDimension(getContext(), R.dimen.settings_dialog_height)); } + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayOptionsView.java index f2868f0d2..00ff9a4b0 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DisplayOptionsView.java @@ -32,7 +32,14 @@ public DisplayOptionsView(Context aContext, WidgetManagerDelegate aWidgetManager } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_display, this, true); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/EnvironmentOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/EnvironmentOptionsView.java index 9f0a4cf54..b3276668e 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/EnvironmentOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/EnvironmentOptionsView.java @@ -29,7 +29,14 @@ public EnvironmentOptionsView(Context aContext, WidgetManagerDelegate aWidgetMan } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_environment, this, true); 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 1278d4b5a..cc4c6d319 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 @@ -53,7 +53,14 @@ public FxAAccountOptionsView(Context aContext, WidgetManagerDelegate aWidgetMana } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_fxa_account, this, true); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/LanguageOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/LanguageOptionsView.java index 8e8ada86d..09a50080a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/LanguageOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/LanguageOptionsView.java @@ -42,7 +42,20 @@ public LanguageOptionsView(Context aContext, WidgetManagerDelegate aWidgetManage } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + + mContentLanguage = new ContentLanguageOptionsView(getContext(), mWidgetManager); + mVoiceLanguage = new VoiceSearchLanguageOptionsView(getContext(), mWidgetManager); + mDisplayLanguage = new DisplayLanguageOptionsView(getContext(), mWidgetManager); + + mPrefs = PreferenceManager.getDefaultSharedPreferences(aContext); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_language, this, true); @@ -62,12 +75,6 @@ private void initialize(Context aContext) { setVoiceLanguage(); setContentLanguage(); setDisplayLanguage(); - - mContentLanguage = new ContentLanguageOptionsView(getContext(), mWidgetManager); - mVoiceLanguage = new VoiceSearchLanguageOptionsView(getContext(), mWidgetManager); - mDisplayLanguage = new DisplayLanguageOptionsView(getContext(), mWidgetManager); - - mPrefs = PreferenceManager.getDefaultSharedPreferences(aContext); } @Override @@ -85,10 +92,9 @@ protected void onDismiss() { } private OnClickListener mResetListener = (view) -> { - if (mContentLanguage.reset() | - mDisplayLanguage.reset() | - mVoiceLanguage.reset()) - showRestartDialog(); + mContentLanguage.reset(); + mDisplayLanguage.reset(); + mVoiceLanguage.reset(); }; private void setVoiceLanguage() { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PopUpExceptionsOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PopUpExceptionsOptionsView.java index f40d83c2b..7747890ec 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PopUpExceptionsOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PopUpExceptionsOptionsView.java @@ -37,13 +37,20 @@ public PopUpExceptionsOptionsView(Context aContext, WidgetManagerDelegate aWidge } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); // Preferred languages adapter mAdapter = new PopUpAdapter(getContext(), mCallback); // View Model mViewModel = new PopUpsViewModel(((Application)getContext().getApplicationContext())); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_privacy_popups, this, true); @@ -114,4 +121,5 @@ public void onDelete(@NonNull PopUpSite item) { } }; + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java index 993b5426b..0fd5e6ff6 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/PrivacyOptionsView.java @@ -43,7 +43,16 @@ public PrivacyOptionsView(Context aContext, WidgetManagerDelegate aWidgetManager } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + + ((Application)aContext.getApplicationContext()).registerActivityLifecycleCallbacks(mLifeCycleListener); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_privacy, this, true); @@ -56,8 +65,6 @@ private void initialize(Context aContext) { // Footer mBinding.footerLayout.setFooterButtonClickListener(v -> resetOptions()); - ((Application)aContext.getApplicationContext()).registerActivityLifecycleCallbacks(mLifeCycleListener); - // Options mBinding.showPrivacyButton.setOnClickListener(v -> { SessionStore.get().getActiveSession().loadUri(getContext().getString(R.string.private_policy_url)); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsView.java index df3b2b11b..bad06b46c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/SettingsView.java @@ -91,4 +91,9 @@ public Point getDimensions() { protected boolean reset() { return false; } + + protected void updateUI() { + removeAllViews(); + } + } 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 548c9e555..b54692834 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 @@ -9,6 +9,7 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.text.Html; @@ -98,16 +99,30 @@ public SettingsWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { @SuppressLint("ClickableViewAccessibility") private void initialize() { - LayoutInflater inflater = LayoutInflater.from(getContext()); - - // Inflate this data binding layout - mBinding = DataBindingUtil.inflate(inflater, R.layout.settings, this, true); + updateUI(); mAccounts = ((VRBrowserApplication)getContext().getApplicationContext()).getAccounts(); mAccounts.addAccountListener(mAccountObserver); mUIThreadExecutor = ((VRBrowserApplication)getContext().getApplicationContext()).getExecutors().mainThread(); + mAudio = AudioEngine.fromContext(getContext()); + + mViewMarginH = mWidgetPlacement.width - WidgetPlacement.dpDimension(getContext(), R.dimen.options_width); + mViewMarginH = WidgetPlacement.convertDpToPixel(getContext(), mViewMarginH); + mViewMarginV = mWidgetPlacement.height - WidgetPlacement.dpDimension(getContext(), R.dimen.options_height); + mViewMarginV = WidgetPlacement.convertDpToPixel(getContext(), mViewMarginV); + } + + @SuppressLint("ClickableViewAccessibility") + public void updateUI() { + removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.settings, this, true); + mBinding.backButton.setOnClickListener(v -> { if (mAudio != null) { mAudio.playSound(AudioEngine.Sound.CLICK); @@ -158,8 +173,8 @@ private void initialize() { String app_name = getResources().getString(R.string.app_name); String[] app_name_parts = app_name.split(" "); mBinding.versionText.setText(Html.fromHtml("" + app_name_parts[0] + "" + - " " + app_name_parts[1] + " " + - " " + pInfo.versionName + "", + " " + app_name_parts[1] + " " + + " " + pInfo.versionName + "", Html.FROM_HTML_MODE_LEGACY)); } catch (PackageManager.NameNotFoundException e) { @@ -209,12 +224,14 @@ private void initialize() { showControllerOptionsDialog(); }); - mAudio = AudioEngine.fromContext(getContext()); + mCurrentView = null; + } - mViewMarginH = mWidgetPlacement.width - WidgetPlacement.dpDimension(getContext(), R.dimen.options_width); - mViewMarginH = WidgetPlacement.convertDpToPixel(getContext(), mViewMarginH); - mViewMarginV = mWidgetPlacement.height - WidgetPlacement.dpDimension(getContext(), R.dimen.options_height); - mViewMarginV = WidgetPlacement.convertDpToPixel(getContext(), mViewMarginV); + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateUI(); } @Override @@ -277,7 +294,7 @@ private void manageAccount() { mAccounts.logoutAsync(); } else { - hide(REMOVE_WIDGET); + hide(KEEP_WIDGET); CompletableFuture result = mAccounts.authUrlAsync(); if (result != null) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/VoiceSearchLanguageOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/VoiceSearchLanguageOptionsView.java index 52ab1542c..69f323f6d 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/VoiceSearchLanguageOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/VoiceSearchLanguageOptionsView.java @@ -30,7 +30,14 @@ public VoiceSearchLanguageOptionsView(Context aContext, WidgetManagerDelegate aW } private void initialize(Context aContext) { - LayoutInflater inflater = LayoutInflater.from(aContext); + updateUI(); + } + + @Override + protected void updateUI() { + super.updateUI(); + + LayoutInflater inflater = LayoutInflater.from(getContext()); // Inflate this data binding layout mBinding = DataBindingUtil.inflate(inflater, R.layout.options_language_voice, this, true); @@ -100,4 +107,5 @@ public Point getDimensions() { return new Point( WidgetPlacement.dpDimension(getContext(), R.dimen.settings_dialog_width), WidgetPlacement.dpDimension(getContext(), R.dimen.settings_dialog_height)); } + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/LocaleUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/LocaleUtils.java index 7561aa15c..cc4c12fd2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/LocaleUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/LocaleUtils.java @@ -32,6 +32,10 @@ public static void init() { getAllLanguages(); } + public static void refresh() { + getAllLanguages(true); + } + public static void saveSystemLocale() { mSystemLocale = Locale.getDefault(); } @@ -47,7 +51,11 @@ public static String getCurrentLocale() { } private static HashMap getAllLanguages() { - if (mLanguagesCache != null) { + return getAllLanguages(false); + } + + private static HashMap getAllLanguages(boolean refresh) { + if (mLanguagesCache != null && !refresh) { return mLanguagesCache; } @@ -198,7 +206,7 @@ public static String getDisplayLocale(Context context) { } public static void setDisplayLocale(@NonNull Context context, @NonNull String locale) { - SettingsStore.getInstance(context).setDisplayLocale(locale); + SettingsStore.getInstance(context).setDisplayLocale(getClosestAvailableLocale(locale)); } @NonNull diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/StringUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/StringUtils.java index 229d1fce9..5336f7c90 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/StringUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/StringUtils.java @@ -3,6 +3,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Build; import androidx.annotation.NonNull; @@ -19,7 +20,14 @@ public class StringUtils { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static String getStringByLocale(Context context, int id, Locale locale) { Configuration configuration = new Configuration(context.getResources().getConfiguration()); - configuration.setLocale(locale); + // This looks like an Android bug, when trying to get the localized string for the system locale + // it returns the locale for the current context one. + Locale deviceLocale = Resources.getSystem().getConfiguration().getLocales().get(0); + if (deviceLocale.equals(locale)) { + configuration.setLocale(deviceLocale); + } else { + configuration.setLocale(locale); + } return context.createConfigurationContext(configuration).getResources().getString(id); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java index 97efa13d1..9d05c00c7 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java @@ -7,12 +7,17 @@ import android.content.Context; import android.util.Base64; +import android.webkit.URLUtil; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.browser.SettingsStore; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; import java.util.regex.Pattern; @@ -73,4 +78,41 @@ public static boolean isPrivateAboutPage(@NonNull Context context, @NonNull Str byte[] privatePageBytes = InternalPages.createAboutPage(context, pageResources); return uri.equals("data:text/html;base64," + Base64.encodeToString(privatePageBytes, Base64.NO_WRAP)); } + + public static Boolean isHomeUri(@NonNull Context context, @Nullable String aUri) { + return aUri != null && aUri.toLowerCase().startsWith( + SettingsStore.getInstance(context).getHomepage() + ); + } + + public static Boolean isDataUri(@NonNull String aUri) { + return aUri.startsWith("data"); + } + + public static Boolean isBlankUri(@NonNull Context context, @NonNull String aUri) { + return aUri.equals(context.getString(R.string.about_blank)); + } + + public static String titleBarUrl(@Nullable String aUri) { + if (aUri == null) { + return ""; + } + + if (URLUtil.isValidUrl(aUri)) { + try { + URI uri = URI.create(aUri); + URL url = new URL( + uri.getScheme() != null ? uri.getScheme() : "", + uri.getAuthority() != null ? uri.getAuthority() : "", + ""); + return url.toString(); + + } catch (MalformedURLException | IllegalArgumentException e) { + return ""; + } + + } else { + return aUri; + } + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f59ecec04..8ebde46a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,7 +25,7 @@ diff --git a/app/src/main/res/layout/navigation_bar.xml b/app/src/main/res/layout/navigation_bar.xml index 52344ff0b..1578dd90d 100644 --- a/app/src/main/res/layout/navigation_bar.xml +++ b/app/src/main/res/layout/navigation_bar.xml @@ -1,9 +1,27 @@ - + + + + + + - + - - - - + + + diff --git a/app/src/main/res/layout/navigation_bar_fullscreen.xml b/app/src/main/res/layout/navigation_bar_fullscreen.xml index 09db1a1ec..b89e58d2d 100644 --- a/app/src/main/res/layout/navigation_bar_fullscreen.xml +++ b/app/src/main/res/layout/navigation_bar_fullscreen.xml @@ -1,6 +1,14 @@ - - + + + + + + android:tooltipText="@string/back_tooltip" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:tooltipText="@string/resize_tooltip" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:tooltipText="@string/video_mode_tooltip" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:tooltipText="@string/brightness_mode_tooltip" + app:privateMode="@{viewmodel.isPrivateSession}"/> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_bar_menu.xml b/app/src/main/res/layout/navigation_bar_menu.xml index bd6d867ed..3de067c6a 100644 --- a/app/src/main/res/layout/navigation_bar_menu.xml +++ b/app/src/main/res/layout/navigation_bar_menu.xml @@ -1,6 +1,11 @@ - - + + + + + android:textSize="14sp" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:textSize="14sp" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:textSize="14sp" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:textSize="14sp" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:textSize="14sp" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:src="@drawable/ic_icon_resize_done" + app:privateMode="@{viewmodel.isPrivateSession}"/> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_bar_navigation.xml b/app/src/main/res/layout/navigation_bar_navigation.xml index 99022f071..7e67ff5d2 100644 --- a/app/src/main/res/layout/navigation_bar_navigation.xml +++ b/app/src/main/res/layout/navigation_bar_navigation.xml @@ -1,6 +1,11 @@ - - + + + + + android:tooltipText="@string/back_tooltip" + android:enabled="@{viewmodel.canGoBack}" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:tooltipText="@string/forward_tooltip" + android:enabled="@{viewmodel.canGoForward}" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:src="@{viewmodel.isLoading ? @drawable/ic_icon_exit : @drawable/ic_icon_reload}" + android:tooltipText="@{viewmodel.isLoading ? @string/stop_tooltip : @string/refresh_tooltip}" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:tooltipText="@string/home_tooltip" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:orientation="horizontal"/> + android:tooltipText="@string/servo_tooltip" + visibleGone="@{viewmodel.isServoAvailable}" + app:privateMode="@{viewmodel.isPrivateSession}"/> + android:tooltipText="@string/hamburger_menu_tooltip" + app:privateMode="@{viewmodel.isPrivateSession}"/> - + diff --git a/app/src/main/res/layout/navigation_url.xml b/app/src/main/res/layout/navigation_url.xml index 7959eeca2..c18fe57f8 100644 --- a/app/src/main/res/layout/navigation_url.xml +++ b/app/src/main/res/layout/navigation_url.xml @@ -4,53 +4,10 @@ xmlns:tools="http://schemas.android.com/tools"> - - - - - - - - - - - - - - - - - - - - - - - + name="viewmodel" + type="org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel" /> + android:background="@{viewmodel.isPrivateSession ? @drawable/url_background_private : @drawable/url_background}" + android:foreground="@{viewmodel.isPrivateSession ? @drawable/url_background_private_outline : @drawable/url_background_outline}"> + app:visibleGone="@{viewmodel.isMicrophoneEnabled && !viewmodel.isFocused}"/> + app:visibleGone="@{!viewmodel.isMicrophoneEnabled && viewmodel.isFocused && (urlEditText.text.length > 0)}" /> + app:visibleGone="@{!viewmodel.isLibraryVisible}"> + app:visibleGone="@{viewmodel.isPopUpAvailable}" /> + app:visibleGone="@{!viewmodel.isPopUpAvailable}"/> + app:visibleGone="@{viewmodel.isLoading}" /> + app:visibleGone="@{viewmodel.isInsecureVisible && (urlEditText.length() != 0)}" /> @@ -174,7 +131,7 @@ android:layout_width="15dp" android:layout_height="match_parent" android:layout_toEndOf="@id/iconsLayout" - app:visibleGone="@{isLibraryVisible}"/> + app:visibleGone="@{viewmodel.isLibraryVisible}"/> diff --git a/app/src/main/res/layout/title_bar.xml b/app/src/main/res/layout/title_bar.xml index 38cfe4f86..34d9f48e6 100644 --- a/app/src/main/res/layout/title_bar.xml +++ b/app/src/main/res/layout/title_bar.xml @@ -1,10 +1,14 @@ + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto"> - + + + app:visibleGone="@{viewmodel.isInsecureVisible}" /> + tools:text="@{viewmodel.titleBarUrl}" /> + android:src="@{viewmodel.isMediaPlaying ? @drawable/ic_icon_media_pause : @drawable/ic_icon_media_play}" + android:onClick="@{(view) -> viewmodel.isMediaPlaying ? delegate.onMediaPauseClicked(widget) : delegate.onMediaPlayClicked(widget)}" + android:tooltipText="@{viewmodel.isMediaPlaying ? @string/media_pause_tooltip : @string/media_resume_tooltip}" + android:visibility="@{viewmodel.isMediaAvailable ? View.VISIBLE : View.GONE}" + app:privateMode="@{viewmodel.isPrivateSession}"/> diff --git a/app/src/main/res/layout/top_bar.xml b/app/src/main/res/layout/top_bar.xml index 3a0dbcc20..9523c1849 100644 --- a/app/src/main/res/layout/top_bar.xml +++ b/app/src/main/res/layout/top_bar.xml @@ -1,5 +1,13 @@ - + + + + + + + app:visibleGone="@{!viewmodel.showClearButton}"> + style="@style/uiButtonTheme" + android:background="@{viewmodel.isPrivateSession ? @drawable/fullscreen_button_private_first : @drawable/fullscreen_button_first}" + android:src="@drawable/ic_icon_window_left" + android:enabled="@{viewmodel.placement != WindowPlacement.LEFT}" + app:privateMode="@{viewmodel.isPrivateSession}"/> + style="@style/uiButtonTheme" + android:background="@{viewmodel.isPrivateSession ? @drawable/fullscreen_button_private : @drawable/fullscreen_button}" + android:src="@drawable/ic_icon_window_exit" + app:privateMode="@{viewmodel.isPrivateSession}"/> + style="@style/uiButtonTheme" + android:background="@{viewmodel.isPrivateSession ? @drawable/fullscreen_button_private_last : @drawable/fullscreen_button_last}" + android:src="@drawable/ic_icon_window_right" + android:enabled="@{viewmodel.placement != WindowPlacement.RIGHT}" + app:privateMode="@{viewmodel.isPrivateSession}"/> + app:visibleGone="@{viewmodel.showClearButton}" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/tray.xml b/app/src/main/res/layout/tray.xml index fcdaa270b..1d1179339 100644 --- a/app/src/main/res/layout/tray.xml +++ b/app/src/main/res/layout/tray.xml @@ -1,6 +1,12 @@ - + + + + - + diff --git a/app/src/noapi/java/org/mozilla/vrbrowser/PlatformActivity.java b/app/src/noapi/java/org/mozilla/vrbrowser/PlatformActivity.java index 02438ec31..9d8117a22 100644 --- a/app/src/noapi/java/org/mozilla/vrbrowser/PlatformActivity.java +++ b/app/src/noapi/java/org/mozilla/vrbrowser/PlatformActivity.java @@ -8,13 +8,13 @@ import android.app.Activity; import android.opengl.GLSurfaceView; import android.os.Bundle; -import android.provider.ContactsContract; import android.util.Log; import android.view.MotionEvent; import android.view.View; -import android.widget.ImageButton; import android.widget.TextView; +import androidx.annotation.Keep; + import org.mozilla.vrbrowser.utils.SystemUtils; import java.util.ArrayList; @@ -22,8 +22,6 @@ import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; -import androidx.annotation.Keep; - public class PlatformActivity extends Activity { static String LOGTAG = SystemUtils.createLogtag(PlatformActivity.class); static final float ROTATION = 0.098174770424681f;