A lot of stuff

This commit is contained in:
Isaac Shoebottom 2022-12-06 16:14:34 -04:00
parent 9b60e78c1f
commit 897ae05c1a
6 changed files with 467 additions and 22 deletions

View File

@ -43,7 +43,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
implementation 'com.arthenica:ffmpeg-kit-full:5.1' implementation 'com.arthenica:ffmpeg-kit-full:5.1.LTS'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4' androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'

View File

@ -3,6 +3,12 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication"> package="com.example.myapplication">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"

View File

@ -4,7 +4,8 @@ import java.io.FileDescriptor
class Compressor { class Compressor {
public fun compressFile(fileDescriptor: FileDescriptor) { fun compressFile(fileDescriptor: FileDescriptor) {
} }
} }

View File

@ -1,17 +1,21 @@
package com.example.myapplication package com.example.myapplication
import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.FileUtils
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
@ -20,14 +24,16 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.databinding.ActivityMainBinding import com.example.myapplication.databinding.ActivityMainBinding
import com.example.myapplication.ui.compressing.CompressingAdapter import com.example.myapplication.ui.compressing.CompressingAdapter
import com.example.myapplication.ui.compressing.CompressingFragment
import com.example.myapplication.ui.compressing.CompressingItem import com.example.myapplication.ui.compressing.CompressingItem
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import com.arthenica.ffmpegkit.FFmpegKit
import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.util.* import java.util.*
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val compressingItems: MutableList<CompressingItem> = mutableListOf()
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
@ -56,9 +62,7 @@ class MainActivity : AppCompatActivity() {
//adds actions for when you press buttons //adds actions for when you press buttons
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
val compressingRecycler = findViewById<View>(R.id.compressing_recycler_view) as? RecyclerView
compressingRecycler?.adapter = CompressingAdapter(compressingItems)
compressingRecycler?.layoutManager = LinearLayoutManager(this)
return when (item.itemId) { return when (item.itemId) {
@ -74,12 +78,6 @@ class MainActivity : AppCompatActivity() {
Toast.makeText(applicationContext, "Files", Toast.LENGTH_LONG).show() Toast.makeText(applicationContext, "Files", Toast.LENGTH_LONG).show()
if (fileName != null && fileDate != null) {
compressingItems.add(CompressingItem(fileName!!, 0.0, fileDate!!))
}
compressingItems.add(CompressingItem("Testing", 0.5, Date(1)))
return true return true
} }
R.id.addYoutube ->{ R.id.addYoutube ->{
@ -90,13 +88,9 @@ class MainActivity : AppCompatActivity() {
} }
} }
private var fileName: String? = null
private var fileDate: Date? = null
private var fileStream: FileInputStream? = null
//grabs output from pressing files, used for grabbing URI //grabs output from pressing files, used for grabbing URI
private var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> private var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) { if (result.resultCode == RESULT_OK) {
// There are no request codes // There are no request codes
val data: Uri? = result.data?.data val data: Uri? = result.data?.data
@ -105,16 +99,32 @@ class MainActivity : AppCompatActivity() {
val fd = fileDescriptor?.fileDescriptor val fd = fileDescriptor?.fileDescriptor
val inputStream = FileInputStream(fd) val inputStream = FileInputStream(fd)
val file = File(data.toString())
Log.i("Tag", file.absolutePath)
val fu = com.example.myapplication.utils.FileUtils(this)
val test = "-i " + fu.getPath(data) + " -c:v libx264 -preset ultrafast -crf 28 -c:a aac -b:a 128k -movflags +faststart " + fu.getPath(data) + "_converted.mp4"
FFmpegKit.execute(test)
val cursor = contentResolver.query(data, null, null, null, null) val cursor = contentResolver.query(data, null, null, null, null)
val dateIndex = cursor?.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED)
fileDate = Date(dateIndex?.toLong()!!)
val nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)
fileName = cursor.getString(nameIndex)
cursor?.moveToFirst()
this.fileStream = inputStream val fileDate = Date(System.currentTimeMillis())
val fileName = cursor?.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME))
compressingItems.add(CompressingItem(fileName!!, 0.0, fileDate))
adapter.notifyDataSetChanged()
Toast.makeText(applicationContext, data.toString(), Toast.LENGTH_LONG).show() Toast.makeText(applicationContext, data.toString(), Toast.LENGTH_LONG).show()
} }
} }
companion object {
val compressingItems: MutableList<CompressingItem> = mutableListOf()
val adapter = CompressingAdapter(compressingItems)
}
} }

View File

