Starting react-native activity from java module (android) - java

I see that you can bring your activity form the background to the foreground in android using the following lines
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Now the problem is I don't know how to get the name of the react activity to work - When I try to compile I get
error: cannot find symbol Intent i = new Intent(mReactContext,
MainActivity.class);
symbol: class MainActivity
I'm not very experienced with java - so this is part of my problem, I tried using getCurrentActivity() - but this doesn't seem to work either.
Anyone has an idea?
Thanks!

If you have access to reactContext (I see you have) you can try this:
Context context = getReactApplicationContext();
String pn = context.getApplicationContext().getPackageName();
Intent li = context.getPackageManager().getLaunchIntentForPackage(pn);
context.startActivity(li);
String pn is just a package name (e.g. "com.yourapp"), so you can skip getPackageName() and just pass your package name to getLaunchIntentForPackager(). You can check this solution on react-native-system-notification

You should get reference of your first activity. Then Create your intent and start activity. Run the code below somewhere in your code(for example in a react method which triggers an activity)
Activity currentActivity = getCurrentActivity();
Intent intent = new Intent(name of your activity);
currentActivity.startActivityForResult(intent,FLAG_ACTIVITY_NEW_TASK
);
// create onActivityResult method to process your task according to result
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FLAG_ACTIVITY_NEW_TASK ) {
// do your job
}
}
It seems you use MainActivity.class as parameter in intent. I'm not an expert but it seems wrong. In a react-native project mainactivity will be triggered automatically and index.android.js will be called. You can use an activity you create as well you don't have to use native android activities like Intent.ACTION_GET_CONTENT which can be used to get information of an image from gallery.

Related

Open Activity on notification button click when app is closed

