Android Email intent with multiple attachments - java

I'm working on an app where the user can fill out a report card and send it through the email client of choice (Gmail in my case). In addition to text, the user needs to be able to attach one or more images, but I can't seem to get it to work (full code attached further down).
Below is the onActivityResult which attaches the images to the view and puts their Uris in "userSelectedImageUriList". This seems to work.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==REQUEST_CODE_BROWSE_PICTURE)
{
if(resultCode==RESULT_OK)
{
// Get return image uri. If select the image from camera the uri like file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg
// If select the image from gallery the uri like content://media/external/images/media/1316970.
Uri fileUri = data.getData();
// Save user choose image file uri in list.
if(userSelectedImageUriList == null)
{
userSelectedImageUriList = new ArrayList<Uri>();
}
userSelectedImageUriList.add(fileUri);
// Create content resolver.
ContentResolver contentResolver = getContentResolver();
try {
// Open the file input stream by the uri.
InputStream inputStream = contentResolver.openInputStream(fileUri);
// Get the bitmap.
Bitmap imgBitmap = BitmapFactory.decodeStream(inputStream);
ImageView imageview = new ImageView(ReportCard.this);
LinearLayout linearLayout = (LinearLayout)findViewById(R.id.imageHolderLayout);
LinearLayout.LayoutParams params = new LinearLayout
.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
// Add image path from drawable folder.
imageview.setImageBitmap(imgBitmap);
imageview.setLayoutParams(params);
linearLayout.addView(imageview);
inputStream.close();
}catch(FileNotFoundException ex)
{
Log.e(TAG_BROWSE_PICTURE, ex.getMessage(), ex);
}catch(IOException ex)
{
Log.e(TAG_BROWSE_PICTURE, ex.getMessage(), ex);
}
}
}
}
Next, when the user clicks the send button I create the email intent.
public void sendReport(Context context) {
EditText nameField = (EditText)findViewById(R.id.EditTextName);
EditText emailField = (EditText)findViewById(R.id.EditTextEmail);
EditText locationField = (EditText)findViewById(R.id.EditTextLocation);
EditText dateField = (EditText)findViewById(R.id.EditTextDate);
EditText bodyField = (EditText)findViewById(R.id.EditTextBody);
if(!nameField.getText().toString().matches("") && !emailField.getText().toString().matches("") && !locationField.getText().toString().matches("") && !dateField.getText().toString().matches("") && !bodyField.getText().toString().matches("")) {
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit().putString("report_email", emailField.getText().toString()).commit();
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit().putString("report_name", nameField.getText().toString()).commit();
String emailBody = "Name: "+nameField.getText()+"\n\n";
emailBody += "Location: "+locationField.getText()+"\n\n";
emailBody += "Time: "+dateField.getText()+"\n\n";
emailBody += "Description: "+bodyField.getText();
Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
// set the type to 'email'
emailIntent.setType("text/plain");
String to[] = {emailField.getText().toString()};
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
// the attachment
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, userSelectedImageUriList);
// the mail
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Report");
emailIntent.putExtra(Intent.EXTRA_TEXT, emailBody);
startActivity(Intent.createChooser(emailIntent , "Send using..."));
finish();
} else {
Toast.makeText(this, getString(R.string.field_error), Toast.LENGTH_SHORT).show();
}
}
Now, this is where things stop working. The chooser is displayed but the images are not attached. Gmail opens but a toast is displayed with "Could not attach file".
Full code
ReportCard.java
package com.zaewin.reports;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
public class ReportCard extends Activity {
long reportID;
long newRowId;
// Log tag that is used to distinguish log info.
private final static String TAG_BROWSE_PICTURE = "BROWSE_PICTURE";
// Used when request action Intent.ACTION_GET_CONTENT
private final static int REQUEST_CODE_BROWSE_PICTURE = 1;
// Used when request read external storage permission.
private final static int REQUEST_PERMISSION_READ_EXTERNAL = 2;
// Save user selected image uri list.
private ArrayList<Uri> userSelectedImageUriList = null;
// Currently displayed user selected image index in userSelectedImageUriList.
private int currentDisplayedUserSelectImageIndex = 0;
#Override
public void onBackPressed() {
saveReport(ReportCard.this);
finish();
}
// create an action bar button
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.reportmenu, menu);
return super.onCreateOptionsMenu(menu);
}
// handle button activities
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.deleteButton:
new AlertDialog.Builder(this)
.setTitle(R.string.delete)
.setMessage(R.string.delete_prompt)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Bundle bundle = getIntent().getExtras();
Boolean deletestatus = deleteReport(getApplicationContext(), bundle.getInt("reportID"));
if(deletestatus == true) {
CharSequence text = getString(R.string.delete_success);
Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT);
toast.show();
finish();
} else {
CharSequence text = getString(R.string.delete_fail);
Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT);
toast.show();
}
}})
.setNegativeButton(android.R.string.no, null).show();
return true;
case R.id.saveButton:
saveReport(getApplicationContext());
return true;
case R.id.sendButton:
sendReport(getApplicationContext());
return true;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
}
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.report_view);
setTitle(R.string.report_card);
Bundle bundle = getIntent().getExtras();
if(bundle != null) {
reportID = bundle.getInt("reportID");
loadReport(reportID);
} else {
setDefaults();
}
final Button button = (Button) findViewById(R.id.buttonAddPicture);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Because camera app returned uri value is something like file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg
// So if show the camera image in image view, this app require below permission.
int readExternalStoragePermission = ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_EXTERNAL_STORAGE);
if(readExternalStoragePermission != PackageManager.PERMISSION_GRANTED)
{
String requirePermission[] = {Manifest.permission.READ_EXTERNAL_STORAGE};
ActivityCompat.requestPermissions(ReportCard.this, requirePermission, REQUEST_PERMISSION_READ_EXTERNAL);
}else {
openPictureGallery();
}
}
});
}
/* Invoke android os system file browser to select images. */
private void openPictureGallery()
{
// Create an intent.
Intent openAlbumIntent = new Intent();
// Only show images in the content chooser.
// If you want to select all type data then openAlbumIntent.setType("*/*");
// Must set type for the intent, otherwise there will throw android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.GET_CONTENT }
openAlbumIntent.setType("image/*");
// Set action, this action will invoke android os browse content app.
openAlbumIntent.setAction(Intent.ACTION_GET_CONTENT);
// Start the activity.
startActivityForResult(openAlbumIntent, REQUEST_CODE_BROWSE_PICTURE);
}
/* When the action Intent.ACTION_GET_CONTENT invoked app return, this method will be executed. */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==REQUEST_CODE_BROWSE_PICTURE)
{
if(resultCode==RESULT_OK)
{
// Get return image uri. If select the image from camera the uri like file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg
// If select the image from gallery the uri like content://media/external/images/media/1316970.
Uri fileUri = data.getData();
// Save user choose image file uri in list.
if(userSelectedImageUriList == null)
{
userSelectedImageUriList = new ArrayList<Uri>();
}
userSelectedImageUriList.add(fileUri);
// Create content resolver.
ContentResolver contentResolver = getContentResolver();
try {
// Open the file input stream by the uri.
InputStream inputStream = contentResolver.openInputStream(fileUri);
// Get the bitmap.
Bitmap imgBitmap = BitmapFactory.decodeStream(inputStream);
ImageView imageview = new ImageView(ReportCard.this);
LinearLayout linearLayout = (LinearLayout)findViewById(R.id.imageHolderLayout);
LinearLayout.LayoutParams params = new LinearLayout
.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
// Add image path from drawable folder.
imageview.setImageBitmap(imgBitmap);
imageview.setLayoutParams(params);
linearLayout.addView(imageview);
inputStream.close();
}catch(FileNotFoundException ex)
{
Log.e(TAG_BROWSE_PICTURE, ex.getMessage(), ex);
}catch(IOException ex)
{
Log.e(TAG_BROWSE_PICTURE, ex.getMessage(), ex);
}
}
}
}
/* After user choose grant read external storage permission or not. */
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if(requestCode==REQUEST_PERMISSION_READ_EXTERNAL)
{
if(grantResults.length > 0)
{
int grantResult = grantResults[0];
if(grantResult == PackageManager.PERMISSION_GRANTED)
{
// If user grant the permission then open choose image popup dialog.
openPictureGallery();
}else
{
Toast.makeText(getApplicationContext(), "You denied read external storage permission.", Toast.LENGTH_LONG).show();
}
}
}
}
public void setDefaults() {
EditText emailField = (EditText)findViewById(R.id.EditTextEmail);
emailField.setText(PreferenceManager.getDefaultSharedPreferences(getBaseContext()).getString("report_email", ""), TextView.BufferType.EDITABLE);
EditText nameField = (EditText)findViewById(R.id.EditTextName);
nameField.setText(PreferenceManager.getDefaultSharedPreferences(getBaseContext()).getString("report_name", ""), TextView.BufferType.EDITABLE);
Calendar c = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String formattedDate = df.format(c.getTime());
EditText dateField = (EditText)findViewById(R.id.EditTextDate);
dateField.setText(formattedDate, TextView.BufferType.EDITABLE);
}
public void loadReport(long reportID) {
ReportDbHelper mDbHelper = new ReportDbHelper(getBaseContext());
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
ReportContract.ReportEntry._ID,
ReportContract.ReportEntry.COLUMN_NAME,
ReportContract.ReportEntry.COLUMN_EMAIL,
ReportContract.ReportEntry.COLUMN_LOCATION,
ReportContract.ReportEntry.COLUMN_DATE,
ReportContract.ReportEntry.COLUMN_BODY
};
// Filter results WHERE "title" = 'My Title'
String selection = ReportContract.ReportEntry._ID + " = ?";
String[] selectionArgs = { Long.toString(reportID) };
// How you want the results sorted in the resulting Cursor
String sortOrder = ReportContract.ReportEntry.COLUMN_NAME + " DESC";
Cursor cursor = db.query(
ReportContract.ReportEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
//List itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
EditText emailField = (EditText)findViewById(R.id.EditTextEmail);
emailField.setText(cursor.getString(cursor.getColumnIndexOrThrow(ReportContract.ReportEntry.COLUMN_EMAIL)), TextView.BufferType.EDITABLE);
EditText nameField = (EditText)findViewById(R.id.EditTextName);
nameField.setText(cursor.getString(cursor.getColumnIndexOrThrow(ReportContract.ReportEntry.COLUMN_NAME)), TextView.BufferType.EDITABLE);
EditText dateField = (EditText)findViewById(R.id.EditTextDate);
dateField.setText(cursor.getString(cursor.getColumnIndexOrThrow(ReportContract.ReportEntry.COLUMN_DATE)), TextView.BufferType.EDITABLE);
EditText locationField = (EditText)findViewById(R.id.EditTextLocation);
locationField.setText(cursor.getString(cursor.getColumnIndexOrThrow(ReportContract.ReportEntry.COLUMN_LOCATION)), TextView.BufferType.EDITABLE);
EditText bodyField = (EditText)findViewById(R.id.EditTextBody);
bodyField.setText(cursor.getString(cursor.getColumnIndexOrThrow(ReportContract.ReportEntry.COLUMN_BODY)), TextView.BufferType.EDITABLE);
}
cursor.close();
db.close();
}
public long saveReport(Context context) {
EditText nameField = (EditText)findViewById(R.id.EditTextName);
EditText emailField = (EditText)findViewById(R.id.EditTextEmail);
EditText locationField = (EditText)findViewById(R.id.EditTextLocation);
EditText dateField = (EditText)findViewById(R.id.EditTextDate);
EditText bodyField = (EditText)findViewById(R.id.EditTextBody);
ReportDbHelper mDbHelper = new ReportDbHelper(context);
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(ReportContract.ReportEntry.COLUMN_NAME, nameField.getText().toString());
values.put(ReportContract.ReportEntry.COLUMN_EMAIL, emailField.getText().toString());
values.put(ReportContract.ReportEntry.COLUMN_LOCATION, locationField.getText().toString());
values.put(ReportContract.ReportEntry.COLUMN_DATE, dateField.getText().toString());
values.put(ReportContract.ReportEntry.COLUMN_BODY, bodyField.getText().toString());
CharSequence text;
try {
if(reportID == 0) {
newRowId = db.insert(ReportContract.ReportEntry.TABLE_NAME, null, values);
text = getString(R.string.save_success);
} else {
String where = ReportContract.ReportEntry._ID + " = ?";
String[] whereArgs = new String[]{String.valueOf(reportID)};
newRowId = db.update(ReportContract.ReportEntry.TABLE_NAME, values, where, whereArgs);
text = getString(R.string.update_success);
}
Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
toast.show();
//finish();
} catch(android.database.sqlite.SQLiteException ex) {
text = getString(R.string.save_error);
Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
toast.show();
}
db.close();
return newRowId;
}
public boolean deleteReport(Context context, Integer reportID) {
ReportDbHelper mDbHelper = new ReportDbHelper(context);
SQLiteDatabase db = mDbHelper.getWritableDatabase();
Boolean status = db.delete(ReportContract.ReportEntry.TABLE_NAME, ReportContract.ReportEntry._ID + "=" + reportID, null) > 0;
db.close();
return status;
}
public void sendReport(Context context) {
EditText nameField = (EditText)findViewById(R.id.EditTextName);
EditText emailField = (EditText)findViewById(R.id.EditTextEmail);
EditText locationField = (EditText)findViewById(R.id.EditTextLocation);
EditText dateField = (EditText)findViewById(R.id.EditTextDate);
EditText bodyField = (EditText)findViewById(R.id.EditTextBody);
if(!nameField.getText().toString().matches("") && !emailField.getText().toString().matches("") && !locationField.getText().toString().matches("") && !dateField.getText().toString().matches("") && !bodyField.getText().toString().matches("")) {
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit().putString("report_email", emailField.getText().toString()).commit();
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit().putString("report_name", nameField.getText().toString()).commit();
String emailBody = "Ditt namn: "+nameField.getText()+"\n\n";
emailBody += "Plats: "+locationField.getText()+"\n\n";
emailBody += "Tidpunkt: "+dateField.getText()+"\n\n";
emailBody += "Beskrivning: "+bodyField.getText();
Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
ArrayList<Uri> uris = new ArrayList<Uri>();
for (Uri file : userSelectedImageUriList)
{
File fileIn = new File(file.toString());
fileIn.setReadable(true, false);
Uri u = Uri.fromFile(fileIn);
uris.add(u);
}
// set the type to 'email'
emailIntent.setType("text/plain");
String to[] = {emailField.getText().toString()};
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
// the attachment
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
// the mail
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Rapport från Hamnarbetarappen");
emailIntent.putExtra(Intent.EXTRA_TEXT, emailBody);
startActivity(Intent.createChooser(emailIntent , "Skicka med..."));
finish();
} else {
Toast.makeText(this, getString(R.string.field_error), Toast.LENGTH_SHORT).show();
}
}
}
report_view.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="#+id/ScrollView01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp">
<EditText
android:id="#+id/EditTextName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/report_name"
android:inputType="textPersonName" >
</EditText>
<EditText
android:id="#+id/EditTextEmail"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/report_email"
android:inputType="textEmailAddress" >
</EditText>
<EditText
android:id="#+id/EditTextLocation"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/report_location" >
</EditText>
<EditText
android:id="#+id/EditTextDate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/report_date"
android:inputType="datetime" >
</EditText>
<EditText
android:id="#+id/EditTextBody"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/report_description"
android:inputType="textMultiLine"
android:lines="5" >
</EditText>
<LinearLayout
android:id="#+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="5dp">
<Button
android:id="#+id/buttonAddPicture"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#drawable/blue_button"
android:drawableRight="#drawable/ic_action_camera"
android:padding="10dp"
android:text="#string/report_takepicture"
android:textAlignment="center"
android:textColor="#color/actionbar_text" />
</LinearLayout>
<LinearLayout
android:id="#+id/imageHolderLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="5dp">
</LinearLayout>
</ScrollView>
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.zaewin.reports" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="22" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:required="true" />
<uses-permission android:name="android.permission.INTERNET" android:required="true"/>
<application android:theme="#style/CustomActionBarTheme" android:label="#string/app_name" android:icon="#mipmap/ic_launcher" android:allowBackup="true">
<activity android:label="ReportCard" android:screenOrientation="portrait" android:configChanges="orientation|keyboardHidden" android:name=".ReportCard">
<meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".ReportList" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
</application>
</manifest>

I've solved it. When the images are chosen they are put into the ArrayList "userSelectedImageUriList" in onActivityResult.
Instead of parsing this list in the sendReport method, I just add this list to the intent.
The working method looks like this:
public void sendReport(Context context) {
EditText nameField = (EditText)findViewById(R.id.EditTextName);
EditText emailField = (EditText)findViewById(R.id.EditTextEmail);
EditText locationField = (EditText)findViewById(R.id.EditTextLocation);
EditText dateField = (EditText)findViewById(R.id.EditTextDate);
EditText bodyField = (EditText)findViewById(R.id.EditTextBody);
if(!nameField.getText().toString().matches("") && !emailField.getText().toString().matches("") && !locationField.getText().toString().matches("") && !dateField.getText().toString().matches("") && !bodyField.getText().toString().matches("")) {
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit().putString("report_email", emailField.getText().toString()).apply();
PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit().putString("report_name", nameField.getText().toString()).apply();
String emailBody = "Name: "+nameField.getText()+"\n\n";
emailBody += "Location: "+locationField.getText()+"\n\n";
emailBody += "Time: "+dateField.getText()+"\n\n";
emailBody += "Description: "+bodyField.getText();
Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
// set the type to 'email'
emailIntent.setType("text/plain");
String to[] = {emailField.getText().toString()};
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
// the attachment - ArrayList populated in onActivityResult
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, userSelectedImageUriList);
// the mail
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Report);
emailIntent.putExtra(Intent.EXTRA_TEXT, emailBody);
startActivity(Intent.createChooser(emailIntent , "Send with..."));
//finish();
} else {
Toast.makeText(this, getString(R.string.field_error), Toast.LENGTH_SHORT).show();
}
}

Related

google.mlkit code never executes .addOnSuccessListener() and .addOnFailureListener()

I followed the istructions of the tutorial at com.google.codelab.mlkit.
Instead of using intent.data I am using FileProvider to get and analyze the full picture.
I replaced the virtural image in the emulation based on the recommendation in Android emulator camera custom image.
So I start my app (main activity), take a photo with the internal camera (which is the replaced virtual image) and get back to the main activity. I run into the code recognizeTextFromImage(), but I never run into .addOnSuccessListener() and .addOnFailureListener(). That surpises me because I even do not get a failure. Nothing is printed into the log.
I am using API-level 23 because the resultCode is 0 (instead of -1) if I am using a higher API.
My question is: why doesn't my code run into .addOnSuccessListener() or at least into .addOnFailureListener() ?
1. Update
I tried "intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);``` and this changed the behavior. It took seconds to read the file. So I think #Danish was correct that the file was not created by the camera. But: same issue with addOnFailureListener(). Maybe the file is to big? Or did I send the wrong format? The Log says "W/e.codelab.mlki: Verification of java.lang.String com.google.codelab.mlkit.MainActivity.recognizeTextFromImage(com.google.mlkit.vision.common.InputImage) took 536.238ms"
2. Update
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
</paths>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.codelab.mlkit">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="true"/>
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.codelab.mlkit.vision.DEPENDENCIES"
android:value="ocr" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/activity_main_scene"
tools:context=".MainActivity" >
<TableLayout
android:layout_width="360dp"
android:layout_height="539dp"
android:layout_centerInParent="true">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView_ServiceID"
android:layout_width="11dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:gravity="center"
android:text="ServiceID"
android:textAlignment="viewStart" />
<EditText
android:id="#+id/editText_ServiceID"
android:layout_height="match_parent"
android:layout_weight="0.7
"
android:gravity="left"
android:inputType="text"
android:text="4711" />
</TableRow>
</TableLayout>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="359dp"
android:layout_height="match_parent">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView_Site"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:gravity="center"
android:text="Site"
android:textAlignment="viewStart" />
<Spinner
android:id="#+id/spinner_Site"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<ImageButton
android:id="#+id/imageButton_Site"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/ic_photo" />
<EditText
android:id="#+id/editText_Site"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:inputType="text"
android:text="not yet reconized" />
</TableRow>
</TableLayout>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end" >
<TableRow
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageButton
android:id="#+id/imageButton6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/ic_send" />
<ImageButton
android:id="#+id/imageButton7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/ic_save" />
</TableRow>
</TableLayout>
</TableRow>
</TableLayout>
</RelativeLayout>
package com.google.codelab.mlkit;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private static final String TAG = "MainActivity";
private ImageButton imageButton_Site;
private EditText editText_Site;
private Spinner spinner_Site;
private InputImage createdImage;
String recognizedText = "";
String currentPhotoPath;
static final int REQUEST_IMAGE_CAPTURE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageButton_Site = findViewById(R.id.imageButton_Site);
imageButton_Site.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
spinner_Site = findViewById(R.id.spinner_Site);
String[] items = new String[]{"Chicago", "New York"}; // has to be retrieved from server based on GPS (satellite)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, items);
spinner_Site.setAdapter(adapter);
spinner_Site.setOnItemSelectedListener(this);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(getApplicationContext(), "Error occurred while creating the File!",Toast.LENGTH_LONG).show();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".fileprovider",
photoFile);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
takePictureIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
takePictureIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // new
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult( requestCode, resultCode, data);
// Log.d("OLR", "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bitmap bitmap=BitmapFactory.decodeFile(currentPhotoPath);
Bitmap imagebitmap=Bitmap.createBitmap(bitmap);//Just add this line and everything will work fine.I tried this code, its working like a charm.
int check = bitmap.getWidth();
InputImage inputImage = InputImage.fromBitmap(imagebitmap, 0);
String text = recognizeTextFromImage(inputImage);
if (text.isEmpty())
{
Toast.makeText(getApplicationContext(), "Nothing recognized. Please try again!",Toast.LENGTH_LONG).show();
editText_Site.setText("Failed !");
}
else {
editText_Site.setText(text);
}
}
else {
Toast.makeText(getApplicationContext(), "An issue occurred. Please inform app owner!",Toast.LENGTH_LONG).show();
}
}
private File createImageFile() throws IOException {
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// create directory if necessary
if (!storageDir.exists()){
storageDir.mkdir();
}
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.GERMANY).format(new Date());
String imageFileName = "OLR_" + timeStamp + "_";
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// imageFile = image;
currentPhotoPath = image.getAbsolutePath();
return image;
}
private String recognizeTextFromImage(InputImage image) {
TextRecognizer recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
Task<Text> task = recognizer.process(image);
// recognizer.process(image)
task
.addOnSuccessListener(
new OnSuccessListener<Text>() {
#Override
public void onSuccess(Text texts) {
recognizedText = processTextRecognitionResult(texts);
Log.d(TAG,"Successful");
}
})
/*.addOnSuccessListener(
new OnSuccessListener<Text>() {
#Override
public void onSuccess(Text texts) {
recognizedText = texts.getText();
editText_Site.setText(recognizedText);
Log.d(TAG,"Successful");
}
})*/
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
Log.d(TAG,"Not Successful");
}
});
recognizer.close();
return recognizedText;
}
private String processTextRecognitionResult(Text texts) {
String recognizedText = "";
List<Text.TextBlock> blocks = texts.getTextBlocks();
if (blocks.size() == 0) {
// No text found
}
else {
for (int i = 0; i < blocks.size(); i++) {
List<Text.Line> lines = blocks.get(i).getLines();
for (int j = 0; j < lines.size(); j++) {
List<Text.Element> elements = lines.get(j).getElements();
for (int k = 0; k < elements.size(); k++) {
String elementText = elements.get(k).getText();
recognizedText = recognizedText + elementText;
}
}
}
}
return recognizedText;
}
private void showToast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
spinner_Site = findViewById(R.id.spinner_Site);
editText_Site = findViewById(R.id.editText_Site);
editText_Site.setText(spinner_Site.getSelectedItem().toString());
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
}
Problem solved
(1) I had to add intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
(2) I checked the the returned string "recognizedText" which was always empty, because the thread executed after the variable was filled. Ashes on my head. My thanks go to #Danish who gave me the decisive hint to add logs to the right place.
(3) For any reason I had to wait sometime before starting debugging.
Worked for hours on this and Alhamdulillah I came out with the solution.
#Micky I found bugs in your code.So to help you out I am providing you with solution below. Basically,the bug is related to rotation if the image is not captured in landscape mode the ocr did not recognized the text properly so its necessary to make sure that the image is rotated properly before scanning.There is also the problem in this line recognizedText = processTextRecognitionResult(texts); it doesnt recognize the text properly you can check below I have added one more edittext to show you the difference on how the text send by texts.getText() gives you better result.
Check the code below:
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.text.Text;
import com.google.mlkit.vision.text.TextRecognition;
import com.google.mlkit.vision.text.TextRecognizer;
import com.google.mlkit.vision.text.latin.TextRecognizerOptions;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private static final String TAG = "MainActivity";
private ImageButton imageButton_Site;
private EditText editText_Site;
EditText editText;
private Spinner spinner_Site;
private InputImage createdImage;
String recognizedText="";
String currentPhotoPath;
static final int REQUEST_IMAGE_CAPTURE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText_Site=findViewById(R.id.editText_Site);
editText=findViewById(R.id.editText);
imageButton_Site = findViewById(R.id.imageButton_Site);
spinner_Site = findViewById(R.id.spinner_Site);
String[] items = new String[]{"Chicago", "Ludwigshafen"}; // has to be retrieved from server based on GPS (satellite)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, items);
spinner_Site.setAdapter(adapter);
spinner_Site.setOnItemSelectedListener(this);
imageButton_Site.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(getApplicationContext(), "Error occurred while creating the File!",Toast.LENGTH_LONG).show();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,BuildConfig.APPLICATION_ID+".fileprovider",
photoFile);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult( requestCode, resultCode, data);
// Log.d("OLR", "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
ParcelFileDescriptor parcelFileDescriptor = null;
try {
parcelFileDescriptor = getContentResolver().openFileDescriptor(Uri.fromFile(new File(currentPhotoPath)), "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
ExifInterface exifInterface = null;
try {
exifInterface = new ExifInterface(fileDescriptor);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
Matrix matrix = new Matrix();
matrix.setRotate(90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
Matrix matrixe = new Matrix();
matrixe.setRotate(180);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrixe, true);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
Matrix matrixes = new Matrix();
matrixes.setRotate(270);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrixes, true);
break;
case ExifInterface.ORIENTATION_NORMAL:
Matrix matrix12 = new Matrix();
matrix12.setRotate(ExifInterface.ORIENTATION_ROTATE_90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix12, true);
}
InputImage inputImage=null;
inputImage= InputImage.fromBitmap(bitmap,0);
String text=null;
try {
text = recognizeTextFromImage(inputImage);
} catch (IOException e) {
e.printStackTrace();
}
if (text.isEmpty())
{
Toast.makeText(getApplicationContext(), "Nothing recognized. Please try again!",Toast.LENGTH_LONG).show();
editText_Site.setText("Failed !");
}
else {
editText_Site.setText(text);
}
}
else {
Toast.makeText(getApplicationContext(), "An issue occurred. Please inform app owner!",Toast.LENGTH_LONG).show();
}
}
private File createImageFile() throws IOException {
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// create directory if necessary
if (!storageDir.exists()){
storageDir.mkdir();
}
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.GERMANY).format(new Date());
String imageFileName = "OLR_" + timeStamp + "_";
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// imageFile = image;
currentPhotoPath = image.getAbsolutePath();
return image;
}
private String recognizeTextFromImage(InputImage image) throws IOException {
TextRecognizer recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
Task<Text> task = recognizer.process(image)
.addOnSuccessListener(
new OnSuccessListener<Text>() {
#Override
public void onSuccess(Text texts) {
recognizedText = processTextRecognitionResult(texts);
editText.setText(texts.getText());
Log.d(TAG,"Successful");
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
Log.d(TAG,"Not Successful");
}
});
return recognizedText;
}
private String processTextRecognitionResult(Text texts) {
String recognizedText = "";
List<Text.TextBlock> blocks = texts.getTextBlocks();
if (blocks.size() == 0) {
// No text found
}
else {
for (int i = 0; i < blocks.size(); i++) {
List<Text.Line> lines = blocks.get(i).getLines();
for (int j = 0; j < lines.size(); j++) {
List<Text.Element> elements = lines.get(j).getElements();
for (int k = 0; k < elements.size(); k++) {
String elementText = elements.get(k).getText();
recognizedText = recognizedText + elementText;
}
}
}
}
return recognizedText;
}
private void showToast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
spinner_Site = findViewById(R.id.spinner_Site);
editText_Site.setText(spinner_Site.getSelectedItem().toString());
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
}

Unable to Resolve errors while adding file download code to webview app in android studio

Trying to make a web view app for a site. although everything works fine, unable to resolve few errors that are popping up while I add this "file download" code.
Here's the android code :
Activity Main:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="#+id/webview_sample"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
Main Activity.java
package com.appgrep.urstudymate;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private final static int FCR = 1;
WebView webView;
private String mCM;
private ValueCallback<Uri> mUM;
private ValueCallback<Uri[]> mUMA;
private ValueCallback<Uri> mUploadMessage;
private Uri mCapturedImageURI = null;
private ValueCallback<Uri[]> mFilePathCallback;
private String mCameraPhotoPath;
private static final int INPUT_FILE_REQUEST_CODE = 1;
private static final int FILECHOOSER_RESULTCODE = 1;
private static final String TAG = MainActivity.class.getSimpleName();
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
Uri[] results = null;
// Check that the response is a good one
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
// If there is not data, then we may have taken a photo
if (mCameraPhotoPath != null) {
results = new Uri[]{Uri.parse(mCameraPhotoPath)};
}
} else {
String dataString = data.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
}
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
if (requestCode != FILECHOOSER_RESULTCODE || mUploadMessage == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == this.mUploadMessage) {
return;
}
Uri result = null;
try {
if (resultCode != RESULT_OK) {
result = null;
} else {
// retrieve from the private variable if the intent is null
result = data == null ? mCapturedImageURI : data.getData();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "activity :" + e,
Toast.LENGTH_LONG).show();
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
return;
}
#SuppressLint({"SetJavaScriptEnabled", "WrongViewCast"})
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview_sample);
if (Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1);
}
assert webView != null;
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);
if (Build.VERSION.SDK_INT >= 21) {
webSettings.setMixedContentMode(0);
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT < 19) {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.setWebViewClient(new Callback());
webView.loadUrl("https://urstudymate.com/");
webView.setWebChromeClient(new WebChromeClient() {
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File imageFile = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
return imageFile;
}
public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> filePath, WebChromeClient.FileChooserParams fileChooserParams) {
// Double check that we don't have any existing callbacks
if (mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePath;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(TAG, "Unable to create Image File", ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
} else {
takePictureIntent = null;
}
}
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("image/*");
Intent[] intentArray;
if (takePictureIntent != null) {
intentArray = new Intent[]{takePictureIntent};
} else {
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
return true;
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
// Create AndroidExampleFolder at sdcard
// Create AndroidExampleFolder at sdcard
File imageStorageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)
, "AndroidExampleFolder");
if (!imageStorageDir.exists()) {
// Create AndroidExampleFolder at sdcard
imageStorageDir.mkdirs();
}
// Create camera captured image file path and name
File file = new File(
imageStorageDir + File.separator + "IMG_"
+ String.valueOf(System.currentTimeMillis())
+ ".jpg");
mCapturedImageURI = Uri.fromFile(file);
// Camera capture image intent
final Intent captureIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
// Create file chooser intent
Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
// Set camera intent to file chooser
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS
, new Parcelable[] { captureIntent });
// On select image call onActivityResult method of activity
startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType,
String capture) {
openFileChooser(uploadMsg, acceptType);
}
});
}
webView.setDownloadListener(new DownloadListener(){
#Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
DownloadManager.Request myRequest = new DownloadManager.Request(Uri.parse(url));
myRequest.allowScanningByMediaScanner();
myRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
DownloadManager myManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
myManager.enqueue(myRequest);
Toast.makeText(getApplicationContext(), "File is Downloading...", Toast.LENGTH_SHORT).show();
}
});
public class Callback extends WebViewClient {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(getApplicationContext(), "Failed loading app!", Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater myMenuInflater = getMenuInflater();
myMenuInflater.inflate(R.menu.super_menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.myMenuOne:
onBackPressed();
break;
case R.id.myMenuTwo:
GoForward();
break;
}
return true;
}
private void GoForward() {
if (webView.canGoForward()) {
webView.goForward();
} else {
Toast.makeText(this, "Can't go further!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onBackPressed() {
if (webView.canGoBack()) {
webView.goBack();
}
}
}
Super Menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context="com.filechooser.file.MainActivity">
<item android:id="#+id/myMenuOne" android:icon="#drawable/ic_arrow_back_black_24dp" android:title="Item" app:showAsAction="always" />
<item android:id="#+id/myMenuTwo" android:icon="#drawable/ic_arrow_back_black_24dp" android:title="Item" app:showAsAction="always" />
</menu>
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.appgrep.urstudymate">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="#style/AppTheme"
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
However the piece of code I added is :
webView.setDownloadListener(new DownloadListener(){
#Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
DownloadManager.Request myRequest = new DownloadManager.Request(Uri.parse(url));
myRequest.allowScanningByMediaScanner();
myRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
DownloadManager myManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
myManager.enqueue(myRequest);
Toast.makeText(getApplicationContext(), "File is Downloading...", Toast.LENGTH_SHORT).show();
}
});
(which i added already for which I got error at "setDownloadListener", "DownloadListener", "DownloadManager" and so on. almost all words in that piece.)
SCREENSHOT :
Any help is greatly appreciated.

Android java crash screen recording

I have the following code that allows you to record what happens on the screen.
It works, but there are some problems and unforeseen events that happen and I do not understand which set of situations allow that app to crash.
To make one of the problems happen, the steps are as follows:
Press the start button
Start recording
Press the stop button
Wait a few moments
Press the start button again
Error:
E/MediaRecorder: SurfaceMediaSource could not be initialized!
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app, PID: 4465
java.lang.IllegalStateException: failed to get surface
at android.media.MediaRecorder.getSurface(Native Method)
at com.app.MainActivity2.getVirtualDisplay(MainActivity2.java:170)
at com.app.MainActivity2.startRecording(MainActivity2.java:71)
at com.app.MainActivity2.access$100(MainActivity2.java:23)
at com.app.MainActivity2$1.onClick(MainActivity2.java:47)....
Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Code:
package com.app;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity2 extends AppCompatActivity {
private static final int CAST_PERMISSION_CODE = 22;
private DisplayMetrics mDisplayMetrics;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private MediaRecorder mMediaRecorder;
private MediaProjectionManager mProjectionManager;
private boolean startRec = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mDisplayMetrics = new DisplayMetrics();
mMediaRecorder = new MediaRecorder();
mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
Button start = (Button) findViewById(R.id.start);
start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!startRec) startRecording();
}
});
Button stop = (Button) findViewById(R.id.stop);
stop.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (startRec) stopRecording();
}
});
}
private void startRecording() {
startRec = true;
// If mMediaProjection is null that means we didn't get a context, lets ask the user
Log.w("class:", "startRecording:start");
if (mMediaProjection == null) {
// This asks for user permissions to capture the screen
Log.w("class:", "startRecording:startResult");
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), CAST_PERMISSION_CODE);
Log.w("class:", "startRecording:endResult");
return;
}
Log.w("class:", "startRecording:end");
mVirtualDisplay = getVirtualDisplay();
mMediaRecorder.start();
}
private void stopRecording() {
startRec = false;
Log.w("class:", "stopRecording:start");
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.reset();
//mMediaRecorder = null;
}
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
//mVirtualDisplay = null;
}
if (mMediaProjection != null) {
mMediaProjection.stop();
//mMediaProjection = null;
}
Log.w("class:", "stopRecording:end");
}
public String getCurSysDate() {
return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
}
private void prepareRecording(String name) {
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
Toast.makeText(this, "Failed to get External Storage", Toast.LENGTH_SHORT).show();
return;
}
final String directory = Environment.getExternalStorageDirectory() + File.separator + "Recordings";
final File folder = new File(directory);
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
if (!success) {
Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
return;
}
String videoName = (name + "_" + getCurSysDate() + ".mp4");
String filePath = directory + File.separator + videoName;
int width = mDisplayMetrics.widthPixels;
int height = mDisplayMetrics.heightPixels;
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncodingBitRate(8000 * 1000);
mMediaRecorder.setVideoFrameRate(24);
mMediaRecorder.setVideoSize(width, height);
mMediaRecorder.setOutputFile(filePath);
try {
mMediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != CAST_PERMISSION_CODE) {
// Where did we get this request from ? -_-
Log.w("class:", "Unknown request code: " + requestCode);
return;
}
Log.w("class:", "onActivityResult:resultCode");
if (resultCode != RESULT_OK) {
startRec = false;
Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
return;
}
prepareRecording("start");
mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
Log.w("class:", "onActivityResult:mMediaProjection");
// TODO Register a callback that will listen onStop and release & prepare the recorder for next recording
// mMediaProjection.registerCallback(callback, null);
mVirtualDisplay = getVirtualDisplay();
mMediaRecorder.start();
}
private VirtualDisplay getVirtualDisplay() {
int screenDensity = mDisplayMetrics.densityDpi;
int width = mDisplayMetrics.widthPixels;
int height = mDisplayMetrics.heightPixels;
return mMediaProjection.createVirtualDisplay(this.getClass().getSimpleName(),
width, height, screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
}
}
Xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="#+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop" />
</LinearLayout>

Download file in Android using ProgressbarDialog

I am trying to develop a simple application for download using DownloadManager but I need to do some changes, I want to download using ProgressbarDialog so how to do.
class DownloadReceiver
if(downloader == null) return;
long completeId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
if(completeId == downloadTaskId){
Query query = new Query();
query.setFilterById(downloadTaskId);
Cursor cur = downloader.query(query);
if (cur.moveToFirst()) {
int columnIndex = cur.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == cur.getInt(columnIndex)) {
//Download the task has been completed, remove
new VersionPersistent(context).clear();
String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
File apkFile = new File(Uri.parse(uriString).getPath());
Intent installIntent = new Intent();
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setAction(Intent.ACTION_VIEW);
installIntent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
context.startActivity(installIntent);
} else {
Toast.makeText(context, R.string.download_failure, Toast.LENGTH_SHORT).show();
}
}
cur.close();
and also
download and install
if ( latestVersion == null || !isNetworkActive() ) return;
downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Query query = new Query();
query.setFilterById(downloadTaskId);
Cursor cur = downloader.query(query);
// Download tasks already exists
if(cur.moveToNext()) return;
DownloadManager.Request task = new DownloadManager.Request(Uri.parse(latestVersion.targetUrl));
String apkName = extractName(latestVersion.targetUrl);
String title = String.format("%s - v%s", apkName,latestVersion.name);
task.setTitle(title);
task.setDescription(latestVersion.feature);
task.setVisibleInDownloadsUi(true);
task.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
task.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);
downloadTaskId = downloader.enqueue(task);
Thanks :)
USE this class to show progress bar , this will give you an idea for downloading an image.
DownloadImageTask.java
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** Reference to the view which should receive the image */
private final WeakReference imageRef;
public DownloadImageTask(ImageView imageView) {
imageRef = new WeakReference(imageView);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(DownloadImageActivity.this, "Wait", "Downloading...");
}
#Override
protected Bitmap doInBackground(String... params) {
InputStream input = null;
try {
URL url = new URL(params[0]);
// We open the connection
URLConnection conection = url.openConnection();
conection.connect();
input = new BufferedInputStream(url.openStream(), 8192);
// we convert the inputStream into bitmap
bitmap = BitmapFactory.decodeStream(input);
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return bitmap;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(Bitmap bitmap) {
progressDialog.dismiss();
if (isCancelled()) {
bitmap = null;
}
if (imageRef != null) {
ImageView imageView = imageRef.get();
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
} else
Toast.makeText(DownloadImageActivity.this, "Error while downloading the image!", Toast.LENGTH_LONG).show();
}
}
}
give permission in AndroidMenifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
you want using progressDialog, does that mean you don't need to download in the background ?
My solution is:
using AsyncTask
init the profressDialog before you call task.execute()
then show the dialog in onPreExecute
download file doInBackfround
update progess in onProgressUpdate
and dosomething you want when download complete in onPostExecute
you can learn AsyncTask and HttpURLConnection and IO Stream
You should use DownloadManager's
DownloadManager.query(DownloadManager.Query)
This gives you a Cursor to browse the columns COLUMN_TOTAL_SIZE_BYTES (Total size of the download in bytes) and COLUMN_BYTES_DOWNLOADED_SO_FAR (Number of bytes download so far).
With this information, you'll have the details to update the ProgressBarDialog.
Use Asynctask for this. Try this.
private class DownloadFileTask extends AsyncTask<String, Void, String> {
ProgressDialog pd;
#Override
protected String doInBackground(String... params) {
// Your File Download Code here
}
#Override
protected void onPostExecute(String result) {
pd.dismiss();
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(yourActivity.this);
pd.setMessage("Please Wait...");
pd.show();
}
#Override
protected void onProgressUpdate(Void... values) {}
}
}
This is my working sample code. I use SeekBar instead of ProgressBar. Hope this help
Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.downloadmanager" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
<SeekBar
android:id="#+id/seekBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<LinearLayout
style="?android:buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="horizontal">
<Button
android:id="#+id/buttonStartDownload"
style="?android:buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="startDownload"
android:text="Start" />
<Button
android:id="#+id/buttonCancelDownload"
style="?android:buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="cancelDownload"
android:text="Cancel" />
<Button
android:id="#+id/buttonViewDownloads"
style="?android:buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="viewDownloads"
android:text="View" />
</LinearLayout>
</RelativeLayout>
MainActivity.java:
package com.example.downloadmanager;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
public class MainActivity extends AppCompatActivity {
private DownloadManager mDownloadManager;
private long mDownloadReference;
private TextView mTextView;
private SeekBar mSeekBar;
private static Cursor mCursor;
private static boolean mDownloading = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mSeekBar = (SeekBar) findViewById(R.id.seekBar);
// Set filter to only when download is complete and register broadcast receiver
IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, filter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
// noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void startDownload(View view) {
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Uri Download_Uri = Uri.parse("http://192.168.0.100/files/test.txt");
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
// Restrict the types of networks over which this download may proceed.
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
// Set whether this download may proceed over a roaming connection.
request.setAllowedOverRoaming(false);
// Set the title of this download, to be displayed in notifications (if enabled).
request.setTitle("My Download");
// Set a description of this download, to be displayed in notifications (if enabled)
request.setDescription("Android Data download using DownloadManager...");
// Set the local destination for the downloaded file to a path within the application's external files directory
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "test.txt");
// Enqueue a new download and same the referenceId
mDownloadReference = mDownloadManager.enqueue(request);
new Thread(new Runnable() {
#Override
public void run() {
mDownloading = true;
while (mDownloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(mDownloadReference);
mCursor = mDownloadManager.query(q);
if (mCursor != null && mCursor.getCount() > 0) {
mCursor.moveToFirst();
int bytes_downloaded = mCursor.getInt(mCursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = mCursor.getInt(mCursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (mCursor.getInt(mCursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
mDownloading = false;
}
final double dl_progress = ((bytes_downloaded * 100) / bytes_total);
runOnUiThread(new Runnable() {
#Override
public void run() {
mSeekBar.setProgress((int) dl_progress);
}
});
}
if (mCursor != null) {
mCursor.close();
}
}
}
}).start();
}
public void cancelDownload(View view) {
mDownloading = false;
if (mDownloadManager != null) {
mDownloadManager.remove(mDownloadReference);
}
mSeekBar.setProgress(0);
}
public void viewDownloads(View view) {
Intent i = new Intent();
i.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
startActivity(i);
}
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (mDownloadReference == referenceId) {
Uri uri = mDownloadManager.getUriForDownloadedFile(mDownloadReference);
if (uri != null) {
String mimeType = mDownloadManager.getMimeTypeForDownloadedFile(mDownloadReference);
File file = new File(uri.getPath());
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("FileName", file.getName());
jsonObject.put("FilePath", file.getAbsolutePath());
jsonObject.put("FileSize", file.length());
jsonObject.put("MimeType", mimeType);
String msg = "Download completed! \n\n" + jsonObject.toString(5);
mTextView.setText(msg);
} catch (JSONException e) {
mTextView.setText(e.getMessage());
}
}
}
}
};
}

Unfortunately <app-name> has stopped

I have written a code for an app that is supposed to be for a Virtual Campus tour. I have shared below the various files (3 class files) and 3 xml files and all have no errors in them.
The app has installed on the emulator successfully but throws up the error mentioned in the heading.
I am very new to android and to java so any help will be really appreciated!
Can anyone spot where I have gone wrong?
Code for one class by the name BuildingEdit
package com.example.udbuildingtour;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class BuildingEdit extends Activity {
private EditText mNameText;
private EditText mLatText;
private EditText mLongiText;
private Long mRowId;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.building_edit);
setTitle(R.string.edit_building);
mNameText = (EditText) findViewById(R.id.name);
mLatText = (EditText) findViewById(R.id.lat);
mLongiText = (EditText) findViewById(R.id.longi);
Button confirmButton = (Button) findViewById(R.id.confirm);
mRowId = null;
Bundle extras = getIntent().getExtras();
if (extras != null) {
String name = extras.getString(BuildingsDbAdapter.KEY_BUILDINGNAME);
String lat = extras.getString(BuildingsDbAdapter.KEY_LAT);
String longi = extras.getString(BuildingsDbAdapter.KEY_LONGI);
mRowId = extras.getLong(BuildingsDbAdapter.KEY_ID);
if (name != null) {
mNameText.setText(name);
}
if (lat != null) {
mLatText.setText(lat);
}
if (longi != null) {
mLongiText.setText(longi);
}
}
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Bundle bundle = new Bundle();
bundle.putString(BuildingsDbAdapter.KEY_BUILDINGNAME, mNameText.getText().toString());
bundle.putString(BuildingsDbAdapter.KEY_LAT, mLatText.getText().toString());
bundle.putString(BuildingsDbAdapter.KEY_LONGI, mLongiText.getText().toString());
if (mRowId != null) {
bundle.putLong(BuildingsDbAdapter.KEY_ID, mRowId);
}
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
}
});
}
}
Code for class UDBuildingTour
package com.example.udbuildingtour;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.SimpleCursorAdapter;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
public class UDBuildingTour extends ListActivity {
private static final int ACTIVITY_CREATE=0;
private static final int ACTIVITY_EDIT=1;
private static final int INSERT_ID = Menu.FIRST;
private static final int DELETE_ID = Menu.FIRST + 1;
private BuildingsDbAdapter mDbHelper;
private Cursor mBuildingsCursor;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.building_edit);
mDbHelper = new BuildingsDbAdapter(this);
mDbHelper.open();
fillData();
registerForContextMenu(getListView());
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()) {
case INSERT_ID:
createBuilding();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
mDbHelper.deleteBuilding(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
private void createBuilding() {
Intent i = new Intent(this, BuildingEdit.class);
startActivityForResult(i, ACTIVITY_CREATE);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Cursor c = mBuildingsCursor;
c.moveToPosition(position);
Intent i = new Intent(this, BuildingEdit.class);
i.putExtra(BuildingsDbAdapter.KEY_ID, id);
i.putExtra(BuildingsDbAdapter.KEY_BUILDINGNAME, c.getString(
c.getColumnIndexOrThrow(BuildingsDbAdapter.KEY_BUILDINGNAME)));
i.putExtra(BuildingsDbAdapter.KEY_LAT, c.getString(
c.getColumnIndexOrThrow(BuildingsDbAdapter.KEY_LAT)));
i.putExtra(BuildingsDbAdapter.KEY_LONGI, c.getString(
c.getColumnIndexOrThrow(BuildingsDbAdapter.KEY_LONGI)));
startActivityForResult(i, ACTIVITY_EDIT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Bundle extras = intent.getExtras();
switch(requestCode) {
case ACTIVITY_CREATE:
Long rowId = extras.getLong(BuildingsDbAdapter.KEY_ID);
String name = extras.getString(BuildingsDbAdapter.KEY_BUILDINGNAME);
String lat = extras.getString(BuildingsDbAdapter.KEY_LAT);
String longi = extras.getString(BuildingsDbAdapter.KEY_LONGI);
mDbHelper.createBuilding(rowId, name, lat, longi);
fillData();
break;
case ACTIVITY_EDIT:
Long Id = extras.getLong(BuildingsDbAdapter.KEY_ID);
if (Id != null) {
String editName = extras.getString(BuildingsDbAdapter.KEY_BUILDINGNAME);
String editLat = extras.getString(BuildingsDbAdapter.KEY_LAT);
String editLongi = extras.getString(BuildingsDbAdapter.KEY_LONGI);
mDbHelper.updateBuilding(Id, editName, editLat, editLongi);
}
fillData();
break;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.udbuilding_tour, menu);
return true;
}
private void fillData() {
// TODO Auto-generated method stub
// Get all of the rows from the database and create the item list
mBuildingsCursor = mDbHelper.fetchAllBuildings();
startManagingCursor(mBuildingsCursor);
// Create an array to specify the fields we want to display in the list (only BUILDINGNAME)
String[] from = new String[]{BuildingsDbAdapter.KEY_BUILDINGNAME};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{R.id.text1};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter building =
new SimpleCursorAdapter(this, R.layout.buildings_row, mBuildingsCursor, from, to);
setListAdapter(building);
}
}
Code for BuildingsDBAdapter
package com.example.udbuildingtour;
import java.io.BufferedReader;
import java.io.FileReader;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class BuildingsDbAdapter {
public static final String KEY_ID = "_id";
public static final String KEY_BUILDINGNAME = "name";
public static final String KEY_LAT = "lat";
public static final String KEY_LONGI = "longi";
private static final String TAG = "BuildingsDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
/**
* Database creation sql statement
*/
private static final String DATABASE_CREATE =
"create table buildings (_id integer primary key autoincrement, "
+ "title text not null, body text not null);";
private static final String DATABASE_NAME = "Buildings";
private static final String DATABASE_TABLE = "UDBuildings";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* #param ctx the Context within which to work
*/
public BuildingsDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public BuildingsDbAdapter open() throws SQLException {
// TODO Auto-generated method stub
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
public boolean deleteBuilding(long id) {
// TODO Auto-generated method stub
return mDb.delete(DATABASE_TABLE, KEY_ID + "=" + id, null) > 0;
}
public long createBuilding(Long id, String name, String lat, String longi) {
// TODO Auto-generated method stub
ContentValues initialValues = new ContentValues();
try{
BufferedReader in = new BufferedReader(new FileReader("UDBuildings.txt"));
String s;
while((s = in.readLine()) != null){
String[] var = s.split(":");
//var[0]=ID,var[1]=Name etc etc
initialValues.put(KEY_BUILDINGNAME, var[1]);
initialValues.put(KEY_LAT, var[2]);
initialValues.put(KEY_LONGI, var[3]);
initialValues.put(KEY_ID, var[0]);
}
}catch(Exception e){
e.printStackTrace();
}
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
/**
* Return a Cursor over the list of all buildings in the database
*
* #return Cursor over all buildings
*/
public Cursor fetchAllBuildings() {
return mDb.query(DATABASE_TABLE, new String[] {KEY_ID, KEY_BUILDINGNAME,
KEY_LAT, KEY_LONGI}, null, null, null, null, null);
}
/**
* Return a Cursor positioned at the building that matches the given building id
*
* #param id of building to retrieve
* #return Cursor positioned to matching building, if found
* #throws SQLException if building could not be found/retrieved
*/
public Cursor fetchBuilding(long id) throws SQLException {
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] {KEY_ID,
KEY_BUILDINGNAME, KEY_LAT, KEY_LONGI}, KEY_ID + "=" + id, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
/**
* Update the building using the details provided. The building to be updated is
* specified using the id, and it is altered to use the name and lat, longi
* values passed in
*
* #param id of building to update
* #param name value to set building name to
* #param lat value to set building lat to
* #param longi value to set building longi to
* #return true if the building was successfully updated, false otherwise
*/
public boolean updateBuilding(Long rowId, String editName, String editLat, String editLongi) {
// TODO Auto-generated method stub
ContentValues args = new ContentValues();
args.put(KEY_BUILDINGNAME, editName);
args.put(KEY_LAT, editLat);
args.put(KEY_LONGI, editLongi);
return mDb.update(DATABASE_TABLE, args, KEY_ID + "=" + rowId, null) > 0;
}
}
xml code for building_edit
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="name" />
<EditText android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="lat" />
<EditText android:id="#+id/lat" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="vertical" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="longi" />
<EditText android:id="#+id/longi" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="vertical" />
<Button android:id="#+id/confirm"
android:text="confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
xml code for buildings_row
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="#+id/text1" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
xml code for buildings_list
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ListView android:id="#+id/android:list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="#+id/android:empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="no_buildings"/>
</LinearLayout>
androidmanifest.xml file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.udbuildingtour"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.udbuildingtour.UDBuildingTour"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".BuildingEdit"></activity>
</application>
</manifest>
android:id="#android:id/list"
and not this...
android:id="#+id/android:list"
in your ListView
I see two problems:
The UDBuildingTour activity is not using buildings_list as the content view. As a result, there is no ListView and the base ListActivity will throw an exception when you call setListAdapter(building); in fill_data. In onCreate(), you should change this:
setContentView(R.layout.building_edit);
to:
setContentView(R.layout.building_list);
As #stir-fried points out, the android:id attribute for the ListView in buildings_list should be #android:id/list, not #+id/android:list (which I'm surprised compiles). For a custom list activity layout, you need to use the predefined Android id for the ListView, not autogenerating your own id. Similarly, the empty-list view should have android:id=#android:id/empty, not #+id/android:empty.

Categories

Resources