Create a folder, create file, print logcat, send email - java

Im still very new to Android development, so I apologize in advance if my question seems silly.
In my application I have one button. When the button is clicked it attempts to see if the application has its own folder on the internal storage, if not it creates a folder, then it creates a file called output.txt, then it writes system information to the output.txt, then it attempts to write all lines containing "SIP_MESSAGE" from the logcat into the output.txt, it then emails the default email address.
EDIT
After a few days of toiling I managed to put it all together. Please read the answer below for everything in detail.

After a few days of research and a countless number of guess and checks, I finally figured everything out. I want to take this time to actually explain everything, in case anyone comes across this and is having the same problems that I had. Hopefully everything you are looking for is right here, and I gave a better explanation then the 100's of other sites that you (and I) had visited previous to this.
First topic is the difference between internal and external storage (it's not the difference between sdcard and not sdcard).
Internal storage is something that no one can see or get to but your application. If you create a file or folder on the internal storage, you cant use a file browser (unless your rooted) or your computer to see what you've created, it is completely inaccessible from outside your application.
Public folders such as Documents/Downloads/Music/Ringtones/etc. are technically on you external storage. You need permissions to write and read from it. This is where I was getting confused. I thought only sdcards counted as external storage, external storage is something you can manually get to from a computer or file browser whether its on an sdcard or not.
To create a file on the internal or external storage you do not need to use mkDir(). Anyone that says you do, is overly complicating things. You can actually create any text file anywhere on the system just from the code:
PrintWriter osw = new PrintWriter(Environment.getExternalStoragePublicDirectory(DOWNLOAD_SERVICE).toString() + "/output.txt");
This creates a text file in the download directory, whether it existed there or not first. You can also use getDataDirectory() or wherever else you want to create the file.
Next Logcat, like what the other people were pointing out, I was trying to read from the logcat as it was being created. There is no end to the logcat, so in effect, my application hung because it was constantly looking for more to write. An easy way around this is to use the -d feature of logcat. What that does is it just takes everything up to the point where -d was entered (which was exactly what I wanted), then it stops, then you can put it into a buffer and get the output with no hanging.
Finally, attaching a file to an email intent. This one was tricky because there were a few different areas that ended up giving me problems. In short, if you are receiving the error, "Couldn't show attachment", it means one of two things - 1.) you are trying to attach a file from the internal memory (remember, no other programs are allowed to access the internal memory, even gmail) or 2.) you are not using getAbsolutePath(). I found quite a few people that said you can't attach a file using uri.parse() and the you have to use uri.fromFile(), that is wrong, attached I show you how to attach a file and not get an error.
I hope this code helps you, and I hope you do not spend 1/10th of the time I did trying to figure this stuff out.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Calendar;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mailb = (Button)findViewById(R.id.bmail);
final TextView confirmation = (TextView)findViewById(R.id.Confirmation);
mailb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
PrintWriter osw = new PrintWriter(Environment.getExternalStoragePublicDirectory(DOWNLOAD_SERVICE).toString() + "/output.txt"); //This creates a file in my public download directory
osw.println("Output Log: Report Tool");
osw.println("Date: " + java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime()));
osw.println("------------------------------------");
osw.println("Manufacturer: " + android.os.Build.MANUFACTURER);
osw.println("Model: " + android.os.Build.MODEL);
osw.println("Serial: " + android.os.Build.SERIAL);
osw.println("BootLoader: " + android.os.Build.BOOTLOADER);
osw.println("Build ID: " + android.os.Build.FINGERPRINT);
osw.println("------------------------------------");
try {
Process p = Runtime.getRuntime().exec("logcat -d -v long"); //This gets the dump of everything up to the button press
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
if(line.toString().contains("SIP_MESSAGE")){ //This parses out everything but SIP Messages
osw.println(line); }}}
catch (IOException e1) {confirmation.setText(e1.getMessage()); }
osw.flush();
osw.close();
} catch(Exception e){ confirmation.setText(e.getMessage()); }
String attach = Environment.getExternalStoragePublicDirectory(DOWNLOAD_SERVICE).getAbsolutePath() + "/output.txt"; //This is where you need to use the absolute path!!
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("message/rfc822");
i.putExtra(Intent.EXTRA_EMAIL , new String[]{"MyEmail#Email.com"});
i.putExtra(Intent.EXTRA_SUBJECT, "Error Report.");
i.putExtra(Intent.EXTRA_TEXT , "Please see the attached file...");
i.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + attach)); //This is where you attach the file
try {
startActivity(Intent.createChooser(i, "Send mail..."));}
catch (android.content.ActivityNotFoundException ex) {
confirmation.setText("There is no Email Client installed on this device.");}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
And finally, the permissions I used for this was READ_LOGS, WRITE_EXTERNAL, READ_EXTERNAL.
I hope you've enjoyed, and good luck.

