Focusing on text input field after opening activity from push notification - java

I have NoteListActivity, where I have search bar, that is called via method:
private void searchClicked(MenuItem item) {
searchText.setText(AppConstant.NULL_STRING);
searchBgr.setVisibility(View.VISIBLE);
searchText.requestFocus();
showKeyBoard();
}
And I need to open that specific method from notification bar.
I managed to open that specific activity, but I have no idea how to call method inside activity that I want to focus on.
This is the intent for notification bar activity:
Intent searchIntent = new Intent(context, NoteListActivity.class);
searchIntent.putExtra(AppConstant.FIXED_NOTIFICATION_SEARCH_KEY, true);
int searchPendingIntentId = AppConstant.FIXED_NOTIFICATION_SEARCH_ID;
PendingIntent searchPendingIntent = PendingIntent.getActivity(context, searchPendingIntentId, searchIntent,
PendingIntent.FLAG_UPDATE_CURRENT);

onCreate(){
if(getIntent().getBooleanExtra (AppConstant.FIXED_NOTIFICATION_SEARCH_KEY,false) ){
searchText.setText(AppConstant.NULL_STRING);
searchBgr.setVisibility(View.VISIBLE);
searchText.requestFocus();
showKeyBoard();
}
}

Related

Starting an Activity from a Notification and passing data onBackPressed

I have 3 Activities on the app:
MainMenuActivity -> ExecuteTrainingActivity -> ExecuteExerciseActivity.
From MainMenuActivity to ExecuteTrainingActivity, I'm passing an idExecution and an idExercise for ExecuteTrainingActivity query and load the initial data.
ExecuteTrainingActivity onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
initialize();
setupRecyclerView(exercises);
}
private void initialize() {
Bundle extras = getIntent().getExtras();
if (extras != null) {
if (extras.containsKey("id_execution")) {
idExecution = extras.getLong("id_execution");
idExercise = extras.getLong("id_exercise");
execution = queryExecution(idExecution);
} else {
insertExecution();
}
}
}
In the 3rd activity, ExecuteExerciseActivity, I have a TimerFragment that, and when TimerCountdown reaches 0, it opens a Notification popup, that when clicked open an fresh ExecuteExerciseActivity.
On this TimerFragment, I'm passing as Extras the same ids, so I can get them in the new fresh ExecuteExerciseActivity:
public class TimerFragment extends Fragment {
//...
private void showNotification(){
Intent intent = new Intent(getActivity(), ExecuteExerciseActivity.class);
intent.putExtra("id_execution", idExecution);
intent.putExtra("id_exercise", idExercise);
intent.putExtra("position", position);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getActivity());
stackBuilder.addNextIntentWithParentStack(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
/*=== CHECK IF NOTIFICATION CHANNEL IS ACTIVE ===*/
boolean ok = isNotificationChannelEnabled(getActivity(), Constants.CHANNEL_ID);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(requireNonNull(getActivity()), Constants.CHANNEL_ID)
.setSmallIcon(R.drawable.d77)
.setContentTitle("Teste Notificação")
.setContentText("Ababa")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
notificationManager.notify(0, mBuilder.build());
}
From this new fresh ExecuteExerciseActivity, I want to make the system maintain the same navigation flow of Activities, but when I backpress from the new ExecuteExerciseActivity to ExecuteTrainingActivity, i can't pass the Id's for the ExecuteTrainingActivity query and load.
Is there a way to pass arguments onBackPress?
Is the best approach override onBackPress creating a new intent and a starting a new Activity?
**My manifest is using parentActivityName correctly.
Save your query and id into a SharedPreferences in onDestroy of your ExecuteExerciseActivity then pull out the query and id again in the old ExecuteTrainingActivity. onBackPressed triggers onDestroy event of an activity's life cycle. Then in the onResume of ExecuteTrainingActivity pull this data back out.
I think you can achieve this by overriding onOptionsItemSelected() method of ExecuteExerciseActivity. Try this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent(this, ExecuteExerciseActivity.class);
//Add the extras to the intent
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
In Android, if your Activity starts another Activity and want to pass data to that Activity, you would add those data as Intent extras.
This Activity A to Activity B type of sending data is something you're using already.
But for Activity B back to Activity A, there's actually a built-in solution for this, which is through startActivityForResult(Intent, REQUEST_CODE) instead of startActivity(Intent).
Now in Activity B, you simply have to code:
#Override
public void onBackPressed()
{
Intent resultIntent = getIntent();
resultIntent.putExtra(EXTRA_NAME, extra_value);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
Basically, in Activity B, you're setting the data you want to send back to the Activity A that started Activity B, since there's a connection between these two Activities.
Next, in your Activity A, just override the onActivityResult() method.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// get data through data.getIntExtra() and etc
}
}
}
The request code needs to match the REQUEST_CODE you used for Activity B, so Activity A knows which Activity to respond to. The result code is just a quick way for you to categorize the type of result you're getting back from Activity B, since there might be more than one type of result being returned from Activity B.
This solution of passing data is better than creating a new Intent and starting a new Activity because you don't need to start a new Activity. Your Activity A already exists, so there's no reason to rebuild the entire layout, reload all the data, and have a new Activity existing on the Activity stack.
Since your only intention is to pass data from Activity B back to the Activity A that started it, use startActivityForResult() and onActivityResult() to handle this type of data sharing.

