From 75d574c53abc284e22a40686311b9faa4bb61d84 Mon Sep 17 00:00:00 2001 From: Sergio Villar Senin Date: Fri, 23 Feb 2024 18:38:19 +0100 Subject: [PATCH 1/4] [VisionGlass] Decouple Phone UI initialization from glasses initialization Prevents errors that might appear due to UI elements not being properly initialized or UI layouts not being inflated because the code is trying to initialize the whole VisionGlass system (note that VisionGlass initialization is fundamentally an async process). --- .../com/igalia/wolvic/PlatformActivity.java | 91 ++++++++++--------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java b/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java index 4873e3ae18..0e636f82eb 100644 --- a/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java @@ -141,6 +141,8 @@ protected void onCreate(Bundle savedInstanceState) { usbPermissionFilter.addAction(HUAWEI_USB_PERMISSION); registerReceiver(mUsbPermissionReceiver, usbPermissionFilter); + initVisionGlassPhoneUI(); + VisionGlass.getInstance().init(getApplication()); VisionGlass.getInstance().setOnConnectionListener(this); initVisionGlass(); @@ -160,49 +162,7 @@ public void onConnectionChange(boolean b) { } } - private void initVisionGlass() { - Log.d(LOGTAG, "initVisionGlass"); - - if (mWasImuStarted) { - Log.d(LOGTAG, "Duplicated call to init the Vision Glass system"); - updateDisplays(); - return; - } - - if (!VisionGlass.getInstance().isConnected()) { - Log.d(LOGTAG, "Glasses not connected yet"); - return; - } - - if (!VisionGlass.getInstance().hasUsbPermission()) { - if (!mIsAskingForPermission) { - Log.d(LOGTAG, "Asking for USB permission"); - mIsAskingForPermission = true; - VisionGlass.getInstance().requestUsbPermission(); - } - return; - } - - Log.d(LOGTAG, "Starting IMU"); - - mWasImuStarted = true; - VisionGlass.getInstance().startImu((w, x, y, z) -> queueRunnable(() -> setHead(x, y, z, w))); - - VisionGlass.getInstance().setDisplayMode(DisplayMode.vr3d, new DisplayModeCallback() { - @Override - public void onSuccess(DisplayMode displayMode) { - Log.d(LOGTAG, "Successfully switched to 3D mode"); - updateDisplays(); - } - - @Override - public void onError(String s, int i) { - Log.d(LOGTAG, "Error " + i + "; failed to switch to 3D mode: " + s); - mWasImuStarted = false; - updateDisplays(); - } - }); - + private void initVisionGlassPhoneUI() { setContentView(R.layout.visionglass_layout); View touchpad = findViewById(R.id.touchpad); @@ -250,6 +210,51 @@ public void onError(String s, int i) { })); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + + private void initVisionGlass() { + Log.d(LOGTAG, "initVisionGlass"); + + if (mWasImuStarted) { + Log.d(LOGTAG, "Duplicated call to init the Vision Glass system"); + updateDisplays(); + return; + } + + if (!VisionGlass.getInstance().isConnected()) { + Log.d(LOGTAG, "Glasses not connected yet"); + return; + } + + if (!VisionGlass.getInstance().hasUsbPermission()) { + if (!mIsAskingForPermission) { + Log.d(LOGTAG, "Asking for USB permission"); + mIsAskingForPermission = true; + VisionGlass.getInstance().requestUsbPermission(); + } + return; + } + + Log.d(LOGTAG, "Starting IMU"); + + mWasImuStarted = true; + VisionGlass.getInstance().startImu((w, x, y, z) -> queueRunnable(() -> setHead(x, y, z, w))); + + VisionGlass.getInstance().setDisplayMode(DisplayMode.vr3d, new DisplayModeCallback() { + @Override + public void onSuccess(DisplayMode displayMode) { + Log.d(LOGTAG, "Successfully switched to 3D mode"); + updateDisplays(); + } + + @Override + public void onError(String s, int i) { + Log.d(LOGTAG, "Error " + i + "; failed to switch to 3D mode: " + s); + mWasImuStarted = false; + updateDisplays(); + } + }); // Show the app if (getLifecycle().getCurrentState() == Lifecycle.State.RESUMED) { From 2656e1a11906e917832631b9d60799d61c8aba6d Mon Sep 17 00:00:00 2001 From: Sergio Villar Senin Date: Tue, 27 Feb 2024 11:18:09 +0100 Subject: [PATCH 2/4] Introducing the PlatformActivityPlugin interface The current architecture of the Activity class is suboptimal. The main class, the VRBrowserActivity, turns out to be a subclass of a PlatformActivity class which is platform specific (because some flavours inherit from different types of Activity). The problem is that we cannot add platform specifics to VRBrowserActivity, but at the same time it's the class that has all the information, so it's complex to do anything meaningful at the PlatformActivity level. In order to do that in a clean way we're adding this new interface which will be implemented and instantiated at the PlatformActivity level. It'll contain the platform specific code, and as it will be used by VRBrowserActivity, it would receive any required information as parametters of the different interface methods. This way we could encapsulate platform specifics at the PlatformActivity level without losing access to the data/methods of the VRBrowserActivity. --- .../com/igalia/wolvic/PlatformActivity.java | 3 ++ .../igalia/wolvic/PlatformActivityPlugin.java | 5 ++ .../com/igalia/wolvic/VRBrowserActivity.java | 10 ++++ .../com/igalia/wolvic/PlatformActivity.java | 2 + .../com/igalia/wolvic/PlatformActivity.java | 4 ++ .../com/igalia/wolvic/PlatformActivity.java | 3 ++ .../com/igalia/wolvic/PlatformActivity.java | 2 + .../com/igalia/wolvic/PlatformActivity.java | 4 ++ .../com/igalia/wolvic/PlatformActivity.java | 3 ++ .../com/igalia/wolvic/PlatformActivity.java | 47 ++++++++++++------- .../mozilla/vrbrowser/PlatformActivity.java | 3 ++ 11 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java diff --git a/app/src/aosp/java/com/igalia/wolvic/PlatformActivity.java b/app/src/aosp/java/com/igalia/wolvic/PlatformActivity.java index cbec98275e..c06e2bdcb2 100644 --- a/app/src/aosp/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/aosp/java/com/igalia/wolvic/PlatformActivity.java @@ -11,6 +11,7 @@ import android.view.View; import android.view.WindowManager; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; public class PlatformActivity extends NativeActivity { @@ -30,6 +31,8 @@ public static boolean isPositionTrackingSupported() { return true; } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + protected Intent getStoreIntent() { // Dummy implementation. return null; diff --git a/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java b/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java new file mode 100644 index 0000000000..8e6ab79cae --- /dev/null +++ b/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java @@ -0,0 +1,5 @@ +package com.igalia.wolvic; + +public interface PlatformActivityPlugin { + void onKeyboardVisibilityChange(boolean isVisible); +} diff --git a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java index 030e95c86c..ac4b9b4bf4 100644 --- a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java +++ b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java @@ -245,6 +245,7 @@ public void run() { private boolean mIsPassthroughEnabled = false; private long mLastBatteryUpdate = System.nanoTime(); private int mLastBatteryLevel = -1; + private PlatformActivityPlugin mPlatformPlugin; private boolean callOnAudioManager(Consumer fn) { if (mAudioManager == null) { @@ -450,6 +451,9 @@ public void onWindowVideoAvailabilityChanged(@NonNull WindowWidget aWindow) { addWidgets(Arrays.asList(mRootWidget, mNavigationBar, mKeyboard, mTray, mWebXRInterstitial)); + // Create the platform plugin after widgets are created to be extra safe. + mPlatformPlugin = createPlatformPlugin(this); + mWindows.restoreSessions(); } @@ -1676,6 +1680,10 @@ public void updateWidget(final Widget aWidget) { view.setVisibility(visible ? View.VISIBLE : View.GONE); } + if (aWidget == mKeyboard && mPlatformPlugin != null) { + mPlatformPlugin.onKeyboardVisibilityChange(visible); + } + for (UpdateListener listener: mWidgetUpdateListeners) { listener.onWidgetUpdate(aWidget); } @@ -1899,6 +1907,8 @@ public void setWindowSize(float targetWidth, float targetHeight) { @Override public void keyboardDismissed() { mNavigationBar.showVoiceSearch(); + if (mPlatformPlugin != null) + mPlatformPlugin.onKeyboardVisibilityChange(false); } @Override diff --git a/app/src/hvr/java/com/igalia/wolvic/PlatformActivity.java b/app/src/hvr/java/com/igalia/wolvic/PlatformActivity.java index ace01e7f48..02fb7e10cd 100644 --- a/app/src/hvr/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/hvr/java/com/igalia/wolvic/PlatformActivity.java @@ -372,6 +372,8 @@ public void surfaceDestroyed(SurfaceHolder holder) queueRunnable(this::nativeOnSurfaceDestroyed); } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + protected boolean platformExit() { return false; } diff --git a/app/src/lynx/java/com/igalia/wolvic/PlatformActivity.java b/app/src/lynx/java/com/igalia/wolvic/PlatformActivity.java index cbec98275e..7703d2bfa8 100644 --- a/app/src/lynx/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/lynx/java/com/igalia/wolvic/PlatformActivity.java @@ -11,6 +11,7 @@ import android.view.View; import android.view.WindowManager; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; public class PlatformActivity extends NativeActivity { @@ -44,6 +45,9 @@ public void run() { } }); } + + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + protected native void queueRunnable(Runnable aRunnable); protected native boolean platformExit(); } diff --git a/app/src/noapi/java/com/igalia/wolvic/PlatformActivity.java b/app/src/noapi/java/com/igalia/wolvic/PlatformActivity.java index 7cef680eb9..4b943c9cd7 100644 --- a/app/src/noapi/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/noapi/java/com/igalia/wolvic/PlatformActivity.java @@ -20,6 +20,7 @@ import androidx.annotation.Keep; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; import java.util.ArrayList; @@ -163,6 +164,8 @@ public boolean onGenericMotionEvent(MotionEvent aEvent) { return true; } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + @Override protected void onPause() { Log.d(LOGTAG, "PlatformActivity onPause"); diff --git a/app/src/oculusvr/java/com/igalia/wolvic/PlatformActivity.java b/app/src/oculusvr/java/com/igalia/wolvic/PlatformActivity.java index 08e25642ac..69a35ad325 100644 --- a/app/src/oculusvr/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/oculusvr/java/com/igalia/wolvic/PlatformActivity.java @@ -21,6 +21,7 @@ import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; public class PlatformActivity extends NativeActivity { @@ -122,6 +123,7 @@ public WindowInsetsCompat onApplyWindowInsets( ); } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } protected native void queueRunnable(Runnable aRunnable); protected native boolean platformExit(); diff --git a/app/src/picoxr/java/com/igalia/wolvic/PlatformActivity.java b/app/src/picoxr/java/com/igalia/wolvic/PlatformActivity.java index 475f608e36..63f1a7c7fd 100644 --- a/app/src/picoxr/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/picoxr/java/com/igalia/wolvic/PlatformActivity.java @@ -9,6 +9,8 @@ import android.content.Intent; import android.view.KeyEvent; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; + public class PlatformActivity extends NativeActivity { public static boolean filterPermission(final String aPermission) { @@ -26,6 +28,8 @@ public static boolean isPositionTrackingSupported() { return true; } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + protected Intent getStoreIntent() { // Dummy implementation. return null; diff --git a/app/src/spaces/java/com/igalia/wolvic/PlatformActivity.java b/app/src/spaces/java/com/igalia/wolvic/PlatformActivity.java index cbec98275e..9b4db48b0b 100644 --- a/app/src/spaces/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/spaces/java/com/igalia/wolvic/PlatformActivity.java @@ -11,6 +11,7 @@ import android.view.View; import android.view.WindowManager; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; public class PlatformActivity extends NativeActivity { @@ -35,6 +36,8 @@ protected Intent getStoreIntent() { return null; } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + @Override public void onBackPressed() { queueRunnable(new Runnable() { diff --git a/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java b/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java index 0e636f82eb..3294c48636 100644 --- a/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java +++ b/app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java @@ -40,7 +40,7 @@ import com.huawei.usblib.DisplayModeCallback; import com.huawei.usblib.OnConnectionListener; import com.huawei.usblib.VisionGlass; -import com.igalia.wolvic.ui.widgets.Windows; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; import java.util.ArrayList; @@ -192,22 +192,7 @@ private void initVisionGlassPhoneUI() { }); ImageButton backButton = findViewById(R.id.back_button); - ImageButton homeButton = findViewById(R.id.home_button); - backButton.setOnClickListener(v -> onBackPressed()); - homeButton.setOnClickListener(v -> runPhoneUICallback((activity) -> { - Windows windows = activity.getWindows(); - if (windows == null) { - Log.e(LOGTAG, "Cannot load homepage because Windows object is null"); - return; - } - windows.getFocusedWindow().loadHome(); - })); - - ToggleButton headlockButton = findViewById(R.id.headlock_toggle_button); - headlockButton.setOnClickListener(v -> runPhoneUICallback((activity) -> { - activity.setHeadLockEnabled(headlockButton.isChecked()); - })); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @@ -424,6 +409,36 @@ private void updateDisplays() { runOnUiThread(this::showPresentation); } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { + return new PlatformActivityPluginVisionGlass(delegate); + } + + private class PlatformActivityPluginVisionGlass implements PlatformActivityPlugin { + private WidgetManagerDelegate mDelegate; + + PlatformActivityPluginVisionGlass(WidgetManagerDelegate delegate) { + mDelegate = delegate; + setupPhoneUI(); + } + + @Override + public void onKeyboardVisibilityChange(boolean isVisible) { + } + + // Setup the phone UI callbacks that require access to the WindowManagerDelegate. + private void setupPhoneUI() { + findViewById(R.id.home_button).setOnClickListener(v -> { + mDelegate.getWindows().getFocusedWindow().loadHome(); + }); + + ToggleButton headlockButton = findViewById(R.id.headlock_toggle_button); + headlockButton.setOnClickListener(v -> { + mDelegate.setHeadLockEnabled(headlockButton.isChecked()); + }); + + } + } + private final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { @Override diff --git a/app/src/wavevr/java/org/mozilla/vrbrowser/PlatformActivity.java b/app/src/wavevr/java/org/mozilla/vrbrowser/PlatformActivity.java index 1b64bea09f..d4509d5300 100644 --- a/app/src/wavevr/java/org/mozilla/vrbrowser/PlatformActivity.java +++ b/app/src/wavevr/java/org/mozilla/vrbrowser/PlatformActivity.java @@ -13,6 +13,7 @@ import android.os.Bundle; import android.view.KeyEvent; +import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate; import com.igalia.wolvic.utils.SystemUtils; public class PlatformActivity extends VRActivity { @@ -60,6 +61,8 @@ public void onBackPressed() { // the system menu to exit applications. } + public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate delegate) { return null; } + protected native void queueRunnable(Runnable aRunnable); protected native void initializeJava(AssetManager aAssets); } From 1c7e3c546f69ce0d1eac85b5bd9325ba6cb93a7a Mon Sep 17 00:00:00 2001 From: Sergio Villar Senin Date: Tue, 27 Feb 2024 18:33:27 +0100 Subject: [PATCH 3/4] [VisionGlass] Add voice search button to Phone UI Added a new Voice Search button to the phone UI. It's only enabled when the keyboard is shown, i.e., when input is required. Once clicked the handling of the input is directly managed by the KeyboardWidget which properly handles the different types of input (like entering text in a Web page vs entering text in a UI widget). --- .../shared/com/igalia/wolvic/VRBrowserActivity.java | 3 +++ .../com/igalia/wolvic/ui/widgets/KeyboardWidget.java | 5 +++++ .../wolvic/ui/widgets/WidgetManagerDelegate.java | 1 + app/src/main/res/layout/visionglass_layout.xml | 5 ++--- .../java/com/igalia/wolvic/PlatformActivity.java | 10 ++++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java index ac4b9b4bf4..9db705dcd9 100644 --- a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java +++ b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java @@ -2118,6 +2118,9 @@ public AppServicesProvider getServicesProvider() { return (AppServicesProvider)getApplication(); } + @Override + public KeyboardWidget getKeyboard() { return mKeyboard; } + private native void addWidgetNative(int aHandle, WidgetPlacement aPlacement); private native void updateWidgetNative(int aHandle, WidgetPlacement aPlacement); private native void updateVisibleWidgetsNative(); diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/KeyboardWidget.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/KeyboardWidget.java index 7bd79d67e6..0f2845d036 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/KeyboardWidget.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/KeyboardWidget.java @@ -1496,4 +1496,9 @@ public void onSessionChanged(@NonNull Session aOldSession, @NonNull Session aSes aOldSession.removeTextInputListener(this); aSession.addTextInputListener(this); } + + public void simulateVoiceButtonClick() { + mKeyboardVoiceButton.performClick(); + } + } diff --git a/app/src/common/shared/com/igalia/wolvic/ui/widgets/WidgetManagerDelegate.java b/app/src/common/shared/com/igalia/wolvic/ui/widgets/WidgetManagerDelegate.java index 9947b7f3af..77c5aff6ed 100644 --- a/app/src/common/shared/com/igalia/wolvic/ui/widgets/WidgetManagerDelegate.java +++ b/app/src/common/shared/com/igalia/wolvic/ui/widgets/WidgetManagerDelegate.java @@ -124,4 +124,5 @@ interface WebXRListener { void updateLocale(@NonNull Context context); @NonNull AppServicesProvider getServicesProvider(); + KeyboardWidget getKeyboard(); } diff --git a/app/src/main/res/layout/visionglass_layout.xml b/app/src/main/res/layout/visionglass_layout.xml index 3ef7aa954a..0d9263c716 100644 --- a/app/src/main/res/layout/visionglass_layout.xml +++ b/app/src/main/res/layout/visionglass_layout.xml @@ -28,14 +28,13 @@ android:textOn="" /> + android:src="@drawable/ic_icon_microphone" /> { // We don't really need the coordinates of the click because we use the position @@ -423,6 +427,7 @@ private class PlatformActivityPluginVisionGlass implements PlatformActivityPlugi @Override public void onKeyboardVisibilityChange(boolean isVisible) { + mVoiceSearchButton.setEnabled(isVisible); } // Setup the phone UI callbacks that require access to the WindowManagerDelegate. @@ -436,6 +441,11 @@ private void setupPhoneUI() { mDelegate.setHeadLockEnabled(headlockButton.isChecked()); }); + findViewById(R.id.phoneUIVoiceButton).setOnClickListener(v -> { + // Delegate all the voice input handling in the KeyboardWidget which already handles + // all the potential voice input cases. + mDelegate.getKeyboard().simulateVoiceButtonClick(); + }); } } From d4a0e914ef9519524aeb6e1af6b2782268fddd74 Mon Sep 17 00:00:00 2001 From: Sergio Villar Senin Date: Tue, 27 Feb 2024 19:06:08 +0100 Subject: [PATCH 4/4] [VisionGlass] Add Media Playback controls to Phone UI Media controls were added to the phone UI using the newly added PlatformActivityPlugin architecture. The media playback controls are only shown whenever the web engine detects that a media element is present and hidden as soon as the media element is gone. The controls include play/pause button, mute button, fast forward and fast backward buttons and a progress seekbar. There are some caveats though caused by limitations of the GeckoView API, for example progress information is only issued for fullscreen media. --- .../igalia/wolvic/PlatformActivityPlugin.java | 1 + .../com/igalia/wolvic/VRBrowserActivity.java | 4 + .../main/res/layout/visionglass_layout.xml | 56 +++++++++++ .../com/igalia/wolvic/PlatformActivity.java | 95 +++++++++++++++++++ 4 files changed, 156 insertions(+) diff --git a/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java b/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java index 8e6ab79cae..bad5291d8c 100644 --- a/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java +++ b/app/src/common/shared/com/igalia/wolvic/PlatformActivityPlugin.java @@ -2,4 +2,5 @@ public interface PlatformActivityPlugin { void onKeyboardVisibilityChange(boolean isVisible); + void onVideoAvailabilityChange(); } diff --git a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java index 9db705dcd9..8e55333cb3 100644 --- a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java +++ b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java @@ -440,6 +440,10 @@ public void onWindowVideoAvailabilityChanged(@NonNull WindowWidget aWindow) { WidgetManagerDelegate.CPU_LEVEL_NORMAL; queueRunnable(() -> setCPULevelNative(cpuLevel)); + + if (mPlatformPlugin != null) { + mPlatformPlugin.onVideoAvailabilityChange(); + } } }); diff --git a/app/src/main/res/layout/visionglass_layout.xml b/app/src/main/res/layout/visionglass_layout.xml index 0d9263c716..9779d62045 100644 --- a/app/src/main/res/layout/visionglass_layout.xml +++ b/app/src/main/res/layout/visionglass_layout.xml @@ -1,5 +1,6 @@ @@ -47,6 +48,61 @@ android:layout_marginTop="10dp" android:layout_marginBottom="10dp"/> + + + + + + + + + + + + + + + + + + + { @@ -441,11 +486,61 @@ private void setupPhoneUI() { mDelegate.setHeadLockEnabled(headlockButton.isChecked()); }); + findViewById(R.id.phoneUIPlayButton).setOnClickListener(v -> { + Media media = getActiveMedia(); + if (media == null) + return; + if (media.isPlaying()) { + media.pause(); + } else { + media.play(); + } + }); + + findViewById(R.id.phoneUISeekBackward10Button).setOnClickListener(v -> { + Media media = getActiveMedia(); + if (media == null) + return; + media.seek(media.getCurrentTime() - 10); + }); + + findViewById(R.id.phoneUISeekForward30Button).setOnClickListener(v -> { + Media media = getActiveMedia(); + if (media == null) + return; + media.seek(media.getCurrentTime() + 30); + }); + findViewById(R.id.phoneUIVoiceButton).setOnClickListener(v -> { // Delegate all the voice input handling in the KeyboardWidget which already handles // all the potential voice input cases. mDelegate.getKeyboard().simulateVoiceButtonClick(); }); + + findViewById(R.id.phoneUIMuteButton).setOnClickListener(v -> { + Media media = getActiveMedia(); + if (media == null) + return; + media.setMuted(!media.isMuted()); + ((ImageButton) findViewById(R.id.phoneUIMuteButton)).setImageResource(!media.isMuted() ? R.drawable.ic_icon_media_volume : R.drawable.ic_icon_media_volume_muted); + }); + + mMediaSeekbar = findViewById(R.id.phoneUIMediaSeekBar); + mMediaSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) {} + + @Override + public void onStartTrackingTouch(SeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + Media media = getActiveMedia(); + if (media == null || !media.canSeek() || media.getDuration() == 0) + return; + media.seek((seekBar.getProgress() / 100.0) * media.getDuration()); + } + }); } }