Skip to content

Commit

Permalink
[VisionGlass] Add Media Playback controls to Phone UI
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
svillar authored and felipeerias committed Feb 28, 2024
1 parent 2377bad commit 18e279a
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

public interface PlatformActivityPlugin {
void onKeyboardVisibilityChange(boolean isVisible);
void onVideoAvailabilityChange();
}
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ public void onWindowVideoAvailabilityChanged(@NonNull WindowWidget aWindow) {
WidgetManagerDelegate.CPU_LEVEL_NORMAL;

queueRunnable(() -> setCPULevelNative(cpuLevel));

if (mPlatformPlugin != null) {
mPlatformPlugin.onVideoAvailabilityChange();
}
}
});

Expand Down
56 changes: 56 additions & 0 deletions app/src/main/res/layout/visionglass_layout.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

Expand Down Expand Up @@ -47,6 +48,61 @@
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"/>

<LinearLayout
android:id="@+id/phoneUIMediaControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">

<SeekBar
android:id="@+id/phoneUIMediaSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.10"
android:orientation="horizontal">

<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />

<ImageButton
android:id="@+id/phoneUISeekBackward10Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:src="@drawable/ic_icon_media_seek_backward_10" />

<ImageButton
android:id="@+id/phoneUIPlayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@android:drawable/ic_media_play" />

<ImageButton
android:id="@+id/phoneUISeekForward30Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:src="@drawable/ic_icon_media_seek_forward_30" />

<ImageButton
android:id="@+id/phoneUIMuteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:src="@drawable/ic_icon_media_volume" />
</LinearLayout>

</LinearLayout>

<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
Expand Down
95 changes: 95 additions & 0 deletions app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.ToggleButton;

import androidx.activity.ComponentActivity;
Expand All @@ -40,6 +41,9 @@
import com.huawei.usblib.DisplayModeCallback;
import com.huawei.usblib.OnConnectionListener;
import com.huawei.usblib.VisionGlass;
import com.igalia.wolvic.browser.Media;
import com.igalia.wolvic.browser.api.WMediaSession;
import com.igalia.wolvic.browser.api.WSession;
import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate;
import com.igalia.wolvic.utils.SystemUtils;

Expand Down Expand Up @@ -419,6 +423,8 @@ public final PlatformActivityPlugin createPlatformPlugin(WidgetManagerDelegate d

private class PlatformActivityPluginVisionGlass implements PlatformActivityPlugin {
private WidgetManagerDelegate mDelegate;
private WMediaSession.Delegate mMediaSessionDelegate;
private SeekBar mMediaSeekbar;

PlatformActivityPluginVisionGlass(WidgetManagerDelegate delegate) {
mDelegate = delegate;
Expand All @@ -430,6 +436,45 @@ public void onKeyboardVisibilityChange(boolean isVisible) {
mVoiceSearchButton.setEnabled(isVisible);
}

@Override
public void onVideoAvailabilityChange() {
boolean isAvailable = mDelegate.getWindows().isVideoAvailable();
findViewById(R.id.phoneUIMediaControls).setVisibility(isAvailable ? View.VISIBLE : View.GONE);

Media media = getActiveMedia();
if (!isAvailable) {
if (media != null) {
media.removeMediaListener(mMediaSessionDelegate);
mMediaSessionDelegate = null;
}
return;
}

assert(media != null);
media.addMediaListener(new WMediaSession.Delegate() {
@Override
public void onPlay(@NonNull WSession session, @NonNull WMediaSession mediaSession) {
((ImageButton) findViewById(R.id.phoneUIPlayButton)).setImageResource(R.drawable.ic_icon_media_pause);
}

@Override
public void onPause(@NonNull WSession session, @NonNull WMediaSession mediaSession) {
((ImageButton) findViewById(R.id.phoneUIPlayButton)).setImageResource(R.drawable.ic_icon_media_play);
}

@Override
public void onPositionState(@NonNull WSession session, @NonNull WMediaSession mediaSession, @NonNull WMediaSession.PositionState state) {
mMediaSeekbar.setProgress((int) ((state.position / state.duration) * 100), false);
}
});
}

private Media getActiveMedia() {
assert mDelegate.getWindows() != null;
assert mDelegate.getWindows().getFocusedWindow() != null;
return mDelegate.getWindows().getFocusedWindow().getSession().getActiveVideo();
}

// Setup the phone UI callbacks that require access to the WindowManagerDelegate.
private void setupPhoneUI() {
findViewById(R.id.home_button).setOnClickListener(v -> {
Expand All @@ -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());
}
});
}
}

Expand Down

0 comments on commit 18e279a

Please sign in to comment.