Oops! Spoke too soon, you meant internal.
Why don't you try writing a file directly into your app directory instead of creating a folder. Check if it that works first.
For that you may do:
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
This is what you're looking for:
File outputDir = new File(Environment.getExternalStorageDirectory()
+ "/farmer survey");
outputDir.mkdirs();
File outputFile = new File(outputDir, "something.csv");
try {
FileOutputStream fos = new FileOutputStream(outputFile);
PrintWriter pw = new PrintWriter(fos);
pw.println(text);
pw.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
You also need to add this permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Do you have the android.permission.READ_LOGS permission in your manifest?

For the email portion do you intent to send it automatically?
If so, I don't think it can be done in the background easily. The best is invoke the Gmail app with the output.txt attached as an attachment. Subsequently, you need to manually send it.
Otherwise the coding may be very long, see here:
Sending Email in Android using JavaMail API without using the default/built-in app
Or another way is to send out through SMS, this can be done in the background.

Related

Start Activity from Service in Android 10

please note that problem might be related to Android 10
Im trying to start a new Activity from myInAppMessagingService, but i got null pointer exception un startActivitys context parameter every time.
So here is my Service code :
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.firebase.inappmessaging.FirebaseInAppMessagingClickListener;
import com.google.firebase.inappmessaging.model.Action;
import com.google.firebase.inappmessaging.model.CampaignMetadata;
import com.google.firebase.inappmessaging.model.InAppMessage;
import viaapp_v2.systems.webview_activity.webview_base;
public class MyFirebaseInAppMessaging extends Service implements FirebaseInAppMessagingClickListener {
String TAG = "MyFirebaseInAppMessaging";
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void messageClicked(#NonNull InAppMessage inAppMessage, #NonNull Action action) {
// Determine which URL the user clicked
String url = action.getActionUrl();
Log.d(TAG, "Popup URL :"+url);
// Get general information about the campaign
CampaignMetadata metadata = inAppMessage.getCampaignMetadata();
Log.d(TAG, "metadata :"+metadata);
try{
startActivity(
new Intent(MyFirebaseInAppMessaging.this, webview_base.class)
.putExtra("web_url", url)
);
}catch(Exception e){
e.printStackTrace();
}
}
}
I got error in "startActivity(..)" line because of 1st parameter, context. I tried everything - getApplicationContext(), MyFirebaseInAppMessaging.this or just simply "this" but nothing works.
I read a restrictions provided by Android Developers, but i couldnt figure out anything new.
Otherwise the app works perfectly - webview_base class works as it should, so does everything else, including myInAppMesaging Services listener. Its just that one context in startActivity() which stops me.
Thanks for any help.
--Update on Sep 7
After playing around with permissions, flags ect. i noticed that nothing works. Newer Android OS opens an web overly over the app, but older Android OS just crashes without any specific crash report. Thats weird.
Try below code , it will work..
you have to add FLAG- FLAG_ACTIVITY_NEW_TASK
Intent myIntent = new Intent(this, webview_base.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(myIntent);
If your app is not visible and has not been visible for a while and you don't want to use a notification, it will not be allowed in Android 10, except if
The app has been granted the SYSTEM_ALERT_WINDOW permission by the user.
(From the restrictions page mentioned in the question)
So that's an option for Android 10.
It's not enough to list the SYSTEM_ALERT_WINDOW in AndroidManifest.xml. You also need user to give the app "Draw over other apps" permission. Check here how to do that easily.

When reading an external PDF with an Android App it always shows the same version, even after updating the PDF

Please donĀ“t be too harsh to me concerning any mistakes with this question since thats my first one here.
So basically what i want to do is reading/showing a PDF document in my Android App after pressing a button. The PDF is located on a Raspberry Pi 3 and i found a code example on this thread how to read it.
Before accessing it however, i call a python script on the Raspi which is (re)creating the PDF based on a database.
So the user presses the button in the App and sees a PDF which presents the current state of a database table.
Now i got the following code in my Activity to call the script and read the PDF:
new AsyncTask<Integer, Void, Void>(){
#Override
protected Void doInBackground(Integer... params) {
try {
executeRemoteCommand("user","pw","ip", port, "command to execute the python script");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}.execute(1);
//waiting for the PDF to be created
handler.postDelayed(new Runnable() {
#Override
public void run() {
String url = "http://IP/path/file.pdf";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
}, 5000);
With this code connecting to the Raspberry, executing the python script, thus updating the database and reading the PDF file works just fine.
But i have the following problem:
When i close the PDF view in my App, add something to the database and press the executing button again the PDF file itself is being updated (i checked that on the Raspberry) but then the App still shows the old version of it. Even when i restart the App and execute this again it still shows the first version of the PDF...
Does anyone have an idea why and how to fix this?
Is there any kind of cache which stores the PDF and just shows the same every time i read from the Raspberry?

Android - Saving data to an internal storage

I'm working on a simple to-do list app, and I'm trying to read/write data from/to internal storage. I'm trying to understand when exactly those read/write methods should be called.
I know that the activity class has an onCreate() method which will be a reasonable location for my read method, but where should I call my write method?
I want to call it when the app closes/ends, so I'd assume onDestory() is a good location, but i heard that onDestroy() may not be a good location for data storage operations and i should use onStop().
Any help or ideas?
It depends on Application Lifecycle.
And see This.
onStop() invokes when user press home button(Hard Key).
And then, if memory insufficient or another reason, Android Memory Manager will kill your app instant and onDestory() will never called.
The best thing you have to is make a button to save datas. Of course, Include onStop() save routine.
Following the table in the Android Developers Guide on the Activity Lifecycle, your app may be killed by the system any time without warning after either onPause() (for Pre-HONEYCOMB devices) or after onStop(). So you probably want to write your data in these methods to make sure nothing gets lost. So for newer devices (API level 11 and up), onStop() should be fine. If your app should run on older devices as well, onPause() would be the best place.
This is Just sample code. But you get the idea. Create a custom method implementing the code below and call it on some events like "onClick" or any other.
File file;
FileOutputStream strem = null;
String line = "Hey this is my name";
try {
file = new File("sdcard/newFile.txt");
strem = new FileOutputStream(file);
byte[] bytes = line.getBytes();
strem.write(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
strem.close();
} catch (IOException e) {
e.printStackTrace();
}
}

How to close external programs (Powerpoint) running on the native desktop using Java?

I have to create an application that will automatically open a powerpoint file, let it play through, and then close it. Not only do I need to figure out HOW to close it, but I also must detect when it closes or stops.
First option:
I know how long each powerpoint will play for, so I can hardcode when to close the file. I just need to know how to do that. There are no methods in the desktop class (that I could find) for closing.
Second option:
If someone knows a microsoft powerpoint api that lets me open powerpoints and use java to progress through the slideshow and get the state or something, that'd be great. I wouldn't have to go into each presentation and count the number of slides and the transition timer on each slide.
The opening, letting it play, and closing it is a small part of the app I need to create. But here is what I have so far with regards to THIS problem:
File myfile = new File("PowerPoint.ppsx");
try {
Desktop.getDesktop().open(myfile);
} catch (IOException ex) {
Logger.getLogger(Sc.class.getName()).log(Level.SEVERE, null, ex);
}
Probably this is the solution how to close external program:
http://www.java-forums.org/new-java/59691-close-another-program.html#post285956
If you want to detect when program has stopped running then you can start new thread with loop which from time to time will check if the program process is still running, using the same method as mentioned in link.
This is solution only for one (Windows) platform, Java is not the best choice for such tasks.
Here a solution using JNA. First we get the handle, we search using the "class name" of the window. You can determine the class name for a specific program (in this case Powerpoint) with a special utility like Spy++ (included with Visual Studio). It's possible to make the search more precise using the class name and the window caption (but here I use only the class name) so if you have more than one presentation running ... you may not close the good one!.
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinDef.HWND;
// https://github.com/twall/jna#readme
// you need 2 jars : jna-3.5.1.jar and platform-3.5.1.jar
public class KillMyPP {
public static void main(String[] args) {
HWND hwnd = User32.INSTANCE.FindWindow("screenClass", null);
if (hwnd == null) {
System.out.println("PPSX is not running");
}
else {
User32.INSTANCE.PostMessage(hwnd, WinUser.WM_QUIT, null, null);
}
}
}

Android: How to open an unknown file type

I am developing a file explorer app in android.
How to handle files with unknown extensions? When I try to open such kind of file, its throwing ActivityNotFound exception. But I want the system to pop up list of apps so that we can manually choose an application to open it.
Can anyone help me here?
I am starting activity to open the file by binding the file and its extension to the intent.
Intent intent = new Intent(Intent.ACTION_VIEW);
MimeTypeMap mime = MimeTypeMap.getSingleton();
String ext = file.getName().substring(file.getName().lastIndexOf(".") + 1);
String type = mime.getMimeTypeFromExtension(ext);
intent.setDataAndType(Uri.fromFile(new File(file.toString())), type);
try
{
startActivity(intent);
}
catch(Exception e){}
ActivityNotFound is thrown when no application is registered that can handle specific file type. This means that the list of apps you want to show will be empty.
The most appropriate way to deal with he situation is to catch ActivityNotFound exception and show a toast notifying the user there are no appropriate applications to open the file.
All android browsers proceed in this manner.
I will leave this link here, that targets the same problem and has a little more detail to it (second answer, read comments): Launching an Activity based on a file in android

Categories