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