Redirect to activity with preserving/creating activity stack

I want to start activity from notification. I want to open an activity, which is successor of some other activities.
Example activities: IntroActivity -> Photos -> SpecificPhoto. What I want to achieve: In case user clicks on notification, I want to open SpecificPhoto activity. Keep in mind, that app can be running (for example PhotosActivity is displayed), or it can be shut down.
I want to preserve back button functionality (move to PhotosActivity on back pressed).
On notification click, I need to launch IntroActivity, because user needs to login here in case he is not.
I tried following (using constants in activities, code):
On PhotosActivity onCreate:
redirectToActivity();
RedirectToActivity method:
private void redirectToActivity() {
Intent intent = getIntent();
int activityCode = intent.getIntExtra("code", 0);
switch (activityCode) {
case SpecificPhotoActivity.CODE:
startActivity(new Intent(this, SpecificPhotoActivity.class));
break;
default:
return;
}
}
By applying this approach, I can traverse the whole activity stack and go to the activity I want. However, this approach is not working in every case. Sometimes, the activity_code is not set (don't know why) and therefore we end in the first activity.
Is there any more professional approach to solve this issue? I believe this must be solved somehow in many apps.
What you want is called TaskStackBuilder.
Here's how you should construct the intent, that would navigate to SpecificPhotoActivity:
Intent action = new Intent(context, SpecificPhotoActivity.class);
PendingIntent pendingIntent = TaskStackBuilder.create(context)
.addNextIntentWithParentStack(action)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
In order to correctly specify stack of activities, you should provide android:parentActivityName inside manifest file:
<application ...>
<activity android:name=".SpecificPhotoActivity"
android:parentActivityName=".PhotosActivity"/>
</application>
With this parameter you have specified, that the parent of SpecificPhotoActivity is PhotoActivity, thus TaskStackBuilder would understand where to navigate as soon as back button is clicked inside SpecificPhotoActivity.
Construction of the notification should be as follows:
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(...)
.setContentText(...)
.setSmallIcon(...)
.setContentIntent(pendingIntent)
.build();
manager.notify(NOTIFICATION_ID, notification);
Now notification click would open SpecificPhotoActivity. A click on back button would navigate to PhotosActivity.
What's left is authorization handling. I suppose you are able to apprehend whether user is authorized or no during the construction of the notification. Hence, following approach should work:
PendingIntent pendingIntent = null;
if (authorized) {
Intent action = new Intent(context, SpecificPhotoActivity.class);
pendingIntent = TaskStackBuilder.create(context)
.addNextIntentWithParentStack(action)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
} else {
Intent action = new Intent(context, IntroActivity.class);
action.putExtra("photos_flow", true);
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
}
Now, inside IntroActivity after successful authorization:
void onAuthorized() {
if(getIntent().getBooleanExtra("photos_flow", false)) {
// most possibly you should pass some id into SpecificPhotoActivity's intent
Intent[] intents = new Intent[]{new Intent(this, PhotosActivity.class), new Intent(this, SpecificPhotoActivity.class)};
startActivities(intents);
finish();
}
}

How to make a button in a notification 'do something'

I am trying to make a simple stopwatch app that will display the time in a notification and give you a couple buttons that will allow you to start and stop the stopwatch.
How do I add a button to a notification? And how do I 'point' that button to a certain function?
Heres a picture of what I was thinking:
actionIntent = new Intent(this, MainActivity.class);
actionPendingIntent = PendingIntent.getService(this, 0, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
timerNotification.addAction(android.R.drawable.ic_media_pause, "Start", actionPendingIntent);
This is what I currently have. Where in the intent would I put the function I want to execute?
Add Action to the notification and assign a pendingintent
If you want to custom your notification layout,you can use setContent() function with a RemoteViews of your custom layout.
Remote View mRemoteView = new RemoteViews(getPackageName(), R.layout.notification_general);
Notification.Builder mBuilder = new Notification.Builder(context);
mBuilder.setSmallIcon(R.mipmap.ic_battery)
.setContent(mRemoteView)
.setContentIntent(notificationPendingIntent);
mNotificationManager.notify(1, mBuilder.build());
To handle an notification button onClick event, you need to use separate PendingIntents(made from Intents with differecnt actions) for every button. Later in onReceive() you just check action of incoming Intent & execute different code depending on that. Remember to assign your Listener on manifest.
Intent generalIntent = new Intent(context, GeneralReceiver.class);
generalIntent.putExtra(REQUEST_CODE, ACTION_GENERAL);
PendingIntent generalPendingIntent =
PendingIntent.getBroadcast(context, 1, generalIntent, 0);
mRemoteView.setOnClickPendingIntent(R.id.btnNotificationGeneral, generalPendingIntent);
public static class GeneralReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Your code here
}
}

