diff --git a/app/src/androidTest/java/com/example/dilnacam/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/dilnacam/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6dcc1c87edd8ff34b794f3999922f71130f4aa4b
--- /dev/null
+++ b/app/src/androidTest/java/com/example/dilnacam/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.webcamupload;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.webcamupload", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dilnacam/CameraActivity.java b/app/src/main/java/com/example/dilnacam/CameraActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd7eba343343973cbc2eb322e40bd9fa6ebb4a68
--- /dev/null
+++ b/app/src/main/java/com/example/dilnacam/CameraActivity.java
@@ -0,0 +1,236 @@
+package com.example.webcamupload;
+
+import static androidx.core.content.PackageManagerCompat.LOG_TAG;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.icu.text.SimpleDateFormat;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import android.widget.Toast;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.camera.core.Camera;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ImageCapture;
+import androidx.camera.core.ImageCaptureException;
+import androidx.camera.core.Preview;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.camera.view.PreviewView;
+import androidx.core.content.ContextCompat;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation;
+import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation;
+import com.owncloud.android.lib.resources.files.model.RemoteFile;
+
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+
+public class CameraActivity extends AppCompatActivity implements OnRemoteOperationListener, OnDatatransferProgressListener{
+ private PreviewView previewView;
+ private TextView textView1;
+ private TextView textView2;
+ private TextView textView3;
+ private FilesArrayAdapter mFilesAdapter;
+ private OwnCloudClient mClient;
+ private Handler taskHandler;
+ private ImageCapture imageCapture;
+ private String lastTimeStamp;
+ private File imageFile;
+ private final long CAPTURE_INTERVAL = 60000;
+ private final Executor executor = Executors.newSingleThreadExecutor();
+
+ private final Runnable repetitiveTaskRunnable = new Runnable() {
+ public void run() {
+ //DO YOUR THINGS
+ SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.getDefault());
+ lastTimeStamp = mDateFormat.format(new Date());
+ textView1.setText(lastTimeStamp);
+ imageFile = new File(getBatchDirectoryName(), lastTimeStamp + ".jpg");
+
+ ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(imageFile).build();
+ imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback () {
+ @Override
+ public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
+ taskHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(getApplicationContext(), "Image Saved successfully", Toast.LENGTH_SHORT).show();
+ String remotePath = getString(R.string.remote_folder_path) + "/" + imageFile.getName();
+ startUpload(imageFile, remotePath, getString(R.string.image_mime_type));
+ }
+ });
+ }
+ @Override
+ public void onError(@NonNull ImageCaptureException error) {
+ error.printStackTrace();
+ }
+ });
+
+
+
+
+ taskHandler.postDelayed(repetitiveTaskRunnable, CAPTURE_INTERVAL);
+ }
+ };
+ /* https://stackoverflow.com/questions/6242268/repeat-a-task-with-a-time-delay/6242292#6242292
+ https://stackoverflow.com/questions/1921514/how-to-run-a-runnable-thread-in-android-at-defined-intervals*/
+
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_camera);
+ previewView = findViewById(R.id.viewFinder);
+ textView1 = findViewById(R.id.textBox1);
+ textView2 = findViewById(R.id.textBox2);
+ textView3 = findViewById(R.id.textBox3);
+
+ mFilesAdapter = new FilesArrayAdapter(this, R.layout.file_in_list);
+ ((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter);
+
+ taskHandler = new Handler();
+ createNextcloudClient();
+ startCamera();
+ taskHandler.postDelayed(repetitiveTaskRunnable, CAPTURE_INTERVAL);
+ startRefresh();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ taskHandler.removeCallbacks(repetitiveTaskRunnable);
+ }
+
+ private void createNextcloudClient(){
+ Intent i = getIntent();
+ String usr = i.getStringExtra("usr");
+ String psw = i.getStringExtra("psw");
+ Uri serverUri = Uri.parse(i.getStringExtra("uri"));
+ mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true);
+ mClient.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials(usr, psw));
+ mClient.setUserId(usr);
+ }
+
+ private File getLastImageFile() {
+ String localPath = Environment.getExternalStorageDirectory().toString() + "/images/" + lastTimeStamp + ".jpg";
+ return new File(localPath);
+ }
+
+ private void startCamera() {
+ final ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this);
+ cameraProviderFuture.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
+ bindPreview(cameraProvider);
+ } catch (ExecutionException | InterruptedException e) {
+ // No errors need to be handled for this Future.
+ // This should never be reached.
+ }
+ }
+ }, ContextCompat.getMainExecutor(this));
+ }
+
+ void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
+ Preview preview = new Preview.Builder().build();
+ CameraSelector cameraSelector = new CameraSelector.Builder()
+ .requireLensFacing(CameraSelector.LENS_FACING_BACK)
+ .build();
+ ImageCapture.Builder builder = new ImageCapture.Builder();
+ imageCapture = builder
+ .setTargetRotation(Surface.ROTATION_90)
+ .setJpegQuality(30)
+ .setTargetResolution(new Size(1280,720))
+ .build();
+ preview.setSurfaceProvider(previewView.getSurfaceProvider());
+ Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview, imageCapture);
+ }
+
+ public String getBatchDirectoryName() {
+ String app_folder_path = Environment.getExternalStorageDirectory().toString() + "/images";
+ File dir = new File(app_folder_path);
+ if (!dir.exists() && !dir.mkdirs()) {
+
+ }
+ return app_folder_path;
+ }
+
+ private void startRefresh() {
+ ReadFolderRemoteOperation refreshOperation = new ReadFolderRemoteOperation("");
+ refreshOperation.execute(mClient, this, taskHandler);
+ }
+
+ private void startUpload(File fileToUpload, String remotePath, String mimeType) {
+ long timeStampLong = fileToUpload.lastModified() / 1000;
+ String lastModifiedTimestamp = Long.toString(timeStampLong);
+ UploadFileRemoteOperation uploadOperation = new UploadFileRemoteOperation(fileToUpload.getAbsolutePath(), remotePath, mimeType, lastModifiedTimestamp);
+ uploadOperation.addDataTransferProgressListener(this);
+ uploadOperation.execute(mClient, this, taskHandler);
+ }
+
+ @SuppressLint("RestrictedApi")
+ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+ if (!result.isSuccess()) {
+ if (operation instanceof ReadFolderRemoteOperation){
+ Toast.makeText(this, getString(R.string.refresh_failed), Toast.LENGTH_SHORT).show();
+ finish();
+ } else {
+ Toast.makeText(this, R.string.todo_operation_finished_in_fail, Toast.LENGTH_SHORT).show();
+ Log.e(LOG_TAG, result.getLogMessage(), result.getException());
+ }
+ } else if (operation instanceof ReadFolderRemoteOperation) {
+ Toast.makeText(this, getString(R.string.refresh_successful), Toast.LENGTH_SHORT).show();
+ textView3.setText("Upload dir: " + getString(R.string.remote_folder_path));
+
+ } else if (operation instanceof UploadFileRemoteOperation) {
+ textView2.setText(lastTimeStamp + " Uploaded");
+ imageFile.delete();
+
+ }
+ }
+
+
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {
+ taskHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ textView2.setText("Uploading: " + Long.toString(totalTransferredSoFar/1000)+" kB");
+ // do your UI updates about progress here
+ }
+ });
+ }
+}
+
+
diff --git a/app/src/main/java/com/example/dilnacam/FilesArrayAdapter.java b/app/src/main/java/com/example/dilnacam/FilesArrayAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..949aaa8ab1966a9388f5f2fd2e9bf7d48b7c7aae
--- /dev/null
+++ b/app/src/main/java/com/example/dilnacam/FilesArrayAdapter.java
@@ -0,0 +1,46 @@
+/* ownCloud Android Library is available under MIT license
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+package com.example.webcamupload;
+
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.owncloud.android.lib.resources.files.model.RemoteFile;
+
+public class FilesArrayAdapter extends ArrayAdapter {
+
+ public FilesArrayAdapter(Context context, int resource) {
+ super(context, resource);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView textView = (TextView)super.getView(position, convertView, parent);
+ textView.setText(getItem(position).getRemotePath());
+ return textView;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dilnacam/MainActivity.java b/app/src/main/java/com/example/dilnacam/MainActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..54254bcd06450723a40dc2fe6bafd23ddd64a5a6
--- /dev/null
+++ b/app/src/main/java/com/example/dilnacam/MainActivity.java
@@ -0,0 +1,107 @@
+package com.example.webcamupload;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+
+
+
+public class MainActivity extends AppCompatActivity {
+ private static final String[] CAMERA_PERMISSION = new String[]{Manifest.permission.CAMERA};
+ private static final int CAMERA_REQUEST_CODE = 10;
+ private static final String[] STORAGE_PERMISSION = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE};
+ int STORAGE_REQUEST_CODE = 1;
+ private String psw;
+ private String usr;
+ private String uri;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ Button enableCamera = findViewById(R.id.enableCamera);
+ enableCamera.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ EditText editTextUsr = (EditText) findViewById(R.id.editTextUsr);
+ EditText editTextPsw = (EditText) findViewById(R.id.editTextPsw);
+ usr = editTextUsr.getText().toString();
+ psw = editTextPsw.getText().toString();
+ uri = getString(R.string.server_base_url);
+
+ if (!hasCameraPermission()) {
+ requestCameraPermission();
+ } else if (!hasStoragePermission()) {
+ requestStoragePermission();
+ //} else if (!validateCredentials(usr, psw)) {
+ // showInvalidCredentialsToast();
+ } else {
+ enableCamera();
+ }
+ }
+ });
+
+ }
+
+ private void enableCamera() {
+ Intent i = new Intent(this, CameraActivity.class);
+ i.putExtra("usr", usr);
+ i.putExtra("psw", psw);
+ i.putExtra("uri", uri);
+ startActivity(i);
+ }
+ private boolean hasCameraPermission() {
+ return ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.CAMERA
+ ) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private boolean hasStoragePermission() {
+ return ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ ) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private void requestCameraPermission() {
+ ActivityCompat.requestPermissions(
+ this,
+ CAMERA_PERMISSION,
+ CAMERA_REQUEST_CODE
+ );
+ }
+
+ private void requestStoragePermission() {
+ ActivityCompat.requestPermissions(
+ this,
+ STORAGE_PERMISSION,
+ STORAGE_REQUEST_CODE
+ );
+ }
+
+ private void showInvalidCredentialsToast(){
+ Context context = getApplicationContext();
+ CharSequence text = "Empty credentials";
+ int duration = Toast.LENGTH_SHORT;
+ Toast toast = Toast.makeText(context, text, duration);
+ toast.show();
+ }
+ private boolean validateCredentials(String usr, String psw) {
+ return usr != null && !usr.trim().isEmpty() && psw != null && !psw.trim().isEmpty();
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/hat.png b/app/src/main/res/drawable/hat.png
new file mode 100644
index 0000000000000000000000000000000000000000..e86a33c03891ae80c30e2f8c9404c7d7175e8d61
Binary files /dev/null and b/app/src/main/res/drawable/hat.png differ
diff --git a/app/src/test/java/com/example/dilnacam/ExampleUnitTest.java b/app/src/test/java/com/example/dilnacam/ExampleUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f84a0faf98a74f1e0cbc7f3becad6de0fada91f0
--- /dev/null
+++ b/app/src/test/java/com/example/dilnacam/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.webcamupload;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file