I'm trying to open the MainActivity when the user clicks a button in my notification, while the app is only running in the background with a service. When the button is clicked, these lines are triggered in the Service class:
Intent openApp = new Intent(this, MainActivity.class);
openApp.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openApp);
I've checked it, and the lines are triggered, so there's no problem in reacting to the button's click, the Activity won't open though.
Any suggestions? Why isn't this working for me and how can I make it work?
Edit
I was asked for some more code, so in my onStartCommand() inside my Service, if it starts with a stop-action within its intent, I call the killService() method, which kills the Service, starts the MainActivity and do some other stuff:
if (action != null && action.equals(ACTION_STOP_SERVICE)) {
killService();
}
To set the Notifications button, I use this code:
Intent stopActionIntent = new Intent(this, TimerService.class);
stopActionIntent.setAction(ACTION_STOP_SERVICE);
PendingIntent stopActionPendingIntent = PendingIntent.getService(this, 1, stopActionIntent, PendingIntent.FLAG_IMMUTABLE);
timerNotificationBuilder.addAction(R.drawable.stop, "Stop", stopActionPendingIntent);
And as I said, the button already reacts to the user clicking on it, so that's not the problem.
You can try to receive the click in a BroadcastReceiver and then open activity from there.
Try this to add a action button o your notification:
timerNotificationBuilder.addAction(createNotificationActionButton("STOP");
Where the createNotificationActionButton method is this:
public NotificationCompat.Action createNotificationActionButton(String text){
Intent intent = new Intent(this, StopwatchNotificationActionReceiver.class);
#SuppressLint("InlinedApi") PendingIntent pendingIntent = PendingIntent.getBroadcast(this, new Random().nextInt(100), intent, PendingIntent.FLAG_IMMUTABLE);
return new NotificationCompat.Action(0, text, pendingIntent);
}
Create a class named StopwatchNotificationActionReceiver and make it extent a BroadcastReceiver`. This is the code for that class:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class StopwatchNotificationActionReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PrefUtil.setIsRunningInBackground(context, false);
PrefUtil.setTimerSecondsPassed(context, 0);
PrefUtil.setWasTimerRunning(context, false);
context.stopService(MainActivity.serviceIntent);
Intent activityIntent = new Intent(context, MainActivity.class);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActvity(activityIntent);
}
}
Also you need to register that receiver in your manifest like this:
<receiver android:name="StopwatchNotificationActionReceiver"/>
Where the MainActivity.serviceIntent is a public static variable which looks like this:
public static Intent serviceIntent;
And this intent is only used to start the service like this:
//In onCreate
serviceIntent = new Intent(this, TimerService.class);
//In onPause
PrefUtil.setTimerSecondsPassed(this,seconds);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent);
}
Or you can try the simple method:
if (action != null && action.equals(ACTION_STOP_SERVICE)) {
Context context = this;
Intent activityIntent = new Intent(context, MainActivity.class);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActvity(activityIntent);
killService();
}
Edit
Another solution is here. Again. You need to refer to my repo as I have made changes to the files in order to complete your task. In the service class, refer to this method. There, I start the activity if the action is reset(r). Or else, it opens the broadcast receiver. Then, in the activity, I receive that extra in the onResume() method. If the reset button is not clicked, it opens the Receiver class.
And as always, you can view the result of the app from here.
I hope that code will do your work.
I found it! See this answer.
This answer suggests enabling ScreeanOverlay settings because as of Android 10 and later you can no longer open an activity from the background just by calling the lines I've used.
To make it work, you'd have to add this permission through your Manifest.xml:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And then the user would have to enable the Display over other apps setting.
I searched for an option to get the user to this setting more easily and found this answer.
This answer gives a code that redirects the user to the Display over other apps setting
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 0);
}
and then I guide the user with the notification's content (text) on how to enable the setting.
Once the setting is enabled, The lines I've used before work.\
So, problem solved?
Not Completely Solved
this whole configuration described above works, but only if the app is not killed.
If the app was killed and I try the method listed above, the app joins the recent apps list, but won't open and show up.
A solution that solves this issue as well will be accepted as an answer instead of this one.

startActivityForResult() is deprecated, use registerForActivityResult() [duplicate]

My app contains a simple Fragment that is used to open external web pages, with:
Intent intent = new Intent(Intent.ACTION_VIEW, externalUrl); // Uri
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooserIntent = Intent.createChooser(intent, "Open URL...");
startActivityForResult(chooserIntent, RC_OPEN_URL);
And, when the result is returned (in my Fragment's onActivityResult(...)), the Fragment is popped off the backstack.
But, I'm now getting the new deprecation warning:
startActivityForResult(Intent,int) in Fragment has been deprecated
I've read the corresponding Getting a result from an activity documentation, but I'm not sure how to adapt the example they provide for my particular case.
I have discovered the ActivityResultContracts.StartActivityForResult class, but can't figure out how to pass my chooserIntent to it.
All the online examples for the class seem to be in Kotlin and I've not had any joy trying to decompile them to Java. So a Java example of how to use the new registerForActivityResult() method to open an external URL would be much appreciated.
There's no reason to use startActivityForResult() at all for createChooser() - you can use startActivity and run your code from onActivityResult() immediately after you call to startActivity:
Intent intent = new Intent(Intent.ACTION_VIEW, externalUrl); // Uri
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooserIntent = Intent.createChooser(intent, "Open URL...");
startActivity(chooserIntent);
// Do your code from onActivityResult() here
However, if you really want to use the Activity Result API, then you can directly adapt the examples in the documentation, replacing the example GetContent contract with the StartActivityForResult contract:
// Create this as a variable in your Fragment class
ActivityResultLauncher<Intent> mLauncher = registerForActivityResult(
new StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
// Do your code from onActivityResult
}
});
private void triggerChooser(Uri externalUri) {
Intent intent = new Intent(Intent.ACTION_VIEW, externalUrl); // Uri
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooserIntent = Intent.createChooser(intent, "Open URL...");
mLauncher.launch(chooserIntent);
}
Below answer may help to someone.... But this is not readymade solution to above question.
I have faced lot of issue when I try to get result from activity to fragment.
Finally I found below solution.
In side the fragment, I created ActivityResultLauncher.
var myActivityResultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult<Intent, ActivityResult>(
ActivityResultContracts.StartActivityForResult(),
ActivityResultCallback<ActivityResult> {
// ToDO:
if (it.resultCode == AppCompatActivity.RESULT_OK) {
}
}
) as ActivityResultLauncher<Intent>
And when I start the activity I used below code.
myActivityResultLauncher.launch(myIntent)

Can the same Android getIntent() receive from two different classes?

Problem:
When I try to "reuse" so-to-speak a getIntent() with extra values by passing data to it from a second activity, the extra values return null. So I want to pass NoteAdapter Intent Extras to the ViewNote class and I also want to pass EditNote Intent Extras to the ViewNote class using the same string keys.
Something like this: User chooses note > User Views Note > User Edits Note > User Views Note corrected.
What works:
Based upon a user selection of a RecyclerView list of notes, the chosen note through a NoteAdapter has extra details passed to an Intent to a ViewNote class which in turn has a Intent n = getIntent() which these extras are received. Note details are loaded into the ViewNote activity. If the user decides this note needs corrected or updated, then the ViewNote class has an Intent that passes extras to the EditNote class. This all works great!
What doesn't work and What I'm trying to do:
I'm not sure whether this is allowed or can be done but I'm trying to pass extras back to the ViewNote class from the EditNote class using the same Intent n = getIntent() in the ViewNote class used earlier when a note was passed to it.
The ViewNote class getIntent():
Intent n = getIntent();
nNoteID = n.getIntExtra("ID", 0);
String nType = n.getStringExtra("Type");
String nSummary = n.getStringExtra("Summary");
String nSource = n.getStringExtra("Source");
String nAuthors = n.getStringExtra("Authors");
The EditNote Intent to pass extras back to the ViewNote
Intent u = new Intent(EditNote.this, ViewNote.class);
u.putExtra("ID", vNoteID);
u.putExtra("Type", ty);
u.putExtra("Summary", su);
u.putExtra("Source", so);
u.putExtra("Authors",au);
EditNote.this.startActivity(u);
What I have tried:
I've read a few posts here on stackoverflow that appeared to be similar and tried changing the context (thinking maybe that was wrong), and tried using Bundle but neither of those made any difference. I thought maybe the String array values weren't passing so I just passed String variables because the "ID" number as a String seems to pass fine but the other values still return null. I've read some of the Android Developer explanations about Intents and maybe I just don't understand Intents fully or maybe this just can't be done or is not how it should be done.
I'm working in the following:
Intellij Idea 2021.1.1
Java Android v.28 Min v.29 Max
Gradle 4.1.2
The solution was exactly what David Wasser posted in the initial comments above. I needed to use the startActivityForResult and follow the guidelines on how to do so. I did review the Android Development links and other examples online, but this video helped:
Android startActivityForResult Tutorial
These are the code segments in sequence:
ViewNote
menuIntent = new Intent(this, EditNote.class);
menuIntent.putExtra("NoteID", nNoteID);
menuIntent.putExtra("NoteDetails", new ArrayList<>(noteDetails));
if(noteFiles.size() > 0)
menuIntent.putParcelableArrayListExtra("NoteFiles", new ArrayList<>(noteFiles));
startActivityForResult(menuIntent, REQUEST_CODE); // REQUEST_CODE = 1
EditNote
Intent u = new Intent();
u.putExtra("ID", vNoteID);
u.putExtra("Type", ty);
u.putExtra("Summary", su);
u.putExtra("Source", so);
u.putExtra("Authors",au);
setResult(RESULT_OK,u);
finish();
Back to ViewNote onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE){
if(resultCode == RESULT_OK) {
nNoteID = data.getIntExtra("ID", 0);
nType = data.getStringExtra("Type");
nSummary = data.getStringExtra("Summary");
nSource = data.getStringExtra("Source");
nAuthors = data.getStringExtra("Authors");
}
}
}

Communication between running activities?

I'm new to android and is currently developing a quest/tresurehunt application. It is a prototype and is going to be evaluated in the field and i would therefore like to implement some sort of cheat to skip checkpoints if the application should crash during the tests.
My application work the way that when you select a quest a activity will be loaded to handle all checkpoints and the user location(ActivityAdapter.java). This activity will open the diffrent navigation tool activities and pass information to them based on the next checkpont using intent. I have implemented a long press event in the app i would like to activate the skip/cheat. My problem is that i can't figure out how to do this.
Location changed event of ActivityAdapter.java:
public void onLocationChanged(Location location) {
location.distanceBetween(location.getLatitude(), location.getLongitude(), lat, lng, dist);
if (dist[0]<= 10) {
if (cid == checkpoints.size()) {
Intent intent = new Intent(ActivityAdapter.this, SuccessActivity.class);
intent.putExtra("title", checkpoints.get(cid).get("title"));
startActivity(intent);
} else {
new loadAndStartQuest().execute();
}
}
}
loadAndStartQuest() just find the next checkpoint and start the right activity (navigationtool). I have tryed creating a object of the ActivityAdapter and set a variable and add it to the the if statement which did not work. I guess it is because it will create another instance of the activity and not affect the current/running one. So how would you communicate between two running activities?
To send data from Activity1 to running Activity2, you must pass through the next steps:
In Manifest.xml set launch mode "singleTask" for Activity2
<activity android:name="Activity2" android:launchMode="singleTask">
Put extras and start Activity2 from Activity1 (if Activity2 was started before, intent will be sended to existing instance).
Intent intent = new Intent(getContext(), Activity2.class);
intent.putExtra("CHECK_POINT", checkPointData);
startActivity(intent)
Override method onNewIntent() in Activity2
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
onNewCheckPoint();
}
private void onNewCheckPoint(){
Intent intent = getIntent();
Bundle extras = intent.getExtras();
//in this moment, you can process data, like you want.
}

Android: Passing data between activities - multiple intent.putExtra not working?

Having a very annoying problem with passing data between activities.
This is the code I use to successfully pass the value of a progress bar to a different activity:
public void WhenClicked(View view)
{
view.clearAnimation();
Intent intent = new Intent("com.android.Test.QUESTION");
if (progressBar != null)
{
if (progressBar.getProgress() != 0)
{
intent.putExtra("ProgressBarValue", progressBar.getProgress());
}
}
startActivity(intent);
}
Okay, so that worked. Now, when I change it to this, it blows up:
public void WhenClicked(View view, String category)
{
view.clearAnimation();
Intent intent = new Intent("com.android.Test.QUESTION");
intent.putExtra("Category", category);
if (progressBar != null)
{
if (progressBar.getProgress() != 0)
{
intent.putExtra("ProgressBarValue", progressBar.getProgress());
}
}
startActivity(intent);
}
I don't understand what the problem is. I've even tried sticking it all into a bundle and adding the bundle as an extra - that just made it crash as well. Maybe I'm being stupid and I've just been staring at my code too long, but any help would be great!
This is my first time with Android and it's killing me!
Thanks in advance guys!
first you need to create bundle object(Bundle bnd=new Bundle();) and next bnd.putString("param1", "test");
next create intent:
Intent myIntent = new Intent(current classname.this,nextactivity.class);
myIntent.putExtras(bnd);
startActivityForResult(myIntent, 0);
In 2nd activity u need to get bundel value like :
Bundle bundle = this.getIntent().getExtras();
String _getData=bundle.getString("param1");
Assuming that you have an activity called QUESTION, you might try to put .class on the end as well as "this" for first param:
Intent intent = new Intent(this, QUESTION.class);
if you don't have a QUESTION activity then that is another problem. I'm assuming your activities are in the same app?
I believe, the activity which should handle this intent action com.android.Test.QUESTION does not understand your category i.e intent.putExtra("Category", category);.
You can try fixing it in 2 ways:
If the receiving activity is from your own application, then try using explicit intent i.e Intent intent = new Intent("youCurrentClass","theClassYouWantToCall"); without feeding additional category, this will launch the specified activity. In case of explicit Intent Android system does not do a comparison with the intent-filters to match Intent Object.
Change the category section in relation to intent receiving Activity.
Hope this helps,
sku

Categories