Start Activity from Service in Android 10 - java

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.

Related

ANDROID STUDIO How to go back to application from settings

I got some trouble with android studio I work in a company who has a web application so I worked on IOS application it was pretty easy but now I worked on Android and I'm not able to do a simple return to the application.
This the visual legacy :
When you open the application it answers you to allow some permission to the app :
[Popup to authorize permission]
https://i.stack.imgur.com/Uz9Ox.png
Then you go to the settings :
[Settings] https://i.stack.imgur.com/oqlfG.png
As you can see we implement additional settings to enter user ids ( mail, password ) :
[Additional settings ] https://i.stack.imgur.com/zn8Ll.png
You can see that there is a button below the inputs I want it to returns to the application but when I'm putting this code
Preference myPref = findPreference("backto");
myPref.setOnPreferenceClickListener(preference -> {
startActivity(new Intent(getContext(), MainActivity.class));
return true;
});
It doesn't send me to the application it creates a new instance of the application directly in the additional settings.
How can I make a function that send me to the app and not create a new instance ?
There is my additional settings class:
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
/**
* A simple {#link Fragment} subclass.
*/
public class SettingsFragment extends PreferenceFragmentCompat {
MainActivity mainActivity;
#Override
public void onCreatePreferences(#Nullable Bundle savedInstanceState, #Nullable String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
Preference myPref = findPreference("backto");
myPref.setOnPreferenceClickListener(preference -> {
startActivity(new Intent(getContext(), MainActivity.class));
return true;
});
}
}
If you want to request permissions from your app, the proper way is through Intent and then you handle the code in onRequestPermissionsResult. There is no need to direct the user to the settings
See these tutorials for more info. Just keep in mind that Google now has a new policy about "sensitive permissions", some of them may not be approved when uploaded on Google Play
Link 1,
Link 2,
Link 3

Passing string literals to stored procedure in android studio with EditText?

Second post here, the first one was extremely helpful so thank you for those that contributed. I will try to be concise with the issue I'm having. I am using android studio in intellij to develop an application. Part of the functionality of the app is a fragment that accepts a new username input from the end user, and then stores that username into my database (a preexisting database that has been linked to intellij). I am new to java and only in the last couple days started to change from creating UI with swing and awt, to xml files. My understanding is that xml files are data descriptors and useful for creating static objects/widgets while the .java files use java to create behaviors for the objects by referencing their IDs created in the xml file. Now comes the confusing part for me, and forgive me if this seems like a no brainer, as I'm pretty new to all this- I have "piggybacked" off a base shell for a android app, and as best as I can tell, setOnClickListener is essentially the android java version of action listeners. I added to the method that essentially took a button and navigated from one fragment to the next, with code that connects to the database, and then executes the stored procedure presumably when the "next"/"submit" button is clicked. Now here's the catch: obviously when a submit button is clicked, there is no user defined username that gets passed into the stored procedure, so obviously it won't work. The problem is, the TextEdit text field that I created is created in an xml file with no way to reference it or manipulate it in the java code, yet it accepts "text" parameters and works fine in the emulator. Obviously I want the stored procedure to take the user inputs in that text field and store it as a new username in the database, but since xml just describes data, and there isn't any defined text field in the java code, I'm at a loss for how to accomplish this task. I can't just write up an action listener and attach it to the xml id of the TextEdit because there isn't anything in the xml file that explains where the actual typed characters are! I know, higher level programming issues. Can anyone help explain how to do what I'm trying to do? Preferably as much as possible in laymans terms. Here is the code:
package com.example.callit;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.sql.*;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;
public class FirstFragment extends Fragment {
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_to_SecondFragment);
String sqldatabase = "//database connection url";
try {
Connection con = DriverManager.getConnection(sqldatabase);
CallableStatement cs = con.prepareCall("{EXEC [dbo].[CreateUser] #UserName = N'Dog', #UserID = #UserID OUTPUT}");
cs.execute();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
});
}
}
I included it in case there was something inherently wrong with the connection to the database code (I also am aware that I should disconnect from the database as well). I would like to note that the code runs without errors, it just doesn't do what it should (for the reasons I explained above). Any help would be greatly appreciated!

Cannot find symbol class Intent