@ -6,12 +6,19 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.MainActivity
import com.example.myapplication.MainActivity.Companion.compressingItems
import com.example.myapplication.R
import com.example.myapplication.databinding.FragmentCompressingBinding import com.example.myapplication.databinding.FragmentCompressingBinding
class CompressingFragment : Fragment() { class CompressingFragment : Fragment() {
private var _binding: FragmentCompressingBinding? = null private var _binding: FragmentCompressingBinding? = null
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
// onDestroyView. // onDestroyView.
private val binding get() = _binding!! private val binding get() = _binding!!
@ -20,7 +27,15 @@ class CompressingFragment : Fragment() {
ViewModelProvider(this)[CompressingViewModel::class.java] ViewModelProvider(this)[CompressingViewModel::class.java]
_binding = FragmentCompressingBinding.inflate(inflater, container, false) _binding = FragmentCompressingBinding.inflate(inflater, container, false)
val compressingRecycler = binding.root.findViewById<View>(R.id.compressing_recycler_view) as? RecyclerView
compressingRecycler?.adapter = MainActivity.adapter
compressingRecycler?.layoutManager = LinearLayoutManager(binding.root.context)
return binding.root return binding.root
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -0,0 +1,413 @@
package com.example.myapplication.utils;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.UUID;
public class FileUtils {
public static String FALLBACK_COPY_FOLDER = "upload_part";
private static String TAG = "FileUtils";
private static Uri contentUri = null;
Context context;
public FileUtils(Context context) {
this.context = context;
}
@SuppressLint("NewApi")
public String getPath(final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String selection = null;
String[] selectionArgs = null;
// DocumentProvider
if (isKitKat) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String fullPath = getPathFromExtSD(split);
if (fullPath == null || !fileExists(fullPath)) {
Log.d(TAG, "Copy files as a fallback");
fullPath = copyFileToInternalStorage(uri, FALLBACK_COPY_FOLDER);
}
if (fullPath != "") {
return fullPath;
} else {
return null;
}
}
// DownloadsProvider
if (isDownloadsDocument(uri)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String id;
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, new String[] {
MediaStore.MediaColumns.DISPLAY_NAME
}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
if (!TextUtils.isEmpty(path)) {
return path;
}
}
} finally {
if (cursor != null)
cursor.close();
}
id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
String[] contentUriPrefixesToTry = new String[] {
"content://downloads/public_downloads",
"content://downloads/my_downloads"
};
for (String contentUriPrefix: contentUriPrefixesToTry) {
try {
final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
//In Android 8 and Android P the id is not a number
return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
}
}
}
} else {
final String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (contentUri != null)
return getDataColumn(context, contentUri, null, null);
}
}
// MediaProvider
if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Log.d(TAG, "MEDIA DOCUMENT TYPE: " + type);
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
} else if ("document".equals(type)) {
contentUri = MediaStore.Files.getContentUri(MediaStore.getVolumeName(uri));
}
selection = "_id=?";
selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri);
}
if (isWhatsAppFile(uri)) {
return getFilePathForWhatsApp(uri);
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// return getFilePathFromURI(context,uri);
return copyFileToInternalStorage(uri, FALLBACK_COPY_FOLDER);
// return getRealPathFromURI(context,uri);
} else {
return getDataColumn(context, uri, null, null);
}
}
if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
} else {
if (isWhatsAppFile(uri)) {
return getFilePathForWhatsApp(uri);
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = null;
try {
cursor = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return copyFileToInternalStorage(uri, FALLBACK_COPY_FOLDER);
}
private static boolean fileExists(String filePath) {
File file = new File(filePath);
return file.exists();
}
private static String getPathFromExtSD(String[] pathData) {
final String type = pathData[0];
final String relativePath = File.separator + pathData[1];
String fullPath = "";
Log.d(TAG, "MEDIA EXTSD TYPE: " + type);
Log.d(TAG, "Relative path: " + relativePath);
// on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
// something like "71F8-2C0A", some kind of unique id per storage
// don't know any API that can get the root path of that storage based on its id.
//
// so no "primary" type, but let the check here for other devices
if ("primary".equalsIgnoreCase(type)) {
fullPath = Environment.getExternalStorageDirectory() + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
}
if ("home".equalsIgnoreCase(type)) {
fullPath = "/storage/emulated/0/Documents" + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
}
// Environment.isExternalStorageRemovable() is `true` for external and internal storage
// so we cannot relay on it.
//
// instead, for each possible path, check if file exists
// we'll start with secondary storage as this could be our (physically) removable sd card
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
return null;
}
private String getDriveFilePath(Uri uri) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e(TAG, "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e(TAG, "Path " + file.getPath());
Log.e(TAG, "Size " + file.length());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return file.getPath();
}
/***
* Used for Android Q+
* @param uri
* @param newDirName if you want to create a directory, you can set this variable
* @return
*/
private String copyFileToInternalStorage(Uri uri, String newDirName) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, new String[] {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
}, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File output;
if (!newDirName.equals("")) {
String random_collision_avoidance = UUID.randomUUID().toString();
File dir = new File(context.getFilesDir() + File.separator + newDirName + File.separator + random_collision_avoidance);
if (!dir.exists()) {
dir.mkdirs();
}
output = new File(context.getFilesDir() + File.separator + newDirName + File.separator + random_collision_avoidance + File.separator + name);
} else {
output = new File(context.getFilesDir() + File.separator + name);
}
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(output);
int read = 0;
int bufferSize = 1024;
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return output.getPath();
}
private String getFilePathForWhatsApp(Uri uri) {
return copyFileToInternalStorage(uri, "whatsapp");
}
private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
public boolean isWhatsAppFile(Uri uri) {
return "com.whatsapp.provider.media".equals(uri.getAuthority());
}
private boolean isGoogleDriveUri(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
}
}