Plugins/MousePadPlugin: Consolidate Bigscreen remote and mousepad into one plugin for TV targets

When connected to a TV (running Plasma Bigscreen), Remote Input will show a TV remote and a button on the top to switch to mouse and keyboard. When connected to any other device, Remote Input will show the mouse and keyboard only.

**Removals:**
- [x] Remove BigscreenPlugin

**Additions:**
- [x] Add "Use mouse and keyboard"

**Changes:**
- [x] Plugin has both remote and mouse/keyboard if device is TV, just mouse/keyboard otherwise

**Code changes:**
- [x] Move all TV functions to MousePlugin

![Screencast_20250519_174042](/uploads/606b32ddc584025fea5fa49b006f3a79/Screencast_20250519_174042.mp4)
This commit is contained in:
User8395
2025-09-04 00:34:07 +00:00
committed by Philip Cohn-Cort
parent 1d833841f5
commit f392ea0a12
8 changed files with 119 additions and 159 deletions

View File

@@ -268,7 +268,7 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
</intent-filter>
</activity>
<activity
android:name="org.kde.kdeconnect.Plugins.BigscreenPlugin.BigscreenActivity"
android:name="org.kde.kdeconnect.Plugins.MousePadPlugin.BigscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/pref_plugin_bigscreen"
android:exported="true"

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M360,840L600,840Q600,840 600,840Q600,840 600,840L600,640Q575,659 544.5,669.5Q514,680 480,680Q446,680 415.5,669.5Q385,659 360,640L360,840Q360,840 360,840Q360,840 360,840ZM480,600Q530,600 565,565Q600,530 600,480Q600,430 565,395Q530,360 480,360Q430,360 395,395Q360,430 360,480Q360,530 395,565Q430,600 480,600ZM360,320Q385,301 415.5,290.5Q446,280 480,280Q514,280 544.5,290.5Q575,301 600,320L600,120Q600,120 600,120Q600,120 600,120L360,120Q360,120 360,120Q360,120 360,120L360,320ZM360,920Q327,920 303.5,896.5Q280,873 280,840L280,120Q280,87 303.5,63.5Q327,40 360,40L600,40Q633,40 656.5,63.5Q680,87 680,120L680,840Q680,873 656.5,896.5Q633,920 600,920L360,920ZM480,540Q455,540 437.5,522.5Q420,505 420,480Q420,455 437.5,437.5Q455,420 480,420Q505,420 522.5,437.5Q540,455 540,480Q540,505 522.5,522.5Q505,540 480,540ZM480,240Q497,240 508.5,228.5Q520,217 520,200Q520,183 508.5,171.5Q497,160 480,160Q463,160 451.5,171.5Q440,183 440,200Q440,217 451.5,228.5Q463,240 480,240ZM480,680Q480,680 480,680Q480,680 480,680L480,680Q480,680 480,680Q480,680 480,680Q480,680 480,680Q480,680 480,680L480,680Q480,680 480,680Q480,680 480,680ZM480,280L480,280Q480,280 480,280Q480,280 480,280L480,280Q480,280 480,280Q480,280 480,280L480,280Q480,280 480,280Q480,280 480,280Q480,280 480,280Q480,280 480,280Z"/>
</vector>

View File

@@ -12,7 +12,7 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.kde.kdeconnect.Plugins.BigscreenPlugin.BigscreenActivity">
tools:context="org.kde.kdeconnect.Plugins.MousePadPlugin.BigscreenActivity">
<include layout="@layout/toolbar" android:id="@+id/toolbar_layout" />

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:kdeconnect="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_use_mouse_and_keyboard"
android:icon="@drawable/touchpad_plugin_action_24dp"
android:title="@string/show_mouse_and_keyboard"
kdeconnect:iconTint="?colorOnBackground"
kdeconnect:showAsAction="ifRoom" />
</menu>

View File

@@ -30,7 +30,8 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="pref_plugin_clipboard_desc">Share the clipboard content</string>
<string name="pref_plugin_clipboard_sent">Clipboard Sent</string>
<string name="pref_plugin_mousepad">Remote input</string>
<string name="pref_plugin_mousepad_desc">Use your phone or tablet as a touchpad and keyboard</string>
<string name="pref_plugin_mousepad_desc_nontv">Use your phone or tablet as a touchpad and keyboard</string>
<string name="pref_plugin_mousepad_desc_tv">Use your phone or tablet as a TV remote</string>
<string name="pref_plugin_presenter">Presentation remote</string>
<string name="pref_plugin_presenter_desc">Use your device to change slides in a presentation</string>
<string name="pref_plugin_remotekeyboard">Receive remote keypresses</string>
@@ -226,6 +227,7 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="right_click">Send Right Click</string>
<string name="middle_click">Send Middle Click</string>
<string name="show_keyboard">Show Keyboard</string>
<string name="show_mouse_and_keyboard">Show Mouse and Keyboard</string>
<string name="device_not_paired">Device not paired</string>
<string name="pairing_duplicate_names">Caution: There are multiple devices with the same name.</string>
<string name="request_pairing">Request pairing</string>

