Skip to content

Commit 627c6e2

Browse files
authored
Merge pull request #8316 from han-sz/fix_video_mouse_hover_overlay
Fix persistent hover overlay when in desktop/DeX mode or using a mouse/non-touch input
2 parents 95c32d6 + abf1cc5 commit 627c6e2

2 files changed

Lines changed: 104 additions & 13 deletions

File tree

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -642,19 +642,7 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
642642
? View.VISIBLE
643643
: View.GONE
644644
);
645-
646-
if (DeviceUtils.isTv(getContext())) {
647-
// remove ripple effects from detail controls
648-
final int transparent = ContextCompat.getColor(requireContext(),
649-
R.color.transparent_background_color);
650-
binding.detailControlsPlaylistAppend.setBackgroundColor(transparent);
651-
binding.detailControlsBackground.setBackgroundColor(transparent);
652-
binding.detailControlsPopup.setBackgroundColor(transparent);
653-
binding.detailControlsDownload.setBackgroundColor(transparent);
654-
binding.detailControlsShare.setBackgroundColor(transparent);
655-
binding.detailControlsOpenInBrowser.setBackgroundColor(transparent);
656-
binding.detailControlsPlayWithKodi.setBackgroundColor(transparent);
657-
}
645+
accommodateForTvAndDesktopMode();
658646
}
659647

660648
@Override
@@ -2118,6 +2106,30 @@ private void setupBrightness() {
21182106
}
21192107
}
21202108