How to have a notification open a view within an activity?

Right now I have an alarm on my main activity which launches a class which launches a notification on the status bar. When I click on the notification, it opens up my main activity, now I want it to open a n specific view within that activity.
This is my notification code.
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
int icon = android.R.drawable.stat_notify_chat; // icon from resources
CharSequence tickerText = "TickerText"; // ticker-text
long when = System.currentTimeMillis(); // notification time
CharSequence contentTitle = "My notification"; // message title
CharSequence contentText = "Hello World!"; // message text
//This is the intent to open my main activity when the notification is clicked
final Intent notificationIntent = new Intent(context, mainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
// the next two lines initialize the Notification, using the configurations above
Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
mNotificationManager.notify(notifID, notification);
This is the button in the layout used by my main activity which opens the view I want the notification to open (graph view).
<Button
android:id="#+id/graphsButton"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_below="#id/reviewButton"
android:layout_toRightOf="#id/medicineButton"
android:onClick="openGraphs"
android:text="Graphs" />
When you click on the button. It executes the following method in the main class.
public void openGraphs(View v) {
canExit = false;
setContentView(R.layout.graphs);
}
So basically, I got the notification to open the app and launch the main activity, but I want it to launch the graph view directly.
Can anybody help me?
You could add a flag to the pending intent set in the notification using the intent's extras. Evaluate the intent when the activity is started. If you find the flag in the starting intent execute the the code in openGraphs(). Make sure to get the most recent intent (not the one which may have started the activity earlier, here is some advice on that: https://stackoverflow.com/a/6838082/1127492).
Is there anything stopping you from showing the graph directly in the Activity?
In the above Activity instead of having a button, to show the Graph when clicked, directly set the view to R.layout.graphs in onCreate() method.
In case you have the prescribed activity for some other purpose then create a separate activity just to show the graph and point to it from the notificationIntent.

notification opening a new window no matter what in Java Android

I want to launch a notification. When I click on it, it opens a NEW window of the app.
Here's my code:
public class Noficitation extends Activity {
NotificationManager nm;
static final int uniqueID = 1394885;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent= new Intent (Intent.ACTION_MAIN);
intent.setClass(getApplicationContext(), SchoolBlichActivity.class);
PendingIntent pi=PendingIntent.getActivity(this, 0, intent, 0);
String body = " body";
String title = "title!";
Notification n =new Notification(R.drawable.table, body, System.currentTimeMillis());
n.setLatestEventInfo(this, title, body, pi);
n.defaults = Notification.DEFAULT_ALL;
n.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(uniqueID,n);
finish();
}
by the way, if i add nm.cancel(uniqueID) before the finish(), it creates the notification and immediately deletes it...
Thanks for the help :D
You might want to just add a notification in the notification bar, and when the user clicks it, it will launch the actual Activity. This way the user won't be interrupted in whatever he's doing.
Create the status bar notification like this:
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.notification_icon, "Hello", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, myclass.class);
notification.setLatestEventInfo(getApplicationContext(), "My notification", "Hello world!", notificationIntent, PendingIntent.getActivity(this, 0, notificationIntent, 0));
mNotificationManager.notify(1, notification);
http://developer.android.com/guide/topics/ui/notifiers/notifications.html
Are you just trying to open a notification window in a current activity? Because if you are I dont think you need to launch it with an intent. You normally only use intents to launch new services or activities in your app unless youve built a custom view and activity/service which is to take place within the notification box. I see you have it set up in its own class which is fine but I think the way your doing it by default would open an entire new view.
If you need to launch a notification during a process or something like a button click you dont need to have the intent there.....or at least I never did :) What exactly are you trying to achieve with the notification.

Categories