View File

@@ -1,146 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Ahmed I. Khalil <ahmedibrahimkhali@gmail.com>
* SPDX-FileCopyrightText: 2020 Sylvia van Os <sylvia@hackerchick.me>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Plugins.BigscreenPlugin;
import static org.kde.kdeconnect.Plugins.MousePadPlugin.KeyListenerView.SpecialKeysMap;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.KeyEvent;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import org.kde.kdeconnect.DeviceType;
import org.kde.kdeconnect.NetworkPacket;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.PluginFactory;
import org.kde.kdeconnect_tp.R;
@PluginFactory.LoadablePlugin
public class BigscreenPlugin extends Plugin {
private final static String PACKET_TYPE_MOUSEPAD_REQUEST = "kdeconnect.mousepad.request";
private final static String PACKET_TYPE_BIGSCREEN_STT = "kdeconnect.bigscreen.stt";
@Override
public boolean isCompatible() {
return getDevice().getDeviceType().equals(DeviceType.TV) && super.isCompatible();
}
@Override
protected int getOptionalPermissionExplanation() {
return R.string.bigscreen_optional_permission_explanation;
}
@Override
public @NonNull String getDisplayName() {
return context.getString(R.string.pref_plugin_bigscreen);
}
@Override
public @NonNull String getDescription() {
return context.getString(R.string.pref_plugin_bigscreen_desc);
}
@Override
public @DrawableRes int getIcon() {
return R.drawable.ic_presenter_24dp;
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
public boolean hasSettings() {
return false;
}
@Override
public boolean displayAsButton(Context context) {
return true;
}
@Override
public void startMainActivity(Activity parentActivity) {
Intent intent = new Intent(parentActivity, BigscreenActivity.class);
intent.putExtra("deviceId", getDevice().getDeviceId());
parentActivity.startActivity(intent);
}
@Override
public @NonNull String[] getSupportedPacketTypes() { return new String[]{PACKET_TYPE_BIGSCREEN_STT}; }
@Override
public @NonNull String[] getOutgoingPacketTypes() {
return new String[]{PACKET_TYPE_MOUSEPAD_REQUEST, PACKET_TYPE_BIGSCREEN_STT};
}
@Override
public @NonNull String getActionName() {
return context.getString(R.string.pref_plugin_bigscreen);
}
public @NonNull String[] getOptionalPermissions() {
return new String[]{Manifest.permission.RECORD_AUDIO};
}
public Boolean hasMicPermission() {
return isPermissionGranted(Manifest.permission.RECORD_AUDIO);
}
public void sendLeft() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_LEFT));
getDevice().sendPacket(np);
}
public void sendRight() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_RIGHT));
getDevice().sendPacket(np);
}
public void sendUp() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_UP));
getDevice().sendPacket(np);
}
public void sendDown() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_DOWN));
getDevice().sendPacket(np);
}
public void sendSelect() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_ENTER));
getDevice().sendPacket(np);
}
public void sendHome() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("alt", true);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_F4));
getDevice().sendPacket(np);
}
public void sendSTT(String content) {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_BIGSCREEN_STT);
np.set("type", "stt");
np.set("content", content);
getDevice().sendPacket(np);
}
}

View File