2109+
/**
2110+
* Make changes to the UI to accommodate for better usability on bigger screens such as TVs
2111+
* or in Android's desktop mode (DeX etc).
2112+
*/
2113+
private void accommodateForTvAndDesktopMode() {
2114+
if (DeviceUtils.isTv(getContext())) {
2115+
// remove ripple effects from detail controls
2116+
final int transparent = ContextCompat.getColor(requireContext(),
2117+
R.color.transparent_background_color);
2118+
binding.detailControlsPlaylistAppend.setBackgroundColor(transparent);
2119+
binding.detailControlsBackground.setBackgroundColor(transparent);
2120+
binding.detailControlsPopup.setBackgroundColor(transparent);
2121+
binding.detailControlsDownload.setBackgroundColor(transparent);
2122+
binding.detailControlsShare.setBackgroundColor(transparent);
2123+
binding.detailControlsOpenInBrowser.setBackgroundColor(transparent);
2124+
binding.detailControlsPlayWithKodi.setBackgroundColor(transparent);
2125+
}
2126+
if (DeviceUtils.isDesktopMode(getContext())) {
2127+
// Remove the "hover" overlay (since it is visible on all mouse events and interferes
2128+
// with the video content being played)
2129+
binding.detailThumbnailRootLayout.setForeground(null);
2130+
}
2131+
}
2132+
21212133
private void checkLandscape() {
21222134
if ((!player.isPlaying() && player.getPlayQueue() != playQueue)
21232135
|| player.getPlayQueue() == null) {

app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package org.schabi.newpipe.util;
22

3+
import android.annotation.SuppressLint;
34
import android.app.UiModeManager;
45
import android.content.Context;
56
import android.content.pm.PackageManager;
67
import android.content.res.Configuration;
78
import android.graphics.Point;
9+
import android.hardware.input.InputManager;
810
import android.os.BatteryManager;
911
import android.os.Build;
1012
import android.provider.Settings;
1113
import android.util.TypedValue;
14+
import android.view.InputDevice;
1215
import android.view.KeyEvent;
1316
import android.view.WindowInsets;
1417
import android.view.WindowManager;
@@ -22,6 +25,10 @@
2225
import org.schabi.newpipe.App;
2326
import org.schabi.newpipe.R;
2427

28+
import java.lang.reflect.Method;
29+
30+
import static android.content.Context.INPUT_SERVICE;
31+
2532
public final class DeviceUtils {
2633

2734
private static final String AMAZON_FEATURE_FIRE_TV = "amazon.hardware.fire_tv";
@@ -84,6 +91,78 @@ public static boolean isTv(final Context context) {
8491
return DeviceUtils.isTV;
8592
}
8693

94+
/**
95+
* Checks if the device is in desktop or DeX mode. This function should only
96+
* be invoked once on view load as it is using reflection for the DeX checks.
97+
* @param context the context to use for services and config.
98+
* @return true if the Android device is in desktop mode or using DeX.
99+
*/
100+
@SuppressWarnings("JavaReflectionMemberAccess")
101+
public static boolean isDesktopMode(@NonNull final Context context) {
102+
// Adapted from https://stackoverflow.com/a/64615568
103+
// to check for all input devices that have an active cursor
104+
final InputManager im = (InputManager) context.getSystemService(INPUT_SERVICE);
105+
for (final int id : im.getInputDeviceIds()) {
106+
final InputDevice inputDevice = im.getInputDevice(id);
107+
if (inputDevice.supportsSource(InputDevice.SOURCE_BLUETOOTH_STYLUS)
108+
|| inputDevice.supportsSource(InputDevice.SOURCE_MOUSE)
109+
|| inputDevice.supportsSource(InputDevice.SOURCE_STYLUS)
110+
|| inputDevice.supportsSource(InputDevice.SOURCE_TOUCHPAD)
111+
|| inputDevice.supportsSource(InputDevice.SOURCE_TRACKBALL)) {
112+
return true;
113+
}
114+
}
115+
116+
final UiModeManager uiModeManager =
117+
ContextCompat.getSystemService(context, UiModeManager.class);
118+
if (uiModeManager != null
119+
&& uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_DESK) {
120+
return true;
121+
}
122+
123+
// DeX check for standalone and multi-window mode, from:
124+
// https://developer.samsung.com/samsung-dex/modify-optimizing.html
125+
try {
126+
final Configuration config = context.getResources().getConfiguration();
127+
final Class<?> configClass = config.getClass();
128+
final int semDesktopModeEnabledConst =
129+
configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass);
130+
final int currentMode =
131+
configClass.getField("semDesktopModeEnabled").getInt(config);
132+
if (semDesktopModeEnabledConst == currentMode) {
133+
return true;
134+
}
135+
} catch (final NoSuchFieldException | IllegalAccessException ignored) {
136+
// Device doesn't seem to support DeX
137+
}
138+
139+
@SuppressLint("WrongConstant") final Object desktopModeManager = context
140+
.getApplicationContext()
141+
.getSystemService("desktopmode");
142+
143+
if (desktopModeManager != null) {
144+
try {
145+
final Method getDesktopModeStateMethod = desktopModeManager.getClass()
146+
.getDeclaredMethod("getDesktopModeState");
147+
final Object desktopModeState = getDesktopModeStateMethod
148+
.invoke(desktopModeManager);
149+
final Class<?> desktopModeStateClass = desktopModeState.getClass();
150+
final Method getEnabledMethod = desktopModeStateClass
151+
.getDeclaredMethod("getEnabled");
152+
final int enabledStatus = (int) getEnabledMethod.invoke(desktopModeState);
153+
if (enabledStatus == desktopModeStateClass
154+
.getDeclaredField("ENABLED").getInt(desktopModeStateClass)) {
155+
return true;
156+
}
157+
} catch (final Exception ignored) {
158+
// Device does not support DeX 3.0 or something went wrong when trying to determine
159+
// if it supports this feature
160+
}
161+
}
162+
163+
return false;
164+
}
165+
87166
public static boolean isTablet(@NonNull final Context context) {
88167
final String tabletModeSetting = PreferenceManager.getDefaultSharedPreferences(context)
89168
.getString(context.getString(R.string.tablet_mode_key), "");

0 commit comments

Comments
 (0)