Bug 1269041 - Temporarily display the dynamic toolbar in onStart if it is not shown. r=ahunt,f=kats
There fixes the issue described in
bug 1245493, however, there are graphical
glitches in the page content as the toolbar is either hidden or shown so we
couldn't land it -
bug 1245523.
MozReview-Commit-ID: 4VTEDvEFbNK
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -299,16 +299,17 @@ public class BrowserApp extends GeckoApp
// The animator used to toggle HomePager visibility has a race where if the HomePager is shown
// (starting the animation), the HomePager is hidden, and the HomePager animation completes,
// both the web content and the HomePager will be hidden. This flag is used to prevent the
// race by determining if the web content should be hidden at the animation's end.
private boolean mHideWebContentOnAnimationEnd;
private final DynamicToolbar mDynamicToolbar = new DynamicToolbar();
+ private DynamicToolbarTemporaryShowTimer mDynamicToolbarShowTimer;
private final List<BrowserAppDelegate> delegates = Collections.unmodifiableList(Arrays.asList(
(BrowserAppDelegate) new AddToHomeScreenPromotion(),
(BrowserAppDelegate) new ScreenshotDelegate()
));
@NonNull
private SearchEngineManager searchEngineManager; // Contains reference to Context - DO NOT LEAK!
@@ -348,16 +349,17 @@ public class BrowserApp extends GeckoApp
if (mZoomedView != null) {
mZoomedView.stopZoomDisplay(false);
}
if (Tabs.getInstance().isSelectedTab(tab)) {
updateHomePagerForTab(tab);
}
mDynamicToolbar.persistTemporaryVisibility();
+ cancelDynamicToolbarShowTimer();
break;
case START:
if (Tabs.getInstance().isSelectedTab(tab)) {
invalidateOptionsMenu();
if (mDynamicToolbar.isEnabled()) {
mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
}
@@ -1096,16 +1098,18 @@ public class BrowserApp extends GeckoApp
// Needed for Adjust to get accurate session measurements
AdjustConstants.getAdjustHelper().onPause();
// Register for Prompt:ShowTop so we can foreground this activity even if it's hidden.
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener) this,
"Prompt:ShowTop");
+ cancelDynamicToolbarShowTimer();
+
for (BrowserAppDelegate delegate : delegates) {
delegate.onPause(this);
}
}
@Override
public void onRestart() {
super.onRestart();
@@ -1114,16 +1118,19 @@ public class BrowserApp extends GeckoApp
delegate.onRestart(this);
}
}
@Override
public void onStart() {
super.onStart();
+ mDynamicToolbarShowTimer = new DynamicToolbarTemporaryShowTimer(mDynamicToolbar);
+ mDynamicToolbarShowTimer.start(VisibilityTransition.IMMEDIATE);
+
// Queue this work so that the first launch of the activity doesn't
// trigger profile init too early.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final GeckoProfile profile = getProfile();
if (profile.inGuestMode()) {
GuestSession.showNotification(BrowserApp.this);
@@ -1173,16 +1180,28 @@ public class BrowserApp extends GeckoApp
// Sending a message to the toolbar when the browser window gains focus
// This is needed for qr code input
if (hasFocus) {
mBrowserToolbar.onParentFocus();
}
}
+ @Override
+ public void onUserInteraction() {
+ cancelDynamicToolbarShowTimer();
+ }
+
+ private void cancelDynamicToolbarShowTimer() {
+ if (mDynamicToolbarShowTimer != null) {
+ mDynamicToolbarShowTimer.cancel();
+ mDynamicToolbarShowTimer = null; // to prevent us from calling cancel unnecessarily & to free memory.
+ }
+ }
+
private void setBrowserToolbarListeners() {
mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
@Override
public void onActivate() {
enterEditingMode();
}
});
--- a/mobile/android/base/java/org/mozilla/gecko/DynamicToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DynamicToolbar.java
@@ -1,13 +1,15 @@
package org.mozilla.gecko;
import org.mozilla.gecko.PrefsHelper.PrefHandlerBase;
+import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.util.FloatUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
public class DynamicToolbar {
private static final String LOGTAG = "DynamicToolbar";
@@ -136,16 +138,27 @@ public class DynamicToolbar {
final boolean isImmediate = transition == VisibilityTransition.IMMEDIATE;
if (visible) {
layerView.getDynamicToolbarAnimator().showToolbar(isImmediate);
} else {
layerView.getDynamicToolbarAnimator().hideToolbar(isImmediate);
}
}
+ public boolean isVisible() {
+ if (layerView == null) {
+ return true; // occurs when not in memory - toolbar defaults to visible
+ }
+ final DynamicToolbarAnimator animator = layerView.getDynamicToolbarAnimator();
+ if (animator == null) {
+ return true; // occurs when not in memory - toolbar defaults to visible
+ }
+ return FloatUtils.fuzzyEquals(0, animator.getToolbarTranslation());
+ }
+
public void setTemporarilyVisible(boolean visible, VisibilityTransition transition) {
ThreadUtils.assertOnUiThread();
if (layerView == null) {
return;
}
if (visible == temporarilyVisible) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/DynamicToolbarTemporaryShowTimer.java
@@ -0,0 +1,61 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package org.mozilla.gecko;
+
+import java.util.concurrent.TimeUnit;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
+import org.mozilla.gecko.util.ThreadUtils;
+
+/**
+ * A container to temporarily show the DynamicToolbar and hide it after a short duration. If the toolbar
+ * is already visible, method calls are a no-op.
+ *
+ * Call {@link #start(VisibilityTransition)} to begin the timer and {@link #cancel()} to cancel it.
+ *
+ * For simplicity, this timer is single-use. This class should only be used from the UIThread.
+ */
+public class DynamicToolbarTemporaryShowTimer {
+ private static final long HIDE_MILLIS = TimeUnit.SECONDS.toMillis(3);
+
+ private final DynamicToolbar toolbar;
+ private Runnable showRunnable;
+
+ private boolean wasStartCalled = false;
+
+ public DynamicToolbarTemporaryShowTimer(final DynamicToolbar toolbar) {
+ this.toolbar = toolbar;
+ }
+
+ @UiThread
+ public void start(@NonNull final VisibilityTransition initialTransition) {
+ if (wasStartCalled) {
+ throw new IllegalStateException("Tried to start already-started timer - these are single-use");
+ }
+ wasStartCalled = true;
+
+ if (!toolbar.isEnabled() || toolbar.isVisible()) {
+ return;
+ }
+
+ toolbar.setVisible(true, initialTransition);
+ showRunnable = new Runnable() {
+ @Override
+ public void run() {
+ toolbar.setVisible(false, VisibilityTransition.ANIMATE);
+ }
+ };
+ ThreadUtils.postDelayedToUiThread(showRunnable, HIDE_MILLIS);
+ }
+
+ @UiThread
+ public void cancel() {
+ ThreadUtils.getUiHandler().removeCallbacks(showRunnable);
+ }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -260,16 +260,17 @@ gbjar.sources += ['java/org/mozilla/geck
'dlc/DownloadAction.java',
'dlc/DownloadContentService.java',
'dlc/StudyAction.java',
'dlc/SyncAction.java',
'dlc/VerifyAction.java',
'DoorHangerPopup.java',
'DownloadsIntegration.java',
'DynamicToolbar.java',
+ 'DynamicToolbarTemporaryShowTimer.java',
'EditBookmarkDialog.java',
'EventDispatcher.java',
'favicons/cache/FaviconCache.java',
'favicons/cache/FaviconCacheElement.java',
'favicons/cache/FaviconsForURL.java',
'favicons/decoders/FaviconDecoder.java',
'favicons/decoders/ICODecoder.java',
'favicons/decoders/IconDirectoryEntry.java',