Get Google Drive Folder Name and Path using DriveId - java

I am using google drive api contents given on GitHub for selecting folder. With below code , I could able to get folder id to transfer data but I m not able to get folder name or folder path. Can some one help over this? I tried to use asDriveFolder but did not get required info.
Here is code to get drive Id of selected folder.
public class GoogleFolderSelector extends GoogleDriveBaseActivity {
String TAG = "Google Folder Picker";
private static final int REQUEST_CODE_OPENER = 1;
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
IntentSender intentSender = Drive.DriveApi
.newOpenFileActivityBuilder()
.setMimeType(new String[]{DriveFolder.MIME_TYPE})
.build(getGoogleApiClient());
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.w(TAG, "Unable to send intent", e);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
try {
switch (requestCode) {
case REQUEST_CODE_OPENER:
if (resultCode == RESULT_OK) {
DriveId driveId = (DriveId) data.getParcelableExtra(
OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
DriveFolder driveFolder = driveId.asDriveFolder();
showMessage("Folder Path"+ driveFolder);
showMessage("Selected folder's ID: " + driveId);
}
finish();
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
} catch (Exception e) {
e.printStackTrace();
Popup.longpopup("Connection Established, Click to select Folder", this);
}
}
}

In order to get folder name, let use meta data as below
Task<Metadata> getMetadataTask = getDriveResourceClient().getMetadata(file);
getMetadataTask
.addOnSuccessListener(this,
metadata -> {
showMessage(getString(
R.string.metadata_retrieved, metadata.getTitle()));
finish();
})
.addOnFailureListener(this, e -> {
Log.e(TAG, "Unable to retrieve metadata", e);
showMessage(getString(R.string.read_failed));
finish();
});
Here is the full instruction
For the folder path, I used to try to retrieve but it seems it is not necessary as you could manipulate everything with driveId such as add file into this driveId folder or create another folder inside this driveId folder. Explore google sample app will give you a better sight.

Related

How to support auto in-app updates Android example in Java

I tried these libraries found on github but i didn't find a way to test if the updates really works ?
how to support auto in-app updates android?
i found this artical that solve this issue to make it clear i'll write the class code and remember there is two methods to implement in-app updates: immediate and flexible.
1 implementation 'com.google.android.play:core:1.10.3'
2.1 if you will use flexible method replace the class name with yours exemple 'MainActivity'
public class Flexible extends AppCompatActivity {
private AppUpdateManager appUpdateManager;
private InstallStateUpdatedListener installStateUpdatedListener;
private static final int FLEXIBLE_APP_UPDATE_REQ_CODE = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update_f);
appUpdateManager = AppUpdateManagerFactory.create(getApplicationContext());
installStateUpdatedListener = state -> {
if (state.installStatus() == InstallStatus.DOWNLOADED) {
popupSnackBarForCompleteUpdate();
} else if (state.installStatus() == InstallStatus.INSTALLED) {
removeInstallStateUpdateListener();
} else {
Toast.makeText(getApplicationContext(), "InstallStateUpdatedListener: state: " + state.installStatus(), Toast.LENGTH_LONG).show();
}
};
appUpdateManager.registerListener(installStateUpdatedListener);
checkUpdate();
}
private void checkUpdate() {
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
startUpdateFlow(appUpdateInfo);
} else if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
popupSnackBarForCompleteUpdate();
}
});
}
private void startUpdateFlow(AppUpdateInfo appUpdateInfo) {
try {
appUpdateManager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType.FLEXIBLE, this, Flexible.FLEXIBLE_APP_UPDATE_REQ_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FLEXIBLE_APP_UPDATE_REQ_CODE) {
if (resultCode == RESULT_CANCELED) {
Toast.makeText(getApplicationContext(), "Update canceled by user! Result Code: " + resultCode, Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_OK) {
Toast.makeText(getApplicationContext(),"Update success! Result Code: " + resultCode, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Update Failed! Result Code: " + resultCode, Toast.LENGTH_LONG).show();
checkUpdate();
}
}
}
private void popupSnackBarForCompleteUpdate() {
Snackbar.make(findViewById(android.R.id.content).getRootView(), "New app is ready!", Snackbar.LENGTH_INDEFINITE)
.setAction("Install", view -> {
if (appUpdateManager != null) {
appUpdateManager.completeUpdate();
}
})
.setActionTextColor(getResources().getColor(R.color.purple_500))
.show();
}
private void removeInstallStateUpdateListener() {
if (appUpdateManager != null) {
appUpdateManager.unregisterListener(installStateUpdatedListener);
}
}
#Override
protected void onStop() {
super.onStop();
removeInstallStateUpdateListener();
}}
2.1 if you will use Immediate method replace the class name with yours exemple 'MainActivity'
public class Immediate extends AppCompatActivity {
private AppUpdateManager appUpdateManager;
private static final int IMMEDIATE_APP_UPDATE_REQ_CODE = 124;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update_f);
appUpdateManager = AppUpdateManagerFactory.create(getApplicationContext());
checkUpdate();
}
private void checkUpdate() {
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
startUpdateFlow(appUpdateInfo);
} else if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS){
startUpdateFlow(appUpdateInfo);
}
});
}
private void startUpdateFlow(AppUpdateInfo appUpdateInfo) {
try {
appUpdateManager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType.IMMEDIATE, this, Immediate.IMMEDIATE_APP_UPDATE_REQ_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == IMMEDIATE_APP_UPDATE_REQ_CODE) {
if (resultCode == RESULT_CANCELED) {
Toast.makeText(getApplicationContext(), "Update canceled by user! Result Code: " + resultCode, Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_OK) {
Toast.makeText(getApplicationContext(), "Update success! Result Code: " + resultCode, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Update Failed! Result Code: " + resultCode, Toast.LENGTH_LONG).show();
checkUpdate();
}
}
}}
3 How to test? please follow all the steps
3.1 Generate a signed app bundle/APK. Note that the APK signing key and the applicationId should be the same as the already published application.
3.2 Share the generated APK with a tester. To do that, select the published application in the Google console, navigate to Internal App Sharing, and upload the generated APK there. Check how to use Google Internal App Sharing.
3.3 Copy the upload’s shareable link and share it with a tester. In this case, the tester should have an Android mobile phone.
3.4 Open the shared link on the phone’s browser. You will be redirected to the Play store.
3.5 Download the app and wait for the installation to complete.
3.6 Once done, generate another signed app bundle/APK. This time change versionCode and versionName in your app.gradle file to a higher version
3.7 Once you have generated the app bundle/APK, head to App Internal Sharing and upload it.
3.8 Again, copy the shareable link generated by this upload and open it with the tester. When the link launches on the Google Play store, you will get an update button, do not click update.
3.9 Close the Google Play store and open the application we installed earlier. This will launch an update UI that will prompt you to update the application. The UI may differ depending on your update type (either flexible or immediate).

Getting FileNotFoundException (Permission denied) when trying to read metadata from a picture

I am accessing pictures of the device's gallery via my app, when the picture is accessed the metadata of the picture will be read and stored in metadata. The problem I'm facing is that whenever the program tries to read the metadata I'm getting the following error java.io.FileNotFoundException: /storage/emulated/0/Snapchat/Snapchat-1185425082.jpg (Permission denied).
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK && requestCode == PICK_IMAGE){
imageUri = data.getData();
imageView.setImageURI(imageUri);
File picturesfile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
picturesfile.setReadable(true);
picturesfile.setExecutable(true);
String[] projection = {MediaStore.Images.Media.DATA};
try {
Cursor cursor = getContentResolver().query(imageUri, projection, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(projection[0]);
path = cursor.getString(columnIndex);
Log.d("Picture Path", path);
}
catch(Exception e) {
Log.e("Path Error", e.toString());
}
File jpegFile = new File(path);
jpegFile.setReadable(true);
jpegFile.setExecutable(true);
try {
metadata = ImageMetadataReader.readMetadata(jpegFile);
for (Directory directory : metadata.getDirectories()) {
for (Tag hoi : directory.getTags()) {
Log.d("tags ", hoi.toString());
}
}
} catch (ImageProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
if(resultCode == RESULT_OK && requestCode == 0){
Bitmap bitmap = (Bitmap)data.getExtras().get("data");
imageView.setImageBitmap(bitmap);
}
}
Tactically, it would appear that you do not have the READ_EXTERNAL_STORAGE permission, which you need to request in the manifest and at runtime.
Beyond that:
There is no requirement for your query() to return a DATA column
There is no requirement that the DATA column have a value
There is no requirement that the DATA column have a filesystem path
There is no requirement that the filesystem path in the DATA column be a file that you can access, even with READ_EXTERNAL_STORAGE
In particular, it is guaranteed that your code will fail on Android Q, and it is very likely to fail for lots of users on lots of other devices as well.
Use the Uri (imageUri) with ContentResolver to get an InputStream (or perhaps a FileDescriptor) to pass to your library.

Get real path of a file from URI? [duplicate]

I am trying to fetch a file this way:
final Intent chooseFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
String[] mimetypes = {"application/pdf"};
chooseFileIntent.setType("*/*");
chooseFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
if (chooseFileIntent.resolveActivity(activity
.getApplicationContext().getPackageManager()) != null) {
chooseFileIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
activity.startActivityForResult(chooseFileIntent, Uploader.PDF);
}
Then in onActivityResult :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
According to many threads I'm supposed to fetch the file name from the intent with data.getData().getPath(), the file name I'm expecting is my_file.pdf, but instead I'm getting this :
/document/acc=1;doc=28
So what to do? Thanks for your help.
I am trying to fetch a file
Not with that code. That code is asking the user to pick a piece of content. This may or may not be a file.
According to many threads I'm supposed to fetch the file name from the intent with data.getData().getPath()
That was never correct, though it tended to work on older versions of Android.
So what to do?
Well, that depends.
If you wish to only accept files, integrate a file chooser library instead of using ACTION_GET_CONTENT. (UPDATE 2019-04-06: since Android Q is banning most filesystem access, this solution is no longer practical)
If you are willing to allow the user to pick a piece of content using ACTION_GET_CONTENT, please understand that it does not have to be a file and it does not have to have something that resembles a filename. The closest that you will get:
If getScheme() of the Uri returns file, your original algorithm will work
If getScheme() of the Uri returns content, use DocumentFile.fromSingleUri() to create a DocumentFile, then call getName() on that DocumentFile — this should return a "display name" which should be recognizable to the user
To get the real name and to avoid getting a name that looks like "image: 4431" or even just a number, you can write code as recommended by CommonsWare.
The following is an example of a code that selects a single pdf file, prints its name and path to the log, and then sends the file by email using its uri.
private static final int FILEPICKER_RESULT_CODE = 1;
private static final int SEND_EMAIL_RESULT_CODE = 2;
private Uri fileUri;
private void chooseFile() {
Intent fileChooser = new Intent(Intent.ACTION_GET_CONTENT);
fileChooser.setType("application/pdf");
startActivityForResult(Intent.createChooser(fileChooser, "Choose one pdf file"), FILEPICKER_RESULT_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILEPICKER_RESULT_CODE) {
if (resultCode == RESULT_OK) {
fileUri = data != null ? data.getData() : null;
if (fileUri != null) {
DocumentFile d = DocumentFile.fromSingleUri(this, fileUri);
if (d != null) {
Log.d("TAG", "file name: " + d.getName());
Log.d("TAG", "file path: " + d.getUri().getPath());
sendEmail(fileUri);
}
}
}
}
}
private void sendEmail(Uri path) {
String email = "example#gmail.com";
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("application/octet-stream");
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "PDF file");
String[] to = { email };
intent.putExtra(Intent.EXTRA_EMAIL, to);
intent.putExtra(Intent.EXTRA_TEXT, "This is the pdf file...");
intent.putExtra(Intent.EXTRA_STREAM, path);
startActivityForResult(Intent.createChooser(intent, "Send mail..."), SEND_EMAIL_RESULT_CODE);
}
hope it helps.

How create directory using URI (Android)?

In my application i want to create subdirectories in choosen directory. Im using SAF (Storage Access Framework): choose directory and create one subdirectory works fine.
Choose directory:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, REQUEST_CODE_PATH_TO_DATA);
Create subdirectory:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) {
return;
}
if (requestCode == REQUEST_CODE_PATH_TO_DATA) {
if (data == null) {
return;
}
DocumentFile pickedDir = DocumentFile.fromTreeUri(getActivity(), data.getData());
getActivity().grantUriPermission(getActivity().getPackageName(), data.getData(), Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getActivity().getContentResolver().takePersistableUriPermission(data.getData(), Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
pickedDir.createDirectory("Portfolio");
String pathToPickedDir = "";
for (DocumentFile file : pickedDir.listFiles()) {
if (file.isDirectory() && file.getName().endsWith("Portfolio")) {
pathToPickedDir = file.getUri().toString();
}
}
}
}
URI from pickedDir is:
content://com.android.externalstorage.documents/tree/314E-7741%3ADCIM
And URI from created subdirectory "Portfolio" is:
content://com.android.externalstorage.documents/tree/314E-7741%3ADCIM/document/314E-7741%3ADCIM%2FPortfolio
And then when im trying to create subdirectory in "Portfolio" i can't do that, because the directory is created in the folder that was initially selected, not in the "Portfolio" folder.
DocumentFile pickedDir = DocumentFile.fromTreeUri(getActivity(), pathToPickedDir);
pickedDir.createDirectory("Patient");
What am I doing wrong? Thank you for your help.
Only way that i found is using "for" cycle:
for (DocumentFile file : pickedDir.listFiles()) {
if (file.isDirectory() && file.getName().equals("Portfolio")) {
file.createDirectory("Subdirectory");
}
}
The following should work in your case:
DocumentFile portfolioDir = pickedDir.createDirectory("Portfolio");
portfolioDir.createDirectory("Patient");
In your code, you are not using the directory object returned by DocumentFile.createDirectory(), which is the object of the newly created directory, in which you want to create a sub-directory.

How to check/set mime type in Android

Quick overview; I am building a Android application for file sharing, just began really but a little stuck on something. I want to enable the user to share multiple different file formats e.g. images, documents, videos etc. Now I got it all that working but only one at a time as show below. I have to change the string variable 'type' to certain mime type in order to open that file. I have the URI of the file that is selected if that helps.
I have Toasts in there just for testing purposes. Basically what I wish to achieve is that the application will check what file format is selected and open the apporiate third party app to preview that file when the preview button is clicked e.g. .JPG file will open pictures/gallery.
I believe code needs to be added to the 'previewBtn' in the onClick method but could be wrong.
Is there a way that the application can check what file is selected, and then set 'type' to be equal to that?
public class ShareFilesActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "ShareFilesActivity";
TextView mTextView = null;
String mimeType = null;
private static final int REQUEST_CODE = 6384; // onActivityResult request
// code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_share_files);
Button chooseFile;
chooseFile = (Button) findViewById(R.id.chooseFileBtn);
chooseFile.setOnClickListener(this);
Button previewBtn;
previewBtn = (Button) findViewById(R.id.previewBtn);
previewBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.chooseFileBtn:
showChooser();
break;
case R.id.previewBtn:
String input = mTextView.getText().toString();
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
String type = "image/*";
Toast.makeText(ShareFilesActivity.this, "Type3: " + type, Toast.LENGTH_LONG).show();
intent.setDataAndType(Uri.parse(input),type);
startActivity(intent);
Toast.makeText(ShareFilesActivity.this, input, Toast.LENGTH_LONG).show();
Toast.makeText(ShareFilesActivity.this, "Type1: " + mimeType, Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
private void showChooser() {
// Use the GET_CONTENT intent from the utility class
Intent target = FileUtils.createGetContentIntent();
// Create the chooser Intent
Intent intent = Intent.createChooser(
target, getString(R.string.chooser_title));
try {
startActivityForResult(intent, REQUEST_CODE);
} catch (ActivityNotFoundException e) {
// The reason for the existence of aFileChooser
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE:
// If the file selection was successful
if (resultCode == RESULT_OK) {
if (data != null) {
// Get the URI of the selected file
final Uri uri = data.getData();
mimeType = getContentResolver().getType(uri);
Toast.makeText(ShareFilesActivity.this, "Type2: " + mimeType, Toast.LENGTH_LONG).show();
Log.i(TAG, "Uri = " + uri.toString());
mTextView = (TextView) findViewById(R.id.fileNameTextView);
mTextView.setText(uri.toString());
mimeType = getContentResolver().getType(uri);
try {
// Get the file path from the URI
final String path = FileUtils.getPath(this, uri);
} catch (Exception e) {
Log.e("ShareFilesActivity", "File Select Error", e);
}
}
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
}
To check mime type you can use the below function and change the type of your own use
public boolean isVideoFile(String path) {
String mimeType = URLConnection.guessContentTypeFromName(path);
System.out.println(mimeType);
return mimeType != null && mimeType.indexOf("video") == 0;
}
Will return true if the type is video on my case
Hope this helps.

Categories