diff --git a/AndroidManifest.xml b/AndroidManifest.xml
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -257,7 +257,8 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.kde.kdeconnect.UserInterface.DeviceSettingsActivity" />
+
\ No newline at end of file
diff --git a/res/drawable/ic_camera.xml b/res/drawable/ic_camera.xml
new file mode 100644
--- /dev/null
+++ b/res/drawable/ic_camera.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -326,6 +326,8 @@
Block contents of notifications
Block images in notifications
Notifications from other devices
+ Take picture
+ Take a picture and send it to another device
findmyphone_ringtone
diff --git a/res/xml/fileprovider_paths.xml b/res/xml/fileprovider_paths.xml
--- a/res/xml/fileprovider_paths.xml
+++ b/res/xml/fileprovider_paths.xml
@@ -3,4 +3,5 @@
+
diff --git a/src/org/kde/kdeconnect/Helpers/FilesHelper.java b/src/org/kde/kdeconnect/Helpers/FilesHelper.java
--- a/src/org/kde/kdeconnect/Helpers/FilesHelper.java
+++ b/src/org/kde/kdeconnect/Helpers/FilesHelper.java
@@ -20,10 +20,18 @@
package org.kde.kdeconnect.Helpers;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.MediaStore;
import android.util.Log;
import android.webkit.MimeTypeMap;
+import org.kde.kdeconnect.NetworkPacket;
+
import java.io.File;
+import java.io.InputStream;
public class FilesHelper {
@@ -100,4 +108,82 @@
public static void LogOpenFileCount() {
Log.e("KDE/FileCount", "" + GetOpenFileCount());
}
+
+
+ //Create the network package from the URI
+ public static NetworkPacket uriToNetworkPacket(final Context context, final Uri uri, String type) {
+
+ try {
+
+ ContentResolver cr = context.getContentResolver();
+ InputStream inputStream = cr.openInputStream(uri);
+
+ NetworkPacket np = new NetworkPacket(type);
+ long size = -1;
+
+ if (uri.getScheme().equals("file")) {
+ // file:// is a non media uri, so we cannot query the ContentProvider
+
+ np.set("filename", uri.getLastPathSegment());
+
+ try {
+ size = new File(uri.getPath()).length();
+ } catch (Exception e) {
+ Log.e("SendFileActivity", "Could not obtain file size");
+ e.printStackTrace();
+ }
+
+ } else {
+ // Probably a content:// uri, so we query the Media content provider
+
+ Cursor cursor = null;
+ try {
+ String[] proj = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DISPLAY_NAME};
+ cursor = cr.query(uri, proj, null, null, null);
+ int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+ cursor.moveToFirst();
+ String path = cursor.getString(column_index);
+ np.set("filename", Uri.parse(path).getLastPathSegment());
+ size = new File(path).length();
+ } catch (Exception unused) {
+
+ Log.w("SendFileActivity", "Could not resolve media to a file, trying to get info as media");
+
+ try {
+ int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
+ cursor.moveToFirst();
+ String name = cursor.getString(column_index);
+ np.set("filename", name);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e("SendFileActivity", "Could not obtain file name");
+ }
+
+ try {
+ int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE);
+ cursor.moveToFirst();
+ //For some reason this size can differ from the actual file size!
+ size = cursor.getInt(column_index);
+ } catch (Exception e) {
+ Log.e("SendFileActivity", "Could not obtain file size");
+ e.printStackTrace();
+ }
+ } finally {
+ try {
+ cursor.close();
+ } catch (Exception ignored) {
+ }
+ }
+
+ }
+
+ np.setPayload(new NetworkPacket.Payload(inputStream, size));
+
+ return np;
+ } catch (Exception e) {
+ Log.e("SendFileActivity", "Exception creating network packet", e);
+ e.printStackTrace();
+ return null;
+ }
+ }
}
diff --git a/src/org/kde/kdeconnect/Plugins/PhotoPlugin/PhotoActivity.java b/src/org/kde/kdeconnect/Plugins/PhotoPlugin/PhotoActivity.java
new file mode 100644
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/PhotoPlugin/PhotoActivity.java
@@ -0,0 +1,72 @@
+package org.kde.kdeconnect.Plugins.PhotoPlugin;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+
+import org.kde.kdeconnect.BackgroundService;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.FileProvider;
+
+public class PhotoActivity extends AppCompatActivity {
+
+ private Uri photoURI;
+ private PhotoPlugin plugin;
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ BackgroundService.runWithPlugin(this, getIntent().getStringExtra("deviceId"), PhotoPlugin.class, plugin -> {
+ this.plugin = plugin;
+ });
+
+ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
+ File photoFile = null;
+ try {
+ photoFile = createImageFile();
+ } catch (IOException ignored) {
+ }
+ // Continue only if the File was successfully created
+ if (photoFile != null) {
+ photoURI = FileProvider.getUriForFile(this,
+ "org.kde.kdeconnect_tp.fileprovider",
+ photoFile);
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
+ startActivityForResult(takePictureIntent, 1);
+ }
+ }
+
+ }
+
+ private File createImageFile() throws IOException {
+ // Create an image file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String imageFileName = "JPEG_" + timeStamp + "_";
+ File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
+ return File.createTempFile(
+ imageFileName, /* prefix */
+ ".jpg", /* suffix */
+ storageDir /* directory */
+ );
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (resultCode == -1) {
+ plugin.sendPhoto(photoURI);
+ }
+ finish();
+ }
+}
diff --git a/src/org/kde/kdeconnect/Plugins/PhotoPlugin/PhotoPlugin.java b/src/org/kde/kdeconnect/Plugins/PhotoPlugin/PhotoPlugin.java
new file mode 100644
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/PhotoPlugin/PhotoPlugin.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 Nicolas Fella
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.kde.kdeconnect.Plugins.PhotoPlugin;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+import org.kde.kdeconnect.Helpers.FilesHelper;
+import org.kde.kdeconnect.NetworkPacket;
+import org.kde.kdeconnect.Plugins.Plugin;
+import org.kde.kdeconnect_tp.R;
+
+import androidx.core.content.ContextCompat;
+
+
+public class PhotoPlugin extends Plugin {
+
+ private final static String PACKET_TYPE_PHOTO = "kdeconnect.photo";
+ private final static String PACKET_TYPE_PHOTO_REQUEST = "kdeconnect.photo.request";
+
+ @Override
+ public String getDisplayName() {
+ return context.getResources().getString(R.string.take_picture);
+ }
+
+ @Override
+ public String getDescription() {
+ return context.getResources().getString(R.string.plugin_photo_desc);
+ }
+
+ @Override
+ public boolean onPacketReceived(NetworkPacket np) {
+ Intent intent = new Intent(context, PhotoActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra("deviceId", device.getDeviceId());
+ context.startActivity(intent);
+ return true;
+ }
+
+ void sendPhoto(Uri uri) {
+ NetworkPacket np = FilesHelper.uriToNetworkPacket(context, uri, PACKET_TYPE_PHOTO);
+ if (np != null) {
+ device.sendPacket(np);
+ }
+ }
+
+ @Override
+ public boolean hasMainActivity() {
+ return false;
+ }
+
+ @Override
+ public boolean displayInContextMenu() {
+ return false;
+ }
+
+ @Override
+ public String[] getSupportedPacketTypes() {
+ return new String[]{PACKET_TYPE_PHOTO_REQUEST};
+ }
+
+ @Override
+ public String[] getOutgoingPacketTypes() {
+ return new String[]{PACKET_TYPE_PHOTO};
+ }
+
+ @Override
+ public Drawable getIcon() {
+ return ContextCompat.getDrawable(context, R.drawable.ic_camera);
+ }
+}
diff --git a/src/org/kde/kdeconnect/Plugins/PingPlugin/PingPlugin.java b/src/org/kde/kdeconnect/Plugins/PingPlugin/PingPlugin.java
--- a/src/org/kde/kdeconnect/Plugins/PingPlugin/PingPlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/PingPlugin/PingPlugin.java
@@ -15,8 +15,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
-*/
+ * along with this program. If not, see .
+ */
package org.kde.kdeconnect.Plugins.PingPlugin;
diff --git a/src/org/kde/kdeconnect/Plugins/PluginFactory.java b/src/org/kde/kdeconnect/Plugins/PluginFactory.java
--- a/src/org/kde/kdeconnect/Plugins/PluginFactory.java
+++ b/src/org/kde/kdeconnect/Plugins/PluginFactory.java
@@ -27,7 +27,6 @@
import org.atteo.classindex.ClassIndex;
import org.atteo.classindex.IndexAnnotated;
import org.kde.kdeconnect.Device;
-
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java
--- a/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java
@@ -40,6 +40,7 @@
import android.util.Log;
import android.widget.Toast;
+import org.kde.kdeconnect.Helpers.FilesHelper;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.NetworkPacket;
import org.kde.kdeconnect.Plugins.Plugin;
@@ -240,7 +241,7 @@
//Read all the data early, as we only have permissions to do it while the activity is alive
final ArrayList toSend = new ArrayList<>();
for (Uri uri : uriList) {
- NetworkPacket np = uriToNetworkPacket(context, uri);
+ NetworkPacket np = FilesHelper.uriToNetworkPacket(context, uri, PACKET_TYPE_SHARE_REQUEST);
if (np != null) {
toSend.add(np);
@@ -268,83 +269,6 @@
}
- //Create the network package from the URI
- private static NetworkPacket uriToNetworkPacket(final Context context, final Uri uri) {
-
- try {
-
- ContentResolver cr = context.getContentResolver();
- InputStream inputStream = cr.openInputStream(uri);
-
- NetworkPacket np = new NetworkPacket(PACKET_TYPE_SHARE_REQUEST);
- long size = -1;
-
- if (uri.getScheme().equals("file")) {
- // file:// is a non media uri, so we cannot query the ContentProvider
-
- np.set("filename", uri.getLastPathSegment());
-
- try {
- size = new File(uri.getPath()).length();
- } catch (Exception e) {
- Log.e("SendFileActivity", "Could not obtain file size");
- e.printStackTrace();
- }
-
- } else {
- // Probably a content:// uri, so we query the Media content provider
-
- Cursor cursor = null;
- try {
- String[] proj = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DISPLAY_NAME};
- cursor = cr.query(uri, proj, null, null, null);
- int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
- cursor.moveToFirst();
- String path = cursor.getString(column_index);
- np.set("filename", Uri.parse(path).getLastPathSegment());
- size = new File(path).length();
- } catch (Exception unused) {
-
- Log.w("SendFileActivity", "Could not resolve media to a file, trying to get info as media");
-
- try {
- int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
- cursor.moveToFirst();
- String name = cursor.getString(column_index);
- np.set("filename", name);
- } catch (Exception e) {
- e.printStackTrace();
- Log.e("SendFileActivity", "Could not obtain file name");
- }
-
- try {
- int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE);
- cursor.moveToFirst();
- //For some reason this size can differ from the actual file size!
- size = cursor.getInt(column_index);
- } catch (Exception e) {
- Log.e("SendFileActivity", "Could not obtain file size");
- e.printStackTrace();
- }
- } finally {
- try {
- cursor.close();
- } catch (Exception ignored) {
- }
- }
-
- }
-
- np.setPayload(new NetworkPacket.Payload(inputStream, size));
-
- return np;
- } catch (Exception e) {
- Log.e("SendFileActivity", "Exception sending files");
- e.printStackTrace();
- return null;
- }
- }
-
public void share(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {