So I've got a simple Android App that can upload a file to an AWS S3 bucket, I'm looking to see how I can go about storing the filename in the object URL using metadata support from AWS.
How would I got about doing so?
Below is my MainActivity.java file:
package com.example.s3imagetest;
import java.net.URL;
import java.util.Date;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
public class MainActivity extends Activity {
private AmazonS3Client s3Client = new AmazonS3Client(
new BasicAWSCredentials(Constants.ACCESS_KEY_ID,
Constants.SECRET_KEY));
private Button selectPhoto = null;
private Button showInBrowser = null;
private static final int PHOTO_SELECTED = 1;
/** Called when the activity is first created. */
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("OnCreate", "OnCreate Was Called");
s3Client.setRegion(Region.getRegion(Regions.EU_WEST_1));
setContentView(R.layout.activity_main);
selectPhoto = (Button) findViewById(R.id.button1);
selectPhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Start the image picker.
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, PHOTO_SELECTED);
}
});
showInBrowser = (Button) findViewById(R.id.button2);
showInBrowser.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new S3GeneratePresignedUrlTask().execute();
}
});
}
// This method is automatically called by the image picker when an image is
// selected.
protected void onActivityResult(int requestCode, int resultCode,
Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch (requestCode) {
case PHOTO_SELECTED:
if(resultCode == RESULT_OK) {
Uri selectedImage = imageReturnedIntent.getData();
new S3PutObjectTask().execute(selectedImage);
}
}
}
// Display an Alert message for error or failure
protected void displayAlert(String title, String message) {
AlertDialog.Builder confirm = new AlertDialog.Builder(this);
confirm.setTitle(title);
confirm.setMessage(message);
confirm.setNegativeButton(MainActivity.this.getString(R.string.ok),
new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
confirm.show().show();
}
protected void displayErrorAlert(String title, String message) {
AlertDialog.Builder confirm = new AlertDialog.Builder(this);
confirm.setTitle(title);
confirm.setMessage(message);
confirm.setNegativeButton(MainActivity.this.getString(R.string.ok),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
MainActivity.this.finish();
}
});
confirm.show().show();
}
private class S3PutObjectTask extends AsyncTask<Uri, Void, S3TaskResult> {
ProgressDialog dialog;
protected void onPreExecute() {
Log.v("S3PutObjectTask", "Its Beginning ");
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage(MainActivity.this.getString(R.string.uploading));
dialog.setCancelable(false);
dialog.show();
Log.v("S3PutObjectTask", "onPreExecute Done");
}
protected S3TaskResult doInBackground(Uri... uris) {
Log.v("S3TaskResult", "Uri" + uris);
if (uris == null || uris.length != 1) {
return null;
}
// The file location of the image selected.
Uri selectedImage = uris[0];
ContentResolver resolver = getContentResolver();
String fileSizeColumn[] = { OpenableColumns.SIZE };
Cursor cursor = resolver.query(selectedImage, fileSizeColumn, null,
null, null);
cursor.moveToFirst();
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
String size = null;
if (!cursor.isNull(sizeIndex)) {
size = cursor.getString(sizeIndex);
}
cursor.close();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(resolver.getType(selectedImage));
if (size != null) {
metadata.setContentLength(Long.parseLong(size));
}
S3TaskResult result = new S3TaskResult();
// Put the image data into S3.
try {
Log.v("PutData into S3", "Data has bee sent");
//s3Client.createBucket(Constants.getPictureBucket());
PutObjectRequest por = new PutObjectRequest(
Constants.PICTURE_BUCKET, Constants.PICTURE_NAME,
resolver.openInputStream(selectedImage), metadata);
Log.v("PubtObjectRequest", "Selected Image");
s3Client.putObject(por);
Log.v("S3Client.putOb", "por");
Toast.makeText(getApplicationContext(), "Photo Upload Success", Toast.LENGTH_LONG).show();
} catch (Exception exception) {
result.setErrorMessage(exception.getMessage());
}
return result;
}
protected void onPostExecute(S3TaskResult result) {
dialog.dismiss();
if (result.getErrorMessage() != null) {
displayErrorAlert(
MainActivity.this
.getString(R.string.upload_failure_title),
result.getErrorMessage());
}
}
}
private class S3GeneratePresignedUrlTask extends
AsyncTask<Void, Void, S3TaskResult> {
protected S3TaskResult doInBackground(Void... voids) {
S3TaskResult result = new S3TaskResult();
try {
// Ensure that the image will be treated as such.
Log.v("S3GeneratePresignedUrlTask", "S3TaskResult");
ResponseHeaderOverrides override = new ResponseHeaderOverrides();
override.setContentType("image/jpeg");
// Generate the pre-signed URL.
// Added an hour's worth of milliseconds to the current time.
Date expirationDate = new Date(
System.currentTimeMillis() + 3600000);
GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(
Constants.PICTURE_BUCKET, Constants.PICTURE_NAME);
urlRequest.setExpiration(expirationDate);
urlRequest.setResponseHeaders(override);
URL url = s3Client.generatePresignedUrl(urlRequest);
result.setUri(Uri.parse(url.toURI().toString()));
} catch (Exception exception) {
result.setErrorMessage(exception.getMessage());
}
return result;
}
protected void onPostExecute(S3TaskResult result) {
if (result.getErrorMessage() != null) {
displayErrorAlert(
MainActivity.this
.getString(R.string.browser_failure_title),
result.getErrorMessage());
} else if (result.getUri() != null) {
// Display in Browser.
startActivity(new Intent(Intent.ACTION_VIEW, result.getUri()));
}
}
}
private class S3TaskResult {
String errorMessage = null;
Uri uri = null;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public Uri getUri() {
return uri;
}
public void setUri(Uri uri) {
this.uri = uri;
}
}
}
From
http://docs.aws.amazon.com/AWSAndroidSDK/latest/javadoc/
setUserMetadata(Map) seems like it might be what you are looking for, although I don't think this is the best way to approach this problem.
Sets the
custom user-metadata for the associated object.
Amazon S3 can store additional metadata on objects by internally
representing it as HTTP headers prefixed with "x-amz-meta-". Use
user-metadata to store arbitrary metadata alongside their data in
Amazon S3. When setting user metadata, callers should not include the
internal "x-amz-meta-" prefix; this library will handle that for them.
Likewise, when callers retrieve custom user-metadata, they will not
see the "x-amz-meta-" header prefix.
User-metadata keys are case insensitive and will be returned as
lowercase strings, even if they were originally specified with
uppercase strings.
Note that user-metadata for an object is limited by the HTTP request
header limit. All HTTP headers included in a request (including user
metadata headers and other standard HTTP headers) must be less than
8KB.
From your description, it sounds like this is an app where users can upload photos and view them from a browser as well as the phone. However, you want it so that when the user deletes a photo from the browser, the corresponding local copy will also be deleted on the phone.
I think you could probably accomplish this with the setUserMetadata method, by passing up metadata that describes the path. However, this would be very cumbersome because the metadata is only lower case, and unfortunately the path and file names are not guaranteed to be(I think?). So, you'd need your own way of mapping lower case strings to upper and lower case strings, which adds a lot of unnecessary complexity.
I feel like it would be better if you set up a database to hold the mappings from S3 file names to their respective local paths. You could do this either on the Android device, which would be much easier but could exhibit weird behavior if the user tries the data. You could also do this on your own back end, which probably makes more sense if you are going to be sending out push notifications to your users to handle deletion anyway, since you could just push the path to them.
An even bigger potential issue is that you have to differentiate between devices, although you could solve that by just keeping a unique id associated with each device in your table. There's also the problem of what to do when the user decides to move the picture.
In any case, those things aren't really relevant to the question at hand. To answer your question, you COULD do this with the metadata but it would be ill advised since it adds a lot of complexity with seeming little upside. If you are looking for the simplest approach(handling all this client side) then I would probably suggest you try to use Cognito and DynamoDB to directly add a row to some DynamoDB table from your app. Make sure you specify the correct permissions to both allow you to do this and also to not allow any extra power to the user if you do take this approach.
Hope some of that helped!
Related
i am currently developping an application for my third year project, it's an android app (i used android studio) that will access a database that i created on my wamp server, the connection works perfectly from the application when i debug it on my android phone( i used in my code the "HttpURLConnection" with the url being my pc ip adress that i got from (cmd/ipconfig) ) .
The problem is that once i disconnect my phone from my pc and try to run the application from the phone, the connection with the database won't work, and also if i connect my pc to another modem, my pc ip changes, which is pretty much normal, but i don't think supposed to change the ip everytime the modem i connect to change ( although i'm not really sure, server connexions are clearly not something i'm an expert at ) , so i tried to use the ip of my pc on the internet that i got from "ipaddress.com" but it won't work, not even if i debug the application directly from android studio,
i don't have much time left to present the application , so i need a quick answer, thank you in advance
P.S : i guess i gotta mention that i need to acces the database to read AND write on it from the phone since it's an app that permits login/registration and will get the data that the user will enter and store it in the database .
I don't know wheter understanded, when you disconnect your phone from your pc, the app dead? or simplely it don't connect with db. Regard router, you need an account in "no-ip" and configure forguard's router on port 80 to redirect your computer's static IP. i need more details and information to help you. Regards
Try to connect the Phone and Mobile in same network.
your connection Url would be Like this 192.10.20.2 which is your ip or computer. as your get it form cmd using ipconfig command.
but whenever your networks changes your have to decompile to change the ip. or provide ip via textview.
take a Editview to take ip. and the concat it to your url. this will work. as it worked for me.
i'm working on an external server
The php code (for the connection to the db)
<?php
$db_name="pfe";
$mysql_username="root";
$mysql_password="";
$server_name="localhost";
$conn = mysqli_connect($server_name,$mysql_username,$mysql_password,$db_name);
?>
then i got another php file which handles the login part
<?php
require "connexion.php";
$user_email =$_POST["user-email"];
$user_pass =$_POST["password"];
$mysql_qry = "select id from donateur where email like '$user_email' and
password like '$user_pass'";
$result = mysqli_query($conn , $mysql_qry);
if(($row=mysqli_fetch_assoc($result))!=null){
$a = array('myarray' => array("donateur", $row["id"]));
echo json_encode($a);}
else {
$mysql_qry2 = "select id, username from association where email like
'$user_email' and password like '$user_pass'";
$result2 = mysqli_query($conn , $mysql_qry2);
if(($row=mysqli_fetch_assoc($result2))!=null) { $a = array('myarray' =>
array("association", $row["id"]));
echo json_encode($a);
}
else { echo "rien";}}
$conn->close();
the java code :
package applis.pfe;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static android.Manifest.permission.READ_CONTACTS;
public class LoginActivity extends AppCompatActivity implements
LoaderCallbacks<Cursor> {
/**
* Id to identity READ_CONTACTS permission request.
*/
private static final int REQUEST_READ_CONTACTS = 0;
DonateurDAO donateurdao= new DonateurDAO(this);
AssociationDAO associationdao=new AssociationDAO(this);
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
String ip="http://105.101.179.155/";
private UserLoginTask mAuthTask = null;
// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;
public static String qui;
public static int id;
public static String username;
SessionManager session;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
///////////////////// POUR AFFICHER LE MESSAGE DIINSCRIPTION REUSSIE /////////////////////////////////////
if(getIntent().getStringExtra("inscription")!=null &&
getIntent().getStringExtra("inscription").equals("oui"))
{ AlertDialog a= new AlertDialog.Builder(LoginActivity.this).create();
a.setTitle("Inscription réussie !");
a.setMessage("Votre inscription a été validé, veuillez vous connecter
pour pouvoir continuer");
a.show();}
session = new SessionManager(this);
// Set up the login form.
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
// populateAutoComplete();
mPasswordView = (EditText) findViewById(R.id.password);
mPasswordView.setOnEditorActionListener(new
TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int id, KeyEvent
keyEvent) {
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
});
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {attemptLogin();
}
});
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
ImageButton btn;
btn =(ImageButton)findViewById(R.id.InscriptionDonateurButton);
btn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {Intent in= new
Intent(LoginActivity.this,InscriptionDonateurActivity.class);
startActivity(in);
}
});
ImageButton btn1;
btn1 =(ImageButton)findViewById(R.id.InscriptionAssociationButton);
btn1.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {Intent in= new
Intent(LoginActivity.this,InscriptionAssociationActivity.class);
startActivity(in);
}
});
}
private void attemptLogin() {
if (mAuthTask != null) {
return;
}
// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);
// Store values at the time of the login attempt.
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password, if the user entered one.
if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid email address.
if (TextUtils.isEmpty(email)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!isEmailValid(email)) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);
mAuthTask = new UserLoginTask(email, password);
mAuthTask.execute((Void) null);
}
}
private boolean isEmailValid(String email) {
//TODO: Replace this with your own logic
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
}
private boolean isPasswordValid(String password) {
//TODO: Replace this with your own logic
return password.length() > 4;
}
/**
* Shows the progress UI and hides the login form.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(this,
// Retrieve data rows for the device user's 'profile' contact.
Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
// Select only email addresses.
ContactsContract.Contacts.Data.MIMETYPE +
" = ?", new String[]{ContactsContract.CommonDataKinds.Email
.CONTENT_ITEM_TYPE},
// Show primary email addresses first. Note that there won't be
// a primary email address if the user hasn't specified one.
ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
List<String> emails = new ArrayList<>();
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
emails.add(cursor.getString(ProfileQuery.ADDRESS));
cursor.moveToNext();
}
addEmailsToAutoComplete(emails);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
}
private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
//Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
ArrayAdapter<String> adapter =
new ArrayAdapter<>(LoginActivity.this,
android.R.layout.simple_dropdown_item_1line, emailAddressCollection);
mEmailView.setAdapter(adapter);
}
private interface ProfileQuery {
String[] PROJECTION = {
ContactsContract.CommonDataKinds.Email.ADDRESS,
ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
};
int ADDRESS = 0;
int IS_PRIMARY = 1;
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, String> {
private final String mEmail;
private final String mPassword;
UserLoginTask(String email, String password) {
mEmail = email;
mPassword = password;
}
#Override
protected String doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
String login_url= ip.concat("login.php");
try {
URL url= new URL(login_url);
HttpURLConnection httpURLConnection=(HttpURLConnection)url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
OutputStream outputStream= httpURLConnection.getOutputStream();
BufferedWriter bufferedWriter= new BufferedWriter(new OutputStreamWriter(outputStream,"UTF-8"));
String Post_data= URLEncoder.encode("user-email","UTF-8")+"="+URLEncoder.encode(mEmail,"UTF-8")+"&"
+URLEncoder.encode("password","UTF-8")+"="+URLEncoder.encode(mPassword,"UTF-8");
bufferedWriter.write(Post_data);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
InputStream inputStream=httpURLConnection.getInputStream();
qui=null;
id=0;
BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(inputStream,"iso-8859-1"));
String resultat="";
String ligne="";
while((ligne=bufferedReader.readLine())!=null)
resultat += ligne;
if (resultat.equals("rien")) return resultat; else {
JSONObject jsonObject = new JSONObject(resultat);
JSONArray json_data = jsonObject.getJSONArray("myarray");
qui=json_data.getString(0);
id=json_data.getInt(1);
username= json_data.getString(2);}
/* for(int i=0;i<json_data.length();i++)
{
k++;
qui= json_data.getString(1);
id= json_data.getInt(2);
//r.add(json_data.getString("categorie"));
}*/
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return resultat;
} catch (MalformedURLException e) {
e.printStackTrace();return e.toString();
} catch (IOException e) {
e.printStackTrace();return e.toString();
} catch (JSONException e) {
e.printStackTrace(); return e.toString();
}
}
/* for (String credential : DUMMY_CREDENTIALS) {
String[] pieces = credential.split(":");
if (pieces[0].equals(mEmail)) {
// Account exists, return true if the password matches.
return pieces[1].equals(mPassword);
}
}*/
// TODO: register the new account here.
#Override
protected void onPostExecute(String resultat) {
mAuthTask = null;
showProgress(false);
/////////////////////////////////////////////////////////////////////////////////
Intent i;
AlertDialog a;
if (resultat.equals("rien")){i= new Intent(LoginActivity.this,LoginActivity.class);
a= new AlertDialog.Builder(LoginActivity.this).create();
a.setTitle("Erreur");
a.setMessage(" Email et/ou mot de passe erroné(s)");
a.show();} else {
try {
session.createLoginSession(mEmail,username,qui,id);
session.checkLogin();
if (qui.equals("donateur")) {
i = new Intent(LoginActivity.this, Suite_Inscription_Donateur.class);
i.putExtra("id", id);
startActivity(i);
} else if (qui.equals("association")) {
session.createLoginSession(mEmail,username,qui,id);
i = new Intent(LoginActivity.this, Suite_Inscription_Association.class);
i.putExtra("id", id);
startActivity(i);
}
} catch (Exception e) {
e.printStackTrace();
a= new AlertDialog.Builder(LoginActivity.this).create();
a.setTitle("Erreur");
a.setMessage("Erreur :".concat(e.toString()));
a.show();
}
}
#Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}
}
I have a custom class in Android, very simple which I call to download and start the share intent on files in my app which come from a specific URL
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Environment;
import java.io.File;
public class DownloadAndShare
{
Activity activity;
Context context;
ProgressDialog dialog;
String URL;
public DownloadAndShare(Activity activity, Context context, String URL) {
this.activity = activity;
this.context = context;
this.URL = URL;
}
public void startSharing()
{
//Start shareIntent for this file
File fileWithinMyDir = Environment.getExternalStorageDirectory();
String[] fn = URL.split("/");
String fileName = fn[fn.length-1];
File storageFolder = new File(fileWithinMyDir.toString() + "/myappname");
//If storage folder does not yet exists, create it
if(!storageFolder.exists()){
storageFolder.mkdirs();
}
final String PATH = fileWithinMyDir.toString() + "/myappname/" + fileName;
//Check if file exists in internal storage
File file = new File(PATH.replace(" ", ""));
if (!file.exists()){
//file does not exists, download to internal storage for use
new executeDownloadAndShare().execute(PATH.replace(" ", ""), URL);
} else {
Intent shareIntent = Globals.getShareIntent(PATH.replace(" ", ""), false);
activity.startActivity(Intent.createChooser(shareIntent, "Share using..."));
}
}
private class executeDownloadAndShare extends AsyncTask<String, Integer, Integer> {
String filePath;
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(context, "", context.getResources().getString(R.string.general_msg_please_wait));
}
#Override
protected Integer doInBackground(String... params) {
filePath = params[0];
try {
Globals.DownloadFromUrl(params[0], params[1]);
} catch (Exception e) {
return AppConstants.STATUS_FAIL;
}
return AppConstants.STATUS_SUCCESS;
}
#Override
protected void onPostExecute(Integer result) {
dialog.dismiss();
Intent shareIntent = Globals.getShareIntent(filePath, false);
activity.startActivity(Intent.createChooser(shareIntent, "Share using..."));
}
}
}
For some reason, when I try to create an instance of it inside one of my files, it needs to have the full com.myappname.android.MyCustomClass myCustomClass = new com.myappname.android.MyCustomClass(); In order files I have it as just MyCustomClass myCustomClass = new MyCustomClass() and it works fine, however in a few files it wants the entire path.
Does anyone have any insight as to why this occurs? Both files where I call this are both extending Fragment, and one works while the other needs the full path. I thought maybe it was something with a private method where it should be public etc, but I can't find anything wrong.
Clean you project and uninstall app from device/emulator before starting it again. If that not help, restart Android Studio.
I am working on an app with email sending function. The email recipients address list is from an SQLite query from a database. Apparently I have to run database query in the background in order to get the email function work (see my code below). However, I don't know how to get the output of my query that contains an email list and load on to a 'TO' recipients field. The Email 'TO' field should be a string array list. The current code is not working. Could someone help me on this? Maybe there are other ways to solve my problem. I am very new to Android and Java. Many thanks!
my activity codes are here:
package jhapps.com.demographics;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.Serializable;
public class PromotionEmailMonthTop10 extends Activity {
private EditText subjectGroupTop10,bodyGroupTop10;
private Button btnMonthTop10;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_promotion_email_month_top10);
subjectGroupTop10=(EditText)findViewById(R.id.subjectMonthTop10);
bodyGroupTop10=(EditText)findViewById(R.id.bodyMonthTop10);
btnMonthTop10=(Button)findViewById(R.id.btnMonthTop10);
btnMonthTop10.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EmailMonthTop10();
// after sending the email, clear the fields
subjectGroupTop10.setText("");
bodyGroupTop10.setText("");
}
});
}
//get month top 10 email list
protected void EmailMonthTop10() {
/** DataBaseHelper dataBaseHelper=new DataBaseHelper(this);
String[] emailGroupTop10=new String[dataBaseHelper.eMailListMonthTop10().size()];
for(int i=0;i<dataBaseHelper.eMailListMonthTop10().size();i++){
emailGroupTop10[i]=dataBaseHelper.eMailListMonthTop10().get(i);
}
*/
new SendEmailTop10Task().execute();
String subjects=subjectGroupTop10.getText().toString();
String bodytext=bodyGroupTop10.getText().toString();
//start email intent
Intent email = new Intent(Intent.ACTION_SENDTO);
// prompts email clients only
email.setType("message/rfc822");
email.setData(Uri.parse("mailto:"));
email.putExtra(Intent.EXTRA_EMAIL, new SendEmailTop10Task().execute());
// email.putExtra(Intent.EXTRA_EMAIL,new String []{"junrudeng#gmail.com","huangji8#gmail.com"});
email.putExtra(Intent.EXTRA_SUBJECT, subjects);
email.putExtra(Intent.EXTRA_TEXT, bodytext);
try {
// the user can choose the email client
startActivity(Intent.createChooser(email, "Choose an email client from..."));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(PromotionEmailMonthTop10.this, "No email client installed.",
Toast.LENGTH_LONG).show();
}
}
class SendEmailTop10Task extends AsyncTask<Void, Void, Void> {
// This is called on a seperate thread
#Override
protected Void doInBackground(Void... Voids) {
DataBaseHelper dataBaseHelper=new DataBaseHelper(PromotionEmailMonthTop10.this);
String[] emailGroupTop10=new String[dataBaseHelper.eMailListMonthTop10().size()];
for(int i=0;i<dataBaseHelper.eMailListMonthTop10().size();i++){
emailGroupTop10[i]=dataBaseHelper.eMailListMonthTop10().get(i);
}
return null;
}
}
}
this is what I can come up with:
public String getEmaillist() {
btnSubmit = (Button) findViewById(R.id.btneMailist);
btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DataBaseHelper dataBaseHelper = new DataBaseHelper(PromotionEmailMonthTop10.this);
String[] emailGroupTop10 = new String[dataBaseHelper.eMailListMonthTop10().size()];
for (int i = 0; i < dataBaseHelper.eMailListMonthTop10().size(); i++) {
emailGroupTop10[i] = dataBaseHelper.eMailListMonthTop10().get(i);
}
}
});
return null;
}
then add
getEmaillist();
to onCreate
modify the original code like this:
String emaillist= new String();
emaillist=getEmaillist();
//start email intent
Intent email = new Intent(Intent.ACTION_SENDTO);
// prompts email clients only
email.setType("message/rfc822");
email.setData(Uri.parse("mailto:"));
email.putExtra(Intent.EXTRA_EMAIL, emaillist);
this is nor working. Please provide me more information. Many many thanks
I am trying to get a simple Android app working with the Pd library I have integrated within my eclipse environment.
I have successfully build and compiled an example project called "CircleOfFifths" which proves that the library has been integrated fine in eclipse.
I am using cordova/phonegap and trying to create a plugin for libpd. All the plugin communication with the javascript file on the front-end is working fine.
The code seems to initialise and load the patch fine. It also goes into the play() method but I don't get any output. I am expecting to hear the sine wave.
I followed this tutorial on YouTube.
My code can be viewed here, and the patch is here.
Can anyone help me figure out where I can be going wrong?
My ultimate objective is to use a live audio from microphone and process that audio and return immediately with applied Pd patch (patch is ready and created for this) but before I go to that stage I want to make sure that I get some sort of output from the existing patch. Same patch as the one above in the YouTube tutorial.
package com.test.libpd;
import java.io.File;
import java.io.IOException;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.puredata.android.io.AudioParameters;
import org.puredata.android.io.PdAudio;
import org.puredata.android.utils.PdUiDispatcher;
import org.puredata.core.PdBase;
import org.puredata.core.utils.IoUtils;
import android.content.Context;
import android.util.Log;
import com.sgil.libpddemo.R;
public class Libpd extends CordovaPlugin {
private static final String TAG = "libpd_plugin";
private Exception exception;
private Context AppContext;
private PdUiDispatcher dispatcher;
private static final int MIN_SAMPLE_RATE = 44100;
public Libpd() { // constructor
}
private Context getApplicationContext() {
return this.cordova.getActivity().getApplicationContext();
}
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
Log.v(TAG, "Init LIBPD PLUGIN");
}
public boolean execute(final String action, final JSONArray args,
final CallbackContext callbackContext) throws JSONException {
cordova.getActivity().runOnUiThread(new Runnable() {
// #SuppressLint("NewApi")
public void run() {
Log.v(TAG, "Plugin received:" + action);
Libpd libpd = new Libpd();
libpd.AppContext = getApplicationContext();
try {
libpd.initPd(libpd.AppContext);
libpd.loadPatch(libpd.AppContext);
} catch (IOException e) {
Log.e(TAG, e.toString());
// libpd.finish();
}
if (action.equals("playRec")) {
// MediaRecordMethod mediaRecordMethod = new
// MediaRecordMethod(action);
// mediaRecordMethod.init();
libpd.play();
}
if (action.equals("stopRec")) {
libpd.onPause();
}
if (action.equals("startRec")) {
libpd.record("start");
libpd.play();
}
}
});
return true;
}
private void initPd(Context ctx) throws IOException {
AudioParameters.init(ctx);
// Configure the audio glue
int sampleRate = AudioParameters.suggestSampleRate();
int srate = Math.max(MIN_SAMPLE_RATE, AudioParameters.suggestSampleRate());
// int sampleRate = 64;
int inpch = AudioParameters.suggestInputChannels();
int outpch = AudioParameters.suggestOutputChannels();
PdAudio.initAudio(srate, 0, outpch, 8, true);
// Create and install the dispatcher
dispatcher = new PdUiDispatcher();
PdBase.setReceiver(dispatcher);
}
private void loadPatch(Context ctx) throws IOException {
File dir = ctx.getFilesDir();
Log.v(TAG, "path:" + dir.getAbsolutePath().toString());
//File dir = new File("/sdcard/mypatches");
IoUtils.extractZipResource(
ctx.getResources().openRawResource(R.raw.simplepatch), dir, true);
File patchFile = new File(dir, "simplepatch.pd");
PdBase.openPatch(patchFile.getAbsolutePath());
//PdAudio.startAudio(ctx);
//this.record("start");
}
private void record(String startorStop) {
if (startorStop.equals("start")) {
PdBase.sendSymbol("recordfilename", "x.aiff");
PdBase.sendBang("openfile");
PdBase.sendBang("record");
} else {
PdBase.sendBang("stoprecording");
}
}
// play back the last recording from the file called 'recorded'
public void play() {
//PdBase.sendSymbol("playfilename", "x.aiff");
//PdBase.sendBang("readfile");
//PdBase.sendBang("play");
Float val = 1.0f;
PdBase.sendFloat("onOff", val);
}
protected void onPause() {
PdAudio.stopAudio();
PdAudio.release();
PdBase.release();
}
}
your code never starts the audio-processing.
For whatever reasons youhave uncommented the line
PdAudio.startAudio(ctx)
I've written an app that sits in the 'Share via' menu (for quickly emailing myself links to things I find on the web or look at in RSS readers) For this I'm using an intent.action.SEND intent-filter:
<activity
android:name="uk.co.baroquedub.checkit.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Here's the MainActivity package, it grabs the page title and url from the Intent and uses a separate GMailSender class to directly email me this info:
package uk.co.baroquedub.checkit;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private static Dialog dialog;
String title;
String url;
String message;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
String action = intent.getAction();
// if this is from the share menu
if (Intent.ACTION_SEND.equals(action)) {
title = intent.getStringExtra(Intent.EXTRA_SUBJECT);
url = intent.getStringExtra(Intent.EXTRA_TEXT);
// Flipboard fix (remove title in URL)
url = url.replace(title, "");
if (url != null){
url = title+"\n"+url;
} else {
url = "error getting URL";
}
// Asynch Task
doSendTask task = new doSendTask();
task.execute(new String[] { url });
}
}
protected void showDialog (String response){
dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog);
dialog.setTitle(response);
Button button = (Button) dialog.findViewById(R.id.Button01);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
finish();
}
});
dialog.show();
}
private class doSendTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
String senderPassword = getResources().getString(R.string.senderPassword);
String senderEmail = getResources().getString(R.string.senderEmail);
String recipientEmail = getResources().getString(R.string.recipientEmail);
String subjectText = getResources().getString(R.string.subjectText);
GMailSender sender = new GMailSender(senderEmail, senderPassword);
try {
sender.sendMail(subjectText,
url,
senderEmail,
recipientEmail);
response = "Email sent";
} catch (Exception e) {
//Log.e("SendMail", e.getMessage(), e);
response = "Error sending email";
}
return response;
}
#Override
protected void onPostExecute(String result) {
showDialog(result);
}
}
#Override
public void onDestroy() {
super.onDestroy();
/*
* Kill application when the root activity is killed.
*/
UIHelper.killApp(true);
}
}
Version 1 worked fine but I was sending the email from within 'onCreate' which meant that until the "Email sent" notification appeared, the phone's browser would be unresponsive (I wasn't able to scroll or navigate to a new page). I then changed the code (as per above) to place the email sending code inside an AsyncTask class - but although the app still works the browser remains unresponsive until the dialog appears. AsyncTask seems to have made no difference.
Can anyone explain why, and hopefully suggest a solution?
ANSWER?... I've massively simplified the above code to try to work out what might be wrong. I created a bog standard App and used the following:
package uk.co.baroquedub.testcheck;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
doSendTask task = new doSendTask();
task.execute(new String[] { "urlString" });
}
protected void showDialog (String response){
Toast.makeText(this, response, Toast.LENGTH_SHORT).show();
finish();
}
private class doSendTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
try {
Thread.sleep(5000);
response = "Waited";
}
catch (InterruptedException ex) { }
return response;
}
#Override
protected void onPostExecute(String result) {
showDialog(result);
}
}
}
This has allowed me to see what's going wrong: my app is opening on top of the browser (a white screen appears with a title bar showing the name of the app) I wasn't aware of this with my proper app (above) because I was using a Theme that used a transparent background.
See: screencast for demo of problem
So although the email is being sent as an AsyncTask, while this is happening the app itself is appearing on top of the browser - which is what is stopping it from being accessible. (I'll post a request for help on this as a separate question)
No, AsyncTask is not bond to your UI thread and you will not be blocking it as you did while doing some lengthy operation in your onCreate().
I think you have a mistake in your code:
doSendTask task = new doSendTask();
task.execute(url); // if you want to put more urls task.execute(url,url1,url2);
try {
sender.sendMail(subjectText,
url[0], // get the first url
senderEmail,
recipientEmail);
response = "Email sent";
} catch (Exception e) {
//Log.e("SendMail", e.getMessage(), e);
response = "Error sending email";
}
ASyncTasks are, indeed, executed on their own thread, as written on their reference page.
When you create the intent for this activity, you pass the flag 'FLAG_ACTIVITY_CLEAR_TOP', which reads something like '...all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.'. Doesn't this mean that the old activity is locked until this new one terminates?