mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 09:58:08 +00:00
Merge branch 'albertvaka/presenter-pointer'
# Conflicts: # res/values/strings.xml # src/org/kde/kdeconnect/Plugins/PresenterPlugin/PresenterActivity.java
This commit is contained in:
commit
bdcefe4a2b
@ -1,31 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/mpris_control_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:padding="12dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Space
|
||||
<TextView
|
||||
style="@android:style/TextAppearance.Medium"
|
||||
android:id="@+id/textView"
|
||||
android:layout_weight="0"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/top_space"/>
|
||||
android:text="@string/presenter_lock_tip" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_below="@id/top_space"
|
||||
android:layout_above="@id/textView">
|
||||
android:layout_weight="1">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/previous_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="0.25"
|
||||
android:contentDescription="@string/mpris_rew"
|
||||
android:layout_weight="0.25"
|
||||
android:layout_marginRight="3dp"
|
||||
android:layout_marginEnd="3dp"
|
||||
android:src="@drawable/ic_previous_black"
|
||||
android:theme="@style/DisableableButton" />
|
||||
|
||||
@ -33,6 +39,8 @@
|
||||
android:id="@+id/next_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:layout_marginStart="3dp"
|
||||
android:layout_weight="0.25"
|
||||
android:contentDescription="@string/mpris_ff"
|
||||
android:src="@drawable/ic_next_black"
|
||||
@ -40,13 +48,16 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
style="@android:style/TextAppearance.Medium"
|
||||
android:padding="12dip"
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:text="@string/presenter_lock_tip" />
|
||||
|
||||
</RelativeLayout>
|
||||
<Button
|
||||
android:id="@+id/pointer_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.30"
|
||||
android:visibility="gone"
|
||||
android:text="@string/presenter_pointer"
|
||||
android:theme="@style/DisableableButton" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -367,4 +367,6 @@
|
||||
<string name="findmyphone_preference_key_ringtone" translatable="false">findmyphone_ringtone</string>
|
||||
<string name="no_app_for_opening">No suitable app found to open this file</string>
|
||||
<string name="remote_keyboard_service">KDE Connect Remote Keyboard</string>
|
||||
<string name="presenter_pointer">Pointer</string>
|
||||
|
||||
</resources>
|
||||
|
@ -49,6 +49,7 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -86,6 +87,11 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
private final SharedPreferences settings;
|
||||
|
||||
private final CopyOnWriteArrayList<PluginsChangedListener> pluginsChangedListeners = new CopyOnWriteArrayList<>();
|
||||
private Set<String> incomingCapabilities = new HashSet<>();
|
||||
|
||||
public boolean supportsPacketType(String type) {
|
||||
return incomingCapabilities.contains(type);
|
||||
}
|
||||
|
||||
public interface PluginsChangedListener {
|
||||
void onPluginsChanged(Device device);
|
||||
@ -489,12 +495,14 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
|
||||
Set<String> outgoingCapabilities = identityPacket.getStringSet("outgoingCapabilities", null);
|
||||
Set<String> incomingCapabilities = identityPacket.getStringSet("incomingCapabilities", null);
|
||||
|
||||
|
||||
if (incomingCapabilities != null && outgoingCapabilities != null) {
|
||||
supportedPlugins = new Vector<>(PluginFactory.pluginsForCapabilities(incomingCapabilities, outgoingCapabilities));
|
||||
} else {
|
||||
supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins());
|
||||
}
|
||||
|
||||
this.incomingCapabilities = incomingCapabilities;
|
||||
|
||||
reloadPluginsFromSettings();
|
||||
|
||||
|
@ -21,28 +21,87 @@
|
||||
package org.kde.kdeconnect.Plugins.PresenterPlugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorEventListener2;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.media.VolumeProviderCompat;
|
||||
|
||||
public class PresenterActivity extends AppCompatActivity {
|
||||
import static androidx.core.math.MathUtils.clamp;
|
||||
|
||||
public class PresenterActivity extends AppCompatActivity implements SensorEventListener {
|
||||
|
||||
private MediaSessionCompat mMediaSession;
|
||||
|
||||
private PresenterPlugin plugin;
|
||||
|
||||
private SensorManager sensorManager;
|
||||
private float xPos, yPos;
|
||||
private float xOffset, yOffset;
|
||||
|
||||
static final float SENSITIVITY = 0.05f; //TODO: Make configurable?
|
||||
|
||||
public void gyroscopeEvent(SensorEvent event) {
|
||||
xPos += -event.values[2];
|
||||
yPos += -event.values[0];
|
||||
|
||||
float percentX = clamp((xPos - xOffset) * SENSITIVITY, -1.f, 1.f);
|
||||
float percentY = clamp((yPos - yOffset) * SENSITIVITY, -1.f, 1.f);
|
||||
|
||||
plugin.sendPointer(percentX, percentY);
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
|
||||
gyroscopeEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
//Ignored
|
||||
}
|
||||
|
||||
void enablePointer() {
|
||||
if (sensorManager != null) {
|
||||
return; //Already enabled
|
||||
}
|
||||
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
|
||||
findViewById(R.id.pointer_button).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.pointer_button).setOnTouchListener((v, event) -> {
|
||||
if(event.getAction() == MotionEvent.ACTION_DOWN){
|
||||
yOffset = yPos;
|
||||
xOffset = xPos;
|
||||
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME);
|
||||
v.performClick(); // The linter complains if this is not called
|
||||
}
|
||||
else if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
sensorManager.unregisterListener(this);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -56,6 +115,9 @@ public class PresenterActivity extends AppCompatActivity {
|
||||
this.plugin = plugin;
|
||||
findViewById(R.id.next_button).setOnClickListener(v -> plugin.sendNext());
|
||||
findViewById(R.id.previous_button).setOnClickListener(v -> plugin.sendPrevious());
|
||||
if (plugin.isPointerSupported()) {
|
||||
enablePointer();
|
||||
}
|
||||
}));
|
||||
}
|
||||
@Override
|
||||
@ -86,13 +148,18 @@ public class PresenterActivity extends AppCompatActivity {
|
||||
mMediaSession.setActive(true);
|
||||
return;
|
||||
}
|
||||
createMediaSession(); //Mediasession will keep
|
||||
createMediaSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
if (sensorManager != null) {
|
||||
// Make sure we don't leave the listener on
|
||||
sensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
if (mMediaSession != null) {
|
||||
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
|
||||
boolean screenOn;
|
||||
|
@ -24,6 +24,8 @@ package org.kde.kdeconnect.Plugins.PresenterPlugin;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
@ -38,8 +40,13 @@ import static org.kde.kdeconnect.Plugins.MousePadPlugin.KeyListenerView.SpecialK
|
||||
@PluginFactory.LoadablePlugin
|
||||
public class PresenterPlugin extends Plugin {
|
||||
|
||||
private final static String PACKET_TYPE_PRESENTER = "kdeconnect.presenter";
|
||||
private final static String PACKET_TYPE_MOUSEPAD_REQUEST = "kdeconnect.mousepad.request";
|
||||
|
||||
public boolean isPointerSupported() {
|
||||
return device.supportsPacketType(PACKET_TYPE_PRESENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return context.getString(R.string.pref_plugin_presenter);
|
||||
@ -73,13 +80,11 @@ public class PresenterPlugin extends Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedPacketTypes() {
|
||||
return new String[0];
|
||||
}
|
||||
public String[] getSupportedPacketTypes() { return new String[0]; }
|
||||
|
||||
@Override
|
||||
public String[] getOutgoingPacketTypes() {
|
||||
return new String[]{PACKET_TYPE_MOUSEPAD_REQUEST};
|
||||
return new String[]{PACKET_TYPE_MOUSEPAD_REQUEST, PACKET_TYPE_PRESENTER};
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -111,4 +116,11 @@ public class PresenterPlugin extends Plugin {
|
||||
device.sendPacket(np);
|
||||
}
|
||||
|
||||
public void sendPointer(float percentX, float percentY) {
|
||||
NetworkPacket np = new NetworkPacket(PACKET_TYPE_PRESENTER);
|
||||
np.set("px", percentX);
|
||||
np.set("py", percentY);
|
||||
device.sendPacket(np);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user