@@ -3,9 +3,9 @@
* SPDX-FileCopyrightText: 2020 Sylvia van Os <sylvia@hackerchick.me>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
*/
package org.kde.kdeconnect.Plugins.BigscreenPlugin;
package org.kde.kdeconnect.Plugins.MousePadPlugin;
import android.Manifest;
import android.app.Activity;
@@ -13,6 +13,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
@@ -33,9 +36,9 @@ import kotlin.LazyKt;
public class BigscreenActivity extends BaseActivity<ActivityBigscreenBinding> {
private static final int REQUEST_SPEECH = 100;
private final Lazy<ActivityBigscreenBinding> lazyBinding = LazyKt.lazy(() -> ActivityBigscreenBinding.inflate(getLayoutInflater()));
@NonNull
@Override
protected ActivityBigscreenBinding getBinding() {
@@ -57,7 +60,7 @@ public class BigscreenActivity extends BaseActivity<ActivityBigscreenBinding> {
getBinding().micButton.setVisibility(View.INVISIBLE);
}
BigscreenPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, BigscreenPlugin.class);
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
if (plugin == null) {
finish();
return;
@@ -90,6 +93,27 @@ public class BigscreenActivity extends BaseActivity<ActivityBigscreenBinding> {
startActivityForResult(intent, REQUEST_SPEECH);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_bigscreen, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_use_mouse_and_keyboard) {
Intent intent = new Intent(this, MousePadActivity.class);
intent.putExtra("deviceId", getIntent().getStringExtra("deviceId"));
startActivity(intent);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@@ -99,7 +123,7 @@ public class BigscreenActivity extends BaseActivity<ActivityBigscreenBinding> {
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if (result.get(0) != null) {
final String deviceId = getIntent().getStringExtra("deviceId");
BigscreenPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, BigscreenPlugin.class);
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
if (plugin == null) {
finish();
return;

View File

@@ -6,13 +6,18 @@
package org.kde.kdeconnect.Plugins.MousePadPlugin;
import static org.kde.kdeconnect.Plugins.MousePadPlugin.KeyListenerView.SpecialKeysMap;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.KeyEvent;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import org.kde.kdeconnect.DeviceType;
import org.kde.kdeconnect.NetworkPacket;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.PluginFactory;
@@ -25,6 +30,7 @@ public class MousePadPlugin extends Plugin {
//public final static String PACKET_TYPE_MOUSEPAD = "kdeconnect.mousepad";
public final static String PACKET_TYPE_MOUSEPAD_REQUEST = "kdeconnect.mousepad.request";
private final static String PACKET_TYPE_MOUSEPAD_KEYBOARDSTATE = "kdeconnect.mousepad.keyboardstate";
private final static String PACKET_TYPE_BIGSCREEN_STT = "kdeconnect.bigscreen.stt";
private boolean keyboardEnabled = true;
@@ -43,7 +49,7 @@ public class MousePadPlugin extends Plugin {
@Override
public @NonNull String getDescription() {
return context.getString(R.string.pref_plugin_mousepad_desc);
return context.getString(R.string.pref_plugin_mousepad_desc_nontv);
}
@Override
@@ -68,9 +74,15 @@ public class MousePadPlugin extends Plugin {
@Override
public void startMainActivity(Activity parentActivity) {
Intent intent = new Intent(parentActivity, MousePadActivity.class);
intent.putExtra("deviceId", getDevice().getDeviceId());
parentActivity.startActivity(intent);
if (getDevice().getDeviceType() == DeviceType.TV) {
Intent intent = new Intent(parentActivity, BigscreenActivity.class);
intent.putExtra("deviceId", getDevice().getDeviceId());
parentActivity.startActivity(intent);
} else {
Intent intent = new Intent(parentActivity, MousePadActivity.class);
intent.putExtra("deviceId", getDevice().getDeviceId());
parentActivity.startActivity(intent);
}
}
@Override
@@ -95,6 +107,10 @@ public class MousePadPlugin extends Plugin {
getDevice().sendPacket(np);
}
public Boolean hasMicPermission() {
return isPermissionGranted(Manifest.permission.RECORD_AUDIO);
}
public void sendLeftClick() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("singleclick", true);
@@ -139,6 +155,50 @@ public class MousePadPlugin extends Plugin {
getDevice().sendPacket(np);
}
public void sendLeft() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_LEFT));
getDevice().sendPacket(np);
}
public void sendRight() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_RIGHT));
getDevice().sendPacket(np);
}
public void sendUp() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_UP));
getDevice().sendPacket(np);
}
public void sendDown() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_DPAD_DOWN));
getDevice().sendPacket(np);
}
public void sendSelect() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_ENTER));
getDevice().sendPacket(np);
}
public void sendHome() {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MOUSEPAD_REQUEST);
np.set("alt", true);
np.set("specialKey", SpecialKeysMap.get(KeyEvent.KEYCODE_F4));
getDevice().sendPacket(np);
}
public void sendSTT(String content) {
NetworkPacket np = new NetworkPacket(PACKET_TYPE_BIGSCREEN_STT);
np.set("type", "stt");
np.set("content", content);
getDevice().sendPacket(np);
}
public void sendKeyboardPacket(NetworkPacket np) {
getDevice().sendPacket(np);
}