I am new in android development and coding java and xml.
but I was following this tutorial:
http://www.steventrigg.com/activities-and-the-action-bar-create-an-alarm-clock-in-android-tutorial-part-1/#comment-296
then I had this error when using Intent. The word "Intent" under switch became red and there is an error "cannot find symbol class Intent"
Can someone explain to me what is going on and how to solve this?
This is the last part of my code under AlarmListActivity.java
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
switch (item.getItemId()) {
case R.id.action_add_new_alarm: {
Intent intent = new Intent(this,
AlarmDetailsActivity.class);
startActivity(intent);
break;
}
}
return super.onOptionsItemSelected(item);
}
Look at your AlarmListActivity again and check the import statements at the top and make sure it includes the line:
import android.content.Intent;
If you intend to use any pre-existing classes that aren't part of the java.lang package, you generally have to import those classes. An Android Intent, for example, is a pre-built class, written by the Android development team, that allows for notification of other apps/activities. If you want to use Intent, you'd then have to import the package containing Intent.
When you write new Intent(), the compiler sees that you're requesting the construction of a new object, but because that object is not found in the java.lang package, it needs to know where to look for a blueprint to build that object. The import statement is the location of that blueprint.
I took a look at the tutorial and in the manner of experienced programmers, the author seems to have glossed over a few basic, but nonetheless, important things, such as the import statements that make his sample code work.
I had a same problem which I just resolved, by understanding how Android Studio indexes files, As you know Building an Android App is quite complicated process. So Android studio has some internal references which it keeps getting updated on change of every file that you have created.
I arrived at this post while searching for the solution,
This is how I got this problem
I usually wont create an activity under the main project package, I create sub packages to organize files as per the design pattern that I use, for eg If my APP name is com.example.testingaravind then inside that I usually create packages such as activites, services, models, managers etc ... So today I just created an activity first and then moved that activity into activites package via Android Studio, I started facing the same issue what you have described, Below was my source code
public class BootstrapActivity extends ActionBarActivity {
private static final String TAG = "BootstrapActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bootstrap);
}
public void startServiceOnClickHandler(View view) {
Intent intent = new Intent(BootstrapActivity.this , AnalyzerService.class);
startService(intent);
}
}
In the method startServiceOnClickHandler it was showing an error saying,
"Cannot resolve constructor Intent" I searched a lot in google and found that
When I move a file from one package to other package, my manifest file wont get updated, in the manifest we mention the activity name and its package path in my case it should be
android:name=".activities.BootstrapActivity"
But it was
android:name=".BootstrapActivity"
Because of this, Android studio was unaware that a class called BootstrapActivity exists inside the activities folder,
This seems to be a bug in the way how android studio works. Android Studio has to update manifestfile when I move the activity class file from one package to another package.
I am posting this to help others who might arrive at this post with the similar usecase.
Check name in manifest file in activity tag specify correct package for example your
<activity
android:name="Your-Package.MainActivity"
android:exported="true" />
In second case If you are using kotlin class inside java class, after configuring kotlin in project can solve the project...

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

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.

Trying to make a Adapter class to choose .Java file depending on firmware version

What I did was create two .java files. One that can compile and run on a 1.5 phone (SDK3) and then one that works on 2.0(SDK5) So for this example i'll call the 1.5 file ExampleOld and the new one Example. I was wondering if i just made activity like this if it would work sort of like a "portal" and pick the activity to load depending on the SDK so there is no crash or compile errors. Are there any changes I should make to my code? Maybe anyone out there that's had to do this before. thanks!
package com.my.app;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
public class ExamplePortal extends Activity {
int sdk=new Integer(Build.VERSION.SDK).intValue();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (sdk<5) {
Intent v = new Intent(this, ExampleOld.class);
startActivity(v);
}
else {
Intent v = new Intent(this, Example.class);
startActivity(v);
}
}
}
What you're doing (correct me if I'm wrong) is trying to maintain backwards compatibility while making use of new APIs if the user is running a newer android version. The best way to do this is to follow the tutorial Google posted here. This avoids any verification issues and is really the best way to do stuff imho.
I would put this decision in a Factory Class to avoid having these if-else statements all over the codebase.

Categories