diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index ac93b0d..0000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 731677a..8c0539e 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,12 @@ Current feature list * File upload * File download * pdf file reader using user provided pdf.js server +* file sharing links +* get object info +* get bucket info Planned feature list -* file sharing links * better interface for uploads and downloads This app is a work in progress, so it have some bugs that need to be fixed diff --git a/app/build.gradle b/app/build.gradle index b094678..0c24d0b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "asgardius.page.s3manager" minSdk 24 targetSdk 33 - versionCode 14 - versionName "0.1.12" + versionCode 15 + versionName "0.1.13" setProperty("archivesBaseName", "s3-manager-$versionName") testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 894774b..1a20301 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,6 +19,14 @@ android:supportsRtl="true" android:theme="@style/Theme.AsgardiusS3Manager" tools:targetApi="31"> + + + diff --git a/app/src/main/java/asgardius/page/s3manager/BucketSelect.java b/app/src/main/java/asgardius/page/s3manager/BucketSelect.java index 60e4e28..2bf5ce2 100644 --- a/app/src/main/java/asgardius/page/s3manager/BucketSelect.java +++ b/app/src/main/java/asgardius/page/s3manager/BucketSelect.java @@ -165,6 +165,8 @@ public class BucketSelect extends AppCompatActivity { //System.out.println(file); //Toast.makeText(BucketSelect.this, intent.getData().toString(), Toast.LENGTH_SHORT).show(); + } else if (menuItem.getTitle() == getResources().getString(R.string.object_info)) { + objectInfo(Name.get(position).toString()); } else if (menuItem.getTitle() == getResources().getString(R.string.file_del)) { //Toast.makeText(BucketSelect.this, getResources().getString(R.string.pending_feature), Toast.LENGTH_SHORT).show(); delete(prefix + Name.get(position).toString()); @@ -288,6 +290,19 @@ public class BucketSelect extends AppCompatActivity { startActivity(intent); } + private void objectInfo(String bucket) { + + Intent intent = new Intent(this, ObjectInfo.class); + //treelevel ++; + intent.putExtra("endpoint", endpoint); + intent.putExtra("username", username); + intent.putExtra("password", password); + intent.putExtra("bucket", bucket); + intent.putExtra("region", location); + startActivity(intent); + + } + private void newBucket() { Intent intent = new Intent(this, CreateBucket.class); intent.putExtra("endpoint", endpoint); diff --git a/app/src/main/java/asgardius/page/s3manager/ObjectInfo.java b/app/src/main/java/asgardius/page/s3manager/ObjectInfo.java new file mode 100644 index 0000000..ffbc132 --- /dev/null +++ b/app/src/main/java/asgardius/page/s3manager/ObjectInfo.java @@ -0,0 +1,147 @@ +package asgardius.page.s3manager; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Region; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.S3ClientOptions; +import com.amazonaws.services.s3.model.Bucket; +import com.amazonaws.services.s3.model.ListObjectsRequest; +import com.amazonaws.services.s3.model.ObjectListing; +import com.amazonaws.services.s3.model.S3ObjectSummary; + +import java.util.ArrayList; +import java.util.List; + +public class ObjectInfo extends AppCompatActivity { + String username, password, endpoint, bucket, object, location; + Region region; + S3ClientOptions s3ClientOptions; + AWSCredentials myCredentials; + AmazonS3 s3client; + ProgressBar simpleProgressBar; + TextView filesize, filesizeinfo, objectcount; + boolean isobject, isfolder; + long totalSize = 0; + int totalItems = 0; + ListObjectsRequest orequest; + long KiB, MiB, GiB; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_object_info); + KiB = 1024; + MiB = 1024 * KiB; + GiB = 1024 * MiB; + simpleProgressBar = (ProgressBar) findViewById(R.id.simpleProgressBar); + filesize = (TextView) findViewById(R.id.size); + filesizeinfo = (TextView) findViewById(R.id.size_info); + objectcount = (TextView) findViewById(R.id.object_count); + endpoint = getIntent().getStringExtra("endpoint"); + username = getIntent().getStringExtra("username"); + password = getIntent().getStringExtra("password"); + bucket = getIntent().getStringExtra("bucket"); + location = getIntent().getStringExtra("region"); + object = getIntent().getStringExtra("object"); + if (object == null) { + getSupportActionBar().setTitle(bucket+"/"); + } else { + getSupportActionBar().setTitle(bucket+"/"+object); + } + region = Region.getRegion(location); + s3ClientOptions = S3ClientOptions.builder().build(); + myCredentials = new BasicAWSCredentials(username, password); + try { + s3client = new AmazonS3Client(myCredentials, region); + } catch (Exception e) { + Toast.makeText(getApplicationContext(),getResources().getString(R.string.media_list_fail), Toast.LENGTH_SHORT).show(); + } + s3client.setEndpoint(endpoint); + if (!endpoint.contains(getResources().getString(R.string.aws_endpoint))) { + s3ClientOptions.setPathStyleAccess(true); + } + s3client.setS3ClientOptions(s3ClientOptions); + Thread getInfo = new Thread(new Runnable() { + + @Override + public void run() { + try { + //Your code goes here + if (object == null) { + isobject = false; + orequest = new ListObjectsRequest().withBucketName(bucket).withMaxKeys(8000); + } else { + isobject = true; + if (object.endsWith("/")) { + isfolder = true; + } else { + isfolder = false; + } + orequest = new ListObjectsRequest().withBucketName(bucket).withPrefix(object).withMaxKeys(8000); + } + ObjectListing result = s3client.listObjects(orequest); + do { + for (S3ObjectSummary objectSummary : result.getObjectSummaries()) { + totalSize += objectSummary.getSize(); + totalItems++; + } + result = s3client.listNextBatchOfObjects (result); + } while (result.isTruncated()); + + + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (isobject) { + if (isfolder) { + filesizeinfo.setText(getResources().getString(R.string.folder_size)); + objectcount.setText(totalItems+" "+getResources().getString(R.string.file_count)); + } else { + filesizeinfo.setText(getResources().getString(R.string.file_size)); + } + } else { + filesizeinfo.setText(getResources().getString(R.string.bucket_size)); + objectcount.setText(totalItems+" "+getResources().getString(R.string.file_count)); + } + if (totalSize >= GiB) { + filesize.setText(Long.toString(totalSize/GiB)+" GiB"); + } else if (totalSize >= MiB) { + filesize.setText(Long.toString(totalSize/MiB)+" MiB"); + } else if (totalSize >= KiB) { + filesize.setText(Long.toString(totalSize/KiB)+" KiB"); + } else { + filesize.setText(Long.toString(totalSize)+" Bytes"); + } + simpleProgressBar.setVisibility(View.INVISIBLE); + } + }); + + } catch (Exception e) { + e.printStackTrace(); + runOnUiThread(new Runnable() { + + @Override + public void run() { + Toast.makeText(getApplicationContext(),getResources().getString(R.string.media_list_fail), Toast.LENGTH_SHORT).show(); + } + }); + //Toast.makeText(getApplicationContext(),getResources().getString(R.string.media_list_fail), Toast.LENGTH_SHORT).show(); + finish(); + } + } + }); + getInfo.start(); + } +} \ No newline at end of file diff --git a/app/src/main/java/asgardius/page/s3manager/ObjectSelect.java b/app/src/main/java/asgardius/page/s3manager/ObjectSelect.java index 1a56cc6..a65f095 100644 --- a/app/src/main/java/asgardius/page/s3manager/ObjectSelect.java +++ b/app/src/main/java/asgardius/page/s3manager/ObjectSelect.java @@ -306,6 +306,8 @@ public class ObjectSelect extends AppCompatActivity { if (menuItem.getTitle() == getResources().getString(R.string.upload_file_here)) { //Toast.makeText(ObjectSelect.this, getResources().getString(R.string.pending_feature), Toast.LENGTH_SHORT).show(); upload(); + } else if (menuItem.getTitle() == getResources().getString(R.string.object_info)) { + objectInfo(prefix + Name.get(position).toString()); } else if (menuItem.getTitle() == getResources().getString(R.string.file_del)) { if (Name.size() == 1 && treelevel >= 1) { Toast.makeText(ObjectSelect.this, getResources().getString(R.string.only_item_onlist), Toast.LENGTH_SHORT).show(); @@ -335,8 +337,10 @@ public class ObjectSelect extends AppCompatActivity { } else if (menuItem.getTitle() == getResources().getString(R.string.upload_file_here)) { //Toast.makeText(ObjectSelect.this, getResources().getString(R.string.pending_feature), Toast.LENGTH_SHORT).show(); upload(); - } else if (menuItem.getTitle() == getResources().getString(R.string.file_share)) { + } else if (menuItem.getTitle() == getResources().getString(R.string.create_link)) { share(prefix + Name.get(position).toString()); + } else if (menuItem.getTitle() == getResources().getString(R.string.object_info)) { + objectInfo(prefix + Name.get(position).toString()); } else if (menuItem.getTitle() == getResources().getString(R.string.file_del)) { if (menuItem.getTitle() == getResources().getString(R.string.file_del)) { if (Name.size() == 1 && treelevel >= 1) { @@ -418,6 +422,20 @@ public class ObjectSelect extends AppCompatActivity { } + private void objectInfo(String object) { + + Intent intent = new Intent(this, ObjectInfo.class); + //treelevel ++; + intent.putExtra("endpoint", endpoint); + intent.putExtra("username", username); + intent.putExtra("password", password); + intent.putExtra("bucket", bucket); + intent.putExtra("object", object); + intent.putExtra("region", location); + startActivity(intent); + + } + private void delete(String object, boolean folder) { AlertDialog.Builder builder = new AlertDialog.Builder(ObjectSelect.this); builder.setCancelable(true); diff --git a/app/src/main/java/asgardius/page/s3manager/Share.java b/app/src/main/java/asgardius/page/s3manager/Share.java index 9f46d39..d46e657 100644 --- a/app/src/main/java/asgardius/page/s3manager/Share.java +++ b/app/src/main/java/asgardius/page/s3manager/Share.java @@ -31,7 +31,7 @@ public class Share extends AppCompatActivity { Calendar mycal; EditText datepick, monthpick, yearpick, hourpick, minutepick; int date, month, year, hour, minute; - Button share; + Button share, external; public static String URLify(String str) { str = str.trim(); @@ -73,6 +73,7 @@ public class Share extends AppCompatActivity { hourpick = (EditText)findViewById(R.id.Hour); minutepick = (EditText)findViewById(R.id.Minute); share = (Button)findViewById(R.id.share); + external = (Button)findViewById(R.id.open_in); endpoint = getIntent().getStringExtra("endpoint"); username = getIntent().getStringExtra("username"); password = getIntent().getStringExtra("password"); @@ -97,31 +98,55 @@ public class Share extends AppCompatActivity { public void onClick(View view) { //buttonaction try { - date = Integer.parseInt(datepick.getText().toString()); - month = Integer.parseInt(monthpick.getText().toString()); - year = Integer.parseInt(yearpick.getText().toString()); - hour = Integer.parseInt(hourpick.getText().toString()); - minute = Integer.parseInt(minutepick.getText().toString()); - mycal.set(Calendar.YEAR, year); - mycal.set(Calendar.MONTH, month-1); - mycal.set(Calendar.DATE, date); - mycal.set(Calendar.HOUR, hour); - mycal.set(Calendar.MINUTE, minute); - mycal.set(Calendar.SECOND, 0); - Date expiration = mycal.getTime(); - //System.out.println(expiration); - GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, object).withExpiration(expiration); - URL objectURL = s3client.generatePresignedUrl(request); - //System.out.println(URLify(objectURL.toString())); - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_TEXT, URLify(objectURL.toString())); - startActivity(Intent.createChooser(shareIntent, "choose one")); + if (datepick.getText().toString().equals("") || monthpick.getText().toString().equals("") || + yearpick.getText().toString().equals("") || hourpick.getText().toString().equals("") || + minutepick.getText().toString().equals("")) { + Toast.makeText(getApplicationContext(),getResources().getString(R.string.null_expiration_date), Toast.LENGTH_SHORT).show(); + } else { + date = Integer.parseInt(datepick.getText().toString()); + month = Integer.parseInt(monthpick.getText().toString()); + year = Integer.parseInt(yearpick.getText().toString()); + hour = Integer.parseInt(hourpick.getText().toString()); + minute = Integer.parseInt(minutepick.getText().toString()); + mycal.set(Calendar.YEAR, year); + mycal.set(Calendar.MONTH, month-1); + mycal.set(Calendar.DATE, date); + mycal.set(Calendar.HOUR, hour); + mycal.set(Calendar.MINUTE, minute); + mycal.set(Calendar.SECOND, 0); + Date expiration = mycal.getTime(); + //System.out.println(expiration); + GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, object).withExpiration(expiration); + URL objectURL = s3client.generatePresignedUrl(request); + //System.out.println(URLify(objectURL.toString())); + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, URLify(objectURL.toString())); + startActivity(Intent.createChooser(shareIntent, "choose one")); + } } catch (Exception e) { Toast.makeText(getApplicationContext(),getResources().getString(R.string.invalid_expiration_date), Toast.LENGTH_SHORT).show(); } } }); + external.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view) { + //buttonaction + try { + GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, object); + URL objectURL = s3client.generatePresignedUrl(request); + //System.out.println(URLify(objectURL.toString())); + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, URLify(objectURL.toString())); + startActivity(Intent.createChooser(shareIntent, "choose one")); + } catch (Exception e) { + Toast.makeText(getApplicationContext(),getResources().getString(R.string.invalid_expiration_date), Toast.LENGTH_SHORT).show(); + } + } + + }); } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_object_info.xml b/app/src/main/res/layout/activity_object_info.xml new file mode 100644 index 0000000..4a8f6c1 --- /dev/null +++ b/app/src/main/res/layout/activity_object_info.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_share.xml b/app/src/main/res/layout/activity_share.xml index 27942ff..aba7813 100644 --- a/app/src/main/res/layout/activity_share.xml +++ b/app/src/main/res/layout/activity_share.xml @@ -112,7 +112,15 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:text="@string/create_link" + android:text="@string/file_share" + tools:ignore="MissingConstraints" /> + +