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

Commit 370e4a9

Browse files
MortimerGorobluemarvin
authored andcommitted
Implement multiwindow hover and click border effect. (#1603)
* Implement multiwindow hover and click border effect. * Proxify keyboard layer to fix depth problems
1 parent 9c4cba9 commit 370e4a9

24 files changed

Lines changed: 608 additions & 173 deletions

app/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ add_library( # Sets the name of the library.
4141
src/main/cpp/VRLayer.cpp
4242
src/main/cpp/VRLayerNode.cpp
4343
src/main/cpp/Widget.cpp
44+
src/main/cpp/WidgetBorder.cpp
4445
src/main/cpp/WidgetMover.cpp
4546
src/main/cpp/WidgetPlacement.cpp
4647
src/main/cpp/WidgetResizer.cpp

app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,16 @@ protected void onCreate(Bundle savedInstanceState) {
256256

257257
protected void initializeWidgets() {
258258
mWindows = new Windows(this);
259-
mWindows.setDelegate(this::attachToWindow);
259+
mWindows.setDelegate(new Windows.Delegate() {
260+
@Override
261+
public void onFocusedWindowChanged(@NonNull WindowWidget aFocusedWindow, @Nullable WindowWidget aPrevFocusedWindow) {
262+
attachToWindow(aFocusedWindow, aPrevFocusedWindow);
263+
}
264+
@Override
265+
public void onWindowBorderChanged(@NonNull WindowWidget aChangeWindow) {
266+
mKeyboard.proxifyLayerIfNeeded(mWindows.getCurrentWindows());
267+
}
268+
});
260269

261270
// Create Browser navigation widget
262271
mNavigationBar = new NavigationBarWidget(this);
@@ -648,20 +657,6 @@ void handleMotionEvent(final int aHandle, final int aDevice, final boolean aPres
648657
if (!isWidgetInputEnabled(widget)) {
649658
widget = null; // Fallback to mRootWidget in order to allow world clicks to dismiss UI.
650659
}
651-
if (widget instanceof WindowWidget) {
652-
WindowWidget window = (WindowWidget) widget;
653-
boolean focused = mWindows.getFocusedWindow() == window;
654-
if (!focused && aPressed) {
655-
// Focus the window when pressed
656-
mWindows.focusWindow(window);
657-
// Discard first click.
658-
return;
659-
} else if (!focused) {
660-
// Do not send hover events to not focused windows.
661-
widget = null;
662-
}
663-
}
664-
665660

666661
float scale = widget != null ? widget.getPlacement().textureScale : 1.0f;
667662
final float x = aX / scale;

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,23 @@ public void dismiss() {
359359
hideOverlays();
360360
}
361361

362+
public void proxifyLayerIfNeeded(ArrayList<WindowWidget> aWindows) {
363+
if (!SettingsStore.getInstance(getContext()).getLayersEnabled()) {
364+
return;
365+
}
366+
boolean proxify = false;
367+
for (WindowWidget window: aWindows) {
368+
if (window.getPlacement().borderColor != 0) {
369+
proxify = true;
370+
break;
371+
}
372+
}
373+
if (mWidgetPlacement.proxifyLayer != proxify) {
374+
mWidgetPlacement.proxifyLayer = proxify;
375+
mWidgetManager.updateWidget(this);
376+
}
377+
}
378+
362379
private void hideOverlays() {
363380
mPopupKeyboardView.setVisibility(View.GONE);
364381
mPopupKeyboardLayer.setVisibility(View.GONE);

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ void resize(int aWidth, int aHeight) {
4343
mSurfaceTexture.setDefaultBufferSize(aWidth, aHeight);
4444
}
4545
}
46+
public boolean isLayer() {
47+
return mSurface != null && mSurfaceTexture == null;
48+
}
4649

4750
void release() {
4851
if(mSurface != null){

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public interface Delegate {
3535
}
3636

3737
protected UISurfaceTextureRenderer mRenderer;
38+
protected UISurfaceTextureRenderer mProxyRenderer;
3839
protected SurfaceTexture mTexture;
3940
protected float mWorldWidth;
4041
protected int mHandle;
@@ -102,6 +103,15 @@ public void setSurfaceTexture(SurfaceTexture aTexture, final int aWidth, final i
102103
Log.d(LOGTAG, "Texture already set");
103104
return;
104105
}
106+
if (mRenderer != null && mRenderer.isLayer()) {
107+
// Widget is using a layer write-only surface but we also want a proxy.
108+
if (mProxyRenderer != null) {
109+
mProxyRenderer.release();
110+
}
111+
mProxyRenderer = new UISurfaceTextureRenderer(aTexture, aWidth, aHeight);
112+
postInvalidate();
113+
return;
114+
}
105115
mTexture = aTexture;
106116
if (mRenderer != null) {
107117
mRenderer.release();
@@ -211,19 +221,27 @@ public void draw(Canvas aCanvas) {
211221
super.draw(aCanvas);
212222
return;
213223
}
214-
Canvas textureCanvas = mRenderer.drawBegin();
224+
draw(aCanvas, mRenderer);
225+
if (mProxyRenderer != null && mWidgetPlacement.proxifyLayer) {
226+
draw(aCanvas, mProxyRenderer);
227+
}
228+
229+
if (mFirstDrawCallback != null) {
230+
mFirstDrawCallback.run();
231+
mFirstDrawCallback = null;
232+
}
233+
}
234+
235+
private void draw(Canvas aCanvas, UISurfaceTextureRenderer aRenderer) {
236+
Canvas textureCanvas = aRenderer.drawBegin();
215237
if(textureCanvas != null) {
216238
// set the proper scale
217239
float xScale = textureCanvas.getWidth() / (float)aCanvas.getWidth();
218240
textureCanvas.scale(xScale, xScale);
219241
// draw the view to SurfaceTexture
220242
super.draw(textureCanvas);
221243
}
222-
mRenderer.drawEnd();
223-
if (mFirstDrawCallback != null) {
224-
mFirstDrawCallback.run();
225-
mFirstDrawCallback = null;
226-
}
244+
aRenderer.drawEnd();
227245
}
228246

229247
@Override

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ public WidgetPlacement(Context aContext) {
4646
public boolean showPointer = true;
4747
public boolean firstDraw = false;
4848
public boolean layer = true;
49+
public boolean proxifyLayer = false;
4950
public float textureScale = 0.7f;
5051
// Widget will be curved if enabled.
5152
public boolean cylinder = true;
53+
public int borderColor = 0;
5254
/*
5355
* Flat surface placements are automatically mapped to curved coordinates.
5456
* If a radius is set it's used for the automatic mapping of the yaw & angle when the

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
import org.mozilla.vrbrowser.ui.widgets.prompts.ConfirmPromptWidget;
4646
import org.mozilla.vrbrowser.ui.widgets.prompts.PromptWidget;
4747
import org.mozilla.vrbrowser.ui.widgets.prompts.TextPromptWidget;
48+
import org.mozilla.vrbrowser.utils.InternalPages;
49+
import org.mozilla.vrbrowser.utils.ViewUtils;
4850

4951
import java.util.ArrayList;
5052

@@ -90,7 +92,15 @@ public class WindowWidget extends UIWidget implements SessionChangeListener,
9092
private Windows.WindowPlacement mWindowPlacement = Windows.WindowPlacement.FRONT;
9193
private float mMaxWindowScale = 3;
9294
private boolean mIsRestored = false;
95+
private WindowDelegate mWindowDelegate;
9396
boolean mActive = false;
97+
boolean mHovered = false;
98+
boolean mClickedAfterFocus = false;
99+
100+
public interface WindowDelegate {
101+
void onFocusRequest(@NonNull WindowWidget aWindow);
102+
void onBorderChanged(@NonNull WindowWidget aWindow);
103+
}
94104

95105
public WindowWidget(Context aContext, int windowId, boolean privateMode) {
96106
super(aContext);
@@ -387,6 +397,7 @@ public void setActiveWindow(boolean active) {
387397
}
388398

389399
TelemetryWrapper.activePlacementEvent(mWindowPlacement.getValue(), mActive);
400+
updateBorder();
390401
}
391402

392403
public SessionStack getSessionStack() {
@@ -488,6 +499,26 @@ public WidgetPlacement getPlacement() {
488499
@Override
489500
public void handleTouchEvent(MotionEvent aEvent) {
490501
mLastMouseClickPos = new Point((int)aEvent.getX(), (int)aEvent.getY());
502+
if (aEvent.getAction() == MotionEvent.ACTION_DOWN) {
503+
if (!mActive) {
504+
mClickedAfterFocus = true;
505+
updateBorder();
506+
if (mWindowDelegate != null) {
507+
// Focus this window
508+
mWindowDelegate.onFocusRequest(this);
509+
}
510+
// Return to discard first click after focus
511+
return;
512+
}
513+
} else if (aEvent.getAction() == MotionEvent.ACTION_UP || aEvent.getAction() == MotionEvent.ACTION_CANCEL) {
514+
mClickedAfterFocus = false;
515+
updateBorder();
516+
}
517+
518+
if (!mActive) {
519+
// Do not send touch events to not focused windows.
520+
return;
521+
}
491522

492523
if (mView != null) {
493524
super.handleTouchEvent(aEvent);
@@ -507,6 +538,19 @@ public void handleTouchEvent(MotionEvent aEvent) {
507538

508539
@Override
509540
public void handleHoverEvent(MotionEvent aEvent) {
541+
if (aEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
542+
mHovered = true;
543+
updateBorder();
544+
} else if (aEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
545+
mHovered = false;
546+
updateBorder();
547+
}
548+
549+
if (!mActive) {
550+
// Do not send touch events to not focused windows.
551+
return;
552+
}
553+
510554
if (mView != null) {
511555
super.handleHoverEvent(aEvent);
512556

@@ -520,6 +564,26 @@ public void handleHoverEvent(MotionEvent aEvent) {
520564
}
521565
}
522566

567+
protected void updateBorder() {
568+
int color = 0;
569+
if (!mActive && !mClickedAfterFocus && mHovered) {
570+
color = ViewUtils.ARGBtoRGBA(getContext().getColor(R.color.window_border_hover));
571+
} else if (mClickedAfterFocus) {
572+
color = ViewUtils.ARGBtoRGBA(getContext().getColor(R.color.window_border_click));
573+
}
574+
if (mWidgetPlacement.borderColor != color) {
575+
mWidgetPlacement.borderColor = color;
576+
mWidgetManager.updateWidget(this);
577+
if (mWindowDelegate != null) {
578+
mWindowDelegate.onBorderChanged(this);
579+
}
580+
}
581+
}
582+
583+
public void setWindowDelegate(WindowDelegate aDelegate) {
584+
mWindowDelegate = aDelegate;
585+
}
586+
523587
@Override
524588
public void handleResizeEvent(float aWorldWidth, float aWorldHeight) {
525589
int width = getWindowWidth(aWorldWidth);
@@ -975,5 +1039,4 @@ public GeckoResult<AllowOrDeny> onLoadRequest(@NonNull GeckoSession session, @No
9751039

9761040
return GeckoResult.ALLOW;
9771041
}
978-
9791042
}

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import java.lang.reflect.Type;
2626
import java.util.ArrayList;
2727

28-
public class Windows implements TrayListener, TopBarWidget.Delegate, GeckoSession.ContentDelegate {
28+
public class Windows implements TrayListener, TopBarWidget.Delegate, GeckoSession.ContentDelegate, WindowWidget.WindowDelegate {
2929

3030
private static final String LOGTAG = Windows.class.getSimpleName();
3131

@@ -86,6 +86,7 @@ public enum WindowPlacement{
8686

8787
public interface Delegate {
8888
void onFocusedWindowChanged(@NonNull WindowWidget aFocusedWindow, @Nullable WindowWidget aPrevFocusedWindow);
89+
void onWindowBorderChanged(@NonNull WindowWidget aChangeWindow);
8990
}
9091

9192
public Windows(Context aContext) {
@@ -347,6 +348,7 @@ public void onPause() {
347348
}
348349

349350
public void onDestroy() {
351+
mDelegate = null;
350352
for (WindowWidget window: mRegularWindows) {
351353
window.close();
352354
}
@@ -436,7 +438,7 @@ private void showMaxWindowsMessage() {
436438
mFocusedWindow.showMaxWindowsDialog(MAX_WINDOWS);
437439
}
438440

439-
private ArrayList<WindowWidget> getCurrentWindows() {
441+
public ArrayList<WindowWidget> getCurrentWindows() {
440442
return mPrivateMode ? mPrivateWindows : mRegularWindows;
441443
}
442444

@@ -510,6 +512,7 @@ private void removeWindow(@NonNull WindowWidget aWindow) {
510512
mPrivateWindows.remove(aWindow);
511513
aWindow.getTopBar().setVisible(false);
512514
aWindow.getTopBar().setDelegate((TopBarWidget.Delegate) null);
515+
aWindow.setWindowDelegate(null);
513516
aWindow.getSessionStack().removeContentListener(this);
514517
aWindow.close();
515518
updateMaxWindowScales();
@@ -664,6 +667,7 @@ private void updateTopBars() {
664667
private WindowWidget createWindow() {
665668
int newWindowId = sIndex++;
666669
WindowWidget window = new WindowWidget(mContext, newWindowId, mPrivateMode);
670+
window.setWindowDelegate(this);
667671
getCurrentWindows().add(window);
668672
window.getTopBar().setDelegate(this);
669673
window.getSessionStack().addContentListener(this);
@@ -782,4 +786,18 @@ private WindowWidget getWindowWithSession(GeckoSession aSession) {
782786
return null;
783787
}
784788

789+
// WindowWidget.Delegate
790+
@Override
791+
public void onFocusRequest(WindowWidget aWindow) {
792+
focusWindow(aWindow);
793+
}
794+
795+
@Override
796+
public void onBorderChanged(WindowWidget aWindow) {
797+
if (mDelegate != null) {
798+
mDelegate.onWindowBorderChanged(aWindow);
799+
}
800+
801+
}
802+
785803
}

app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package org.mozilla.vrbrowser.utils;
22

3+
import android.graphics.Color;
34
import android.os.Build;
45
import android.text.Html;
56
import android.text.SpannableStringBuilder;
67
import android.text.Spanned;
78
import android.text.method.LinkMovementMethod;
89
import android.text.style.ClickableSpan;
910
import android.text.style.URLSpan;
11+
import android.util.Log;
1012
import android.view.View;
1113
import android.view.ViewGroup;
1214
import android.view.ViewParent;
@@ -117,4 +119,7 @@ public static boolean isInsideView(@NotNull View view, int rx, int ry) {
117119
return true;
118120
}
119121

122+
public static int ARGBtoRGBA(int c) {
123+
return (c & 0x00FFFFFF) << 8 | (c & 0xFF000000) >>> 24;
124+
}
120125
}

app/src/main/cpp/BrowserWorld.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,8 @@ BrowserWorld::UpdateWidget(int32_t aHandle, const WidgetPlacementPtr& aPlacement
910910
widget->SetWorldWidth(newWorldWidth);
911911
}
912912

913+
widget->SetBorderColor(vrb::Color(aPlacement->borderColor));
914+
widget->SetProxifyLayer(aPlacement->proxifyLayer);
913915
LayoutWidget(aHandle);
914916
}
915917

0 commit comments

Comments
 (0)