I am trying to make a simple text editor for Android in Java. I run into a problem, when tring to open a file.
In this line of my code
File file = new File(getExternalFilesDir(filepath), filename);
I got a null pointer exception:
java.lang.NullPointerException: name == null
at java.io.File.<init>(File.java:150)
at java.io.File.<init>(File.java:124)
at my.app.texteditor.MainActivity$1.onClick(MainActivity.java:31)
and my app crashes, leaving the filepicker on my android device open.
For me (after some time of trying to debug my code) it seems that the
protected void onActivityResult(int requestCode, int resultCode, Intent data)
function is never called and thus the filepath and filename are never assigned, which generates the exception. Hovever I am not sure whether I detected the problem correctly and I dont know how to fix it.
Here is the (full) code of my main activity - the one where I am trying to open a file:
package my.app.texteditor;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import java.io.File;
public class MainActivity extends AppCompatActivity {
String filepath, filename, folder;
private static final int PICKFILE_RESULT_CODE = 1;
private static int PICKER_RESULT = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button OpenButton = (Button) findViewById(R.id.OpenButton);
OpenButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent getContent = new Intent(Intent.ACTION_GET_CONTENT);
getContent.setType("text/*");
startActivityForResult(getContent, PICKFILE_RESULT_CODE);
File file = new File(getExternalFilesDir(filepath), filename);
Intent openIntent = new Intent(MainActivity.this, ShowFile.class);
openIntent.putExtra("my.app.file", file);
startActivity(openIntent);
}
});
Button NewButton = (Button) findViewById(R.id.NewButton);
NewButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent newIntent = new Intent(MainActivity.this, ShowFile.class);
startActivity(newIntent);
}
});
if (!StorageHandler.isExternalStorageAvailable() || StorageHandler.isExternalStorageReadOnly()) {
OpenButton.setEnabled(false);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
PICKER_RESULT = resultCode;
if (requestCode == PICKFILE_RESULT_CODE) {
if (resultCode == RESULT_OK) {
filepath = data.getData().getPath();
filename = data.getData().getLastPathSegment();
int lastPos = filepath.length() - filename.length();
folder = filepath.substring(0, lastPos);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
}
When I put this part of my code:
File file = new File(getExternalFilesDir(filepath), filename);
Intent openIntent = new Intent(MainActivity.this, ShowFile.class);
openIntent.putExtra("my.app.file", file);
startActivity(openIntent);
in an if statement, so it will be executed only if the PICKER_RESULT variable is changed in onActivityResult function - like this:
if(PICKER_RESULT!=-1) {
File file = new File(getExternalFilesDir(filepath), filename);
Intent openIntent = new Intent(MainActivity.this, ShowFile.class);
openIntent.putExtra("my.app.file", file);
startActivity(openIntent);
}
then my android device opens the filepicker, app DOES NOT crash, but I am not able to open a file - the PICKER_RESULT is still set to -1.
So my quesion is, why is the onActivityResult function never called?
You're trying to use the result of the activity in the onClick event handler. This won't work because the activity is started asynchronously. The event handler will keep running until the end, and only then the activity starts.
All of the code that depends on the activity result should be in
onActivityResult (or a method that's called from it)
startActivityForResult(getContent, PICKFILE_RESULT_CODE);
// MOVE THIS TO onActivityResult
File file = new File(getExternalFilesDir(filepath), filename);
Intent openIntent = new Intent(MainActivity.this, ShowFile.class);
openIntent.putExtra("my.app.file", file);
startActivity(openIntent);
Related
I have a task where the user has to pick two files. I do not like the option to display a dialog before hands, saying Please pick the first file now, and then the second!", so I would like to display a title over the file chooser.
This is my (example) code:
public class MainActivity extends AppCompatActivity {
private static final int FILE_CHOOSE_RESULT_FIRST = 1, FILE_CHOOSE_RESULT_SECOND = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chooseFirstFile();
}
private void chooseFirstFile() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
Intent finalIntent = Intent.createChooser(intent, "Select first file");
startActivityForResult(finalIntent, FILE_CHOOSE_RESULT_FIRST);
}
private void chooseSecondFile() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
Intent finalIntent = Intent.createChooser(intent, "Select second file");
startActivityForResult(finalIntent, FILE_CHOOSE_RESULT_SECOND);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILE_CHOOSE_RESULT_FIRST && resultCode == RESULT_OK) {
Log.v("TEST", "First file is " + data.toString());
chooseSecondFile();
} else if (requestCode == FILE_CHOOSE_RESULT_SECOND && resultCode == RESULT_OK) {
Log.v("TEST", "Second file is " + data.toString());
}
}
}
As you can see, I add a title to the file chooser ("Select first file" and "Select the second file"), but it doesn't get shown:
How can I actually show the file chooser's title?
I've seen the question this one can be seen as a duplicate of, but I did not understand it to answer it, because it asks about the gravity and style of the title.
There is no way to do that. File Picker is based on the ResolverActivity. As evident from this post: How to change the appearance of the file picker title on Android?, there is this info:
createChooser creates an intent with an ACTION_CHOOSER action.
When you launch your intent, a ChooserActivity is created (not sure how exactly) which extends ResolverActivity. The layout applied to ResolverActivity is resolver_list or resolver_list_with_default. In there you can find the title in question.
There is no way to do that as you can't change the title, which is you could say "read-only". But as the answer from the other question also tells, you can create your custom file chooser based on the original source code. Or using a Document Provider create a custom navigator.
I'm making an Android application in Android studio where the user can take a photo and save it into a new folder in their gallery. Currently the application takes the pictures fine but doesn't save the image into the new "SOC" folder in my gallery. I'm not getting any errors and I have no idea why it's not saving the image. Any help would be appreciated.
My code is as fallows
static final int REQUEST_IMAGE_CAPTURE = 1;
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 0;
public void onClickbtnCamera(View v)
{
Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
Uri uriSavedImage=Uri.fromFile(new File("/storage/emulated/0/DCIM/SOC","QR_"+timeStamp+ ".png"));
imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);
startActivityForResult(imageIntent, 1);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
//Check for succesful result code
if (resultCode == -1) {
//Show your Toast when the result is a success.
Toast toast = Toast.makeText(getApplicationContext(),
"Picture is saved in your SOC gallery", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 100, 0);
toast.show();
}
}
}
I think you must manually add your new photo Uri to Media Content Provider.
take a look here
Call this method in your Activity for result
protected void addPhotoToGallery() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(getCurrentPhotoPath());
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.getActivity().sendBroadcast(mediaScanIntent);
}
you should save the photo path before launching the intent and then getCurrentPhotoPath() must get that path
I have a WebActivity that sets a JavascriptInterface for a WebView, on the Interface I have created various methods to be called with Javascript for different tasks, one of them is to send a file through Bluetooth.
The file sends just fine, but I want to inform the user when the file has already been accepted and transmited completely on the other end.
I am trying to use onActivityResult on my main WebActivity and also have tried on the separate class that handles the Bluetooth transmission and has a method called on the JavascriptInterface but I am not getting any callback results after the file is succesfully sent:
//First attempt
public class WebActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
//some code here
//Here I set the interface
myWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
}
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == 0) {
//This message is shown after the file transfer has started but no
//finished
Toast.makeText(this, "File Sent", Toast.LENGTH_SHORT).show();
if(resultCode == Activity.RESULT_OK){
//It doesn't work here either I always get Activity.RESULT_CANCELED (0)
//flag afer the file transfer has started
}
}
}
}
//Second Attempt
public class BluetoothTasks {
//code here
private void startTransferIntent() {
//some more code here
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
File file_to_transfer = new File(Environment.getExternalStorageDirectory() +
"/txtTransfer.txt");
intent.putExtra(Intent.EXTRA_STREAM,Uri.fromFile(file_to_transfer));
//some more code here
Activity act = (Activity) mContext;
act.startActivityForResult(intent, TRANSFER_RESULT);
}
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == TRANSFER_RESULT) {
//Not working here either
//code that is not executed
}
}
}
Could you please tell me if there is a way to do this and if so how would be accomplished?. Thank you.
I have an imageView i am trying to set an image to based on the file path of an image the user selects from their gallery. I put the path into a database and then i pass that path into another activity to set the imageView to display. The path comes back at all steps as
/external/images/media/23
I have used multiple toasts to check the path in the activity before i pass the path, after receiving the path by the called method so i know the path is being sent from activity to activity correctly. However when i use the following code to set the imageView nothing appears.
File imgFile;
//Bitmap moviePic;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_view);
Bundle income = getIntent().getExtras();
if(income != null)
{
mTitle = income.getString("title");
mYear = income.getString("year");
id = income.getLong("id");
mPath = income.getString("path");
}
Toast.makeText(this, "path: " + mPath, Toast.LENGTH_SHORT).show();
imV = (ImageView) findViewById(R.id.movieImage);
//moviePic = BitmapFactory.decodeFile(mPath);
imgFile = new File(mPath);
imV.setImageURI(Uri.fromFile(imgFile));
//imV.setImageResource(R.drawable.top);
mVT = (TextView) findViewById(R.id.movieViewTitle);
mVT.setText(mTitle);
mVY = (TextView) findViewById(R.id.movieViewYear);
mVY.setText(mYear);
delete = (Button) findViewById(R.id.deleteMovie);
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent deleting = new Intent();
deleting.putExtra("Id", id);
setResult(RESULT_OK, deleting);
finish();
}
});
}
My guess is that im doing something wrong with the file path. Below is the code i use to resolve the path.
imgV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent addImage = new
Intent(android.content.Intent.ACTION_PICK);
addImage.setType("image/*");
startActivityForResult(addImage, 1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
super.onActivityResult(requestCode, resultCode, intent);
switch(requestCode)
{
case 1:
if(resultCode == RESULT_OK)
{
Uri image = intent.getData();
imgV.setImageURI(image);
moviePath = image.getPath();
Toast.makeText(this, moviePath, Toast.LENGTH_LONG).show();
}
}
}
}
To find the image files i used the android emulator, browsed to google images and downloaded one or two. When i look in the DDMS It placed them in the mnt\sdcar\download\ folder which is obviously different than the path they are resolving to using the image.getPath() method. Is there another way i should be resolving the path? Or is there something im missing with the way the emulator file path works.
I noticed the default camera activity I call on a Droid X is different looking than the one on my Droid and Nexus One. After selecting "OK" on the Droid and Nexus One, the activity would finish - the Droid X has a "Done" button (which takes you back to the Camera, instead of finishing the activity), and the only way to get to the screen I want is to hit the "Back" button.
Here is the class that works on Android 2.2/2.3, but not for Droid X's:
package com.android.xxx;
import java.io.File;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.Window;
public class CameraView extends MenusHolder {
protected String _path;
protected boolean _taken;
protected static final String PHOTO_TAKEN = "photo_taken";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.create_event_view);
/*
* save to sd
*/
File imageDirectory = new File(
Environment.getExternalStorageDirectory() + "/MyPath/");
imageDirectory.mkdirs();
/*
* temp image overwrites each time for space
*/
_path = Environment.getExternalStorageDirectory()
+ "/MyPath/temporary_image.jpg";
startCameraActivity();
}
protected void startCameraActivity() {
File file = new File(_path);
Uri outputFileUri = Uri.fromFile(file);
Intent intent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) {
case 0:
setResult(5);
finish();
break;
case -1:
onPhotoTaken();
break;
}
}
protected void onPhotoTaken() {
_taken = true;
setResult(0);
finish();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean(CameraView.PHOTO_TAKEN, _taken);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState.getBoolean(CameraView.PHOTO_TAKEN)) {
onPhotoTaken();
}
}
}
I solved this with a really really ugly workaround. I coded two functions to read and write files from sdcard (taken from here: http://www.sgoliver.net/blog/?p=2035).
private boolean readFile() {
try
{
File sd_path = Environment.getExternalStorageDirectory();
File f = new File(sd_path.getAbsolutePath(), "lock_camera_oncreate");
BufferedReader fin =
new BufferedReader(
new InputStreamReader(
new FileInputStream(f)));
String text = fin.readLine();
fin.close();
Log.e("Files", "Reading file");
return true;
}
catch (Exception ex)
{
Log.e("Files", "Error reading file from SD Card");
return false;
}
}
private void createFile() {
try
{
File sd_path = Environment.getExternalStorageDirectory();
File f = new File(sd_path.getAbsolutePath(), "lock_camera_oncreate");
OutputStreamWriter fout =
new OutputStreamWriter(
new FileOutputStream(f));
fout.write("Semaphore test.");
fout.close();
Log.e("Files", "File writed");
}
catch (Exception ex)
{
Log.e("Files", "Error reading file from SD Card");
}
}
Then, in onCreate function, I make this:
public void onCreate(Bundle savedInstanceState) {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onCreate(savedInstanceState);
if(readFile() == true)
{
File sd_path = Environment.getExternalStorageDirectory();
File f = new File(sd_path.getAbsolutePath(), "lock_camera_oncreate");
f.delete();
Intent intent = this.getIntent();
this.setResult(RESULT_OK, intent);
return;
}
createFile();
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCurrentImagePath)));
startActivityForResult(cameraIntent, TAKE_PHOTO_CODE);
}
The setRequestedOrientation call solves the issue when you are using your app in portrait mode, but when camera is launched, you put the mobile in landscape and then shoot the photo.
Then, the ugly readFile thing checks if a lock_camera_oncreate file exists and if it's true,
then an additional onCreate call happened, so delete file and RETURN from this activity.
If activity advances, means the file's not created and there is only one camera activity running.
Hope it helps, it's ugly but worked for me :D
Dude... it's just a bug. I had the same problem and there's no way to workaround that. It sometimes work, and sometimes it does not. I asked the Motorola's guy for help and they said that there's no support for those Android images.