Android popup style activity which sits on top of any other apps - java

What I want to create is a popup style application.
I have a service in the background - something arrives on the queue and i want an activity to start to inform the user - very very similar to the functionality of SMSPopup app.
So I have the code where something arrives on the queue and it calls my activity.
However for some reason the activity always shows on top of the originally started activity instead of just appearing on the main desktop of the android device.
As an example:
I have the main activity which is shown when the application is run
I have the service which checks queue
I have a popup activity.
When i start the main activity it starts the service - I can now close this.
I then have something on the queue and it creates the popup activity which launches the main activity with the popup on top of it :S How do I stop this and have it behave as i want...
The popup class is :
public class SMSPopup extends Activity implements OnClickListener{
public static String msg;
#Override
public void onCreate(Bundle bundle){
super.onCreate(bundle);
// Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
this.setContentView(R.layout.popup);
TextView tv = (TextView)findViewById(R.id.txtLbl);
Intent intent = getIntent();
if (intent != null){
Bundle bb = intent.getExtras();
if (bb != null){
msg = bb.getString("com.andy.tabletsms.message");
}
}
if(msg == null){
msg = "LOLOLOL";
}
tv.setText(msg);
Button b = (Button)findViewById(R.id.closeBtn);
b.setOnClickListener(this);
}
#Override
public void onClick(View v) {
this.finish();
}
}
and I call the activity from a broadcast receiver which checks the queue every 30 seconds or so :
if(main.msgs.size()>0){
Intent testActivityIntent = new Intent(context.getApplicationContext(), com.andy.tabletsms.work.SMSPopup.class);
testActivityIntent.putExtra("com.andy.tabletsms.message", main.msgs.get(0));
testActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(testActivityIntent);
}
The layout is here : http://pastebin.com/F25u6wdM

This is against the design practice suggested by Android. See http://developer.android.com/guide/topics/ui/notifiers/notifications.html
A background Service should never launch an Activity on its own in order to receive user interaction.
You could show the message in a Toast and/or notification. From the notification, you could start a new intent.

Related

Android exit whole program syntax

currently I'm working on Android development, now I'm facing a problem to exit the whole application that had launched.
I'v tried .finish(), but it doesn't show what I want.
I have 2 Activities, A and B. Activity A will forward to Activity B when button click. In activity B, when I click button "Exit" (that I created) with the listener to trigger .finish(), it just back to Activity A but not to close whole application (what I want is back to home screen directly and kill the background process as well).
How can I exit whole application wherever in the application? Thank you.
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
//here to exit whole application not just backwards to previous activity
}
});
You write in Activity A after
startActivity(new Intent(A.this, B.class))
finish()
then you also write in Activity B finish() on button click listener. It should works.
public class A extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(A.this, B.class));
finish(); // you must write this also in A activity to close whole application
}
});
}
public class B extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_1);
Button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
EDIT: I assumed there are cases when the underlying activity either should or shouldn't be terminated on return. This will allow you to handle both cases.
Case A)
Activity A starts activity B, which starts activity C. You want to close all of them from activity C. If they're all in the same task (i.e. probably your case) you can close the whole task by calling
finishAffinity();
According to docs this is what happens:
Finish this activity as well as all activities immediately below it in the current task that have the same affinity. This is typically used when an application can be launched on to another task (such as from an ACTION_VIEW of a content type it understands) and the user has used the up navigation to switch out of the current task and in to its own task. In this case, if the user has navigated down into any other activities of the second application, all of those should be removed from the original task as part of the task switch.
Note that this finish does not allow you to deliver results to the previous activity, and an exception will be thrown if you are trying to do so.
See Activity.finishAffinity().
Case B)
Activity A starts activity B, which starts activity C. You want to close activities B and C from activity C.
This is how you start activity C from B expecting and handling a result:
public class ActivityB extends Activity {
private static final int RC_ACTIVITY_C = 1;
public static final int RESULT_FINISH = 1;
...
public void startActivityC() {
Intent intent = new Intent(this, ActivityC.class);
startActivityForResult(intent, RC_ACTIVITY_C);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_ACTIVITY_C && resultCode == RESULT_FINISH) {
finish();
}
}
}
This is how you let activity B it has to finish from activity C. At any point before finishing activity C call:
setResult(ActivityB.RESULT_FINISH);
See Activity.startActivityForResult(Intent, int) and Activity.setResult(int).
You can try System.exit(0). That should do the job.
EDIT: Take a look at this post for the difference between finish() and System.exit(). Difference between finish() and System.exit(0)

How to display a toast message in only one activity?

In an application I am developing I have some code that attempts to submit information to the internet. If the connection can not be made, I pop up a toast message instructing the user to check the network connection.
Toast.makeText(getApplicationContext(), "Check network connection.", Toast.LENGTH_SHORT).show();
The problem I have is the toast message comes up no matter what the user is looking at! Even if the user is in a different app and my app is running in the background! This is not the desired behavior as I send a notification to the user if network activity fails. I only want the toast message to appear if the user is in the activity that is generating the network activity. Is there a way to do this?
If this is not possible my idea was to just put some kind of visual element in my activity - rather than display a toast message.
Thank You!
You can use a boolean class member in order to keep track of activity state changes.
public class YourClass extends Activity {
private boolean mIsResumed = false;
#Override
public void onResume() {
super.onResume();
mIsResumed = true;
}
#Override
public void onPause() {
super.onPause();
mIsResumed = false;
}
public boolean isResumed() {
return mIsResumed;
}
}
Then you can use something like this:
if (isResumed()) {
//show Toast
}
Use a dynamic BroadcastReceiver. Your background service will broadcast an Intent when something happens. All of your app's activities will register a dynamic BroadcastReceiver which will listen for these events. When such event occurs it will show a toast. When none of your activities are running nothing will happen.
Inside your service
public static final ACTION_SOMETHING = BuildConfig.APPLICATION_ID + ".ACTION_SOMETHING";
public void doSomething() {
// ...
// Show toast if app is running. Or let the app react however you please.
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_SOMETHING));
// ...
}
Of course you can put additional information in the Intent as extras and access them in the BroadcastReceiver.
Inside your activities
private final IntentFilter onSomethingIntentFilter = new IntentFilter(MyService.ACTION_SOMETHING);
private final BroadcastReceiver onSomething = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// This check seems redundant but it's not. Google it.
if (MyService.ACTION_SOMETHING.equals(intent.getAction()) {
// Show toast here.
}
}
};
public void onResume() {
super.onResume();
// Start listening for events when activity is in foreground.
LocalBroadcastManager.getInstance(this).registerReceiver(onSomething, onSomethingIntentFilter);
}
public void onPause() {
super.onPause();
// Stop listening as soon as activity leaves foreground.
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(onSomething);
} catch (IllegalArgumentException ex) {}
}
You may want to pull this code to a common activity parent, a BaseActivity, so you don't repeat yourself.
This is a common case of Provider-Subscriber pattern. Another implementation would be an EventBus.
Keeping it simple, try adding a boolean flag in Activity and set its value as true in onResume & false in onPause. Then display the toast if the boolean flag is true.

how to end an outgoing call after activity result?

I have a outGoingCall broadcast receiver.
basically I want it to intercept any outgoing call and show a dialog for certain pre-defined numbers.
so I made this broadcast init an activity which inits an FragmentDialog which init a AlertDialog.
When the user click "no"
I want to stop the call from happening.
I know setResultData(null); in the broadcast should do it.
But how can I pass the dialog result to the broadcast ?
there is no onActivityResult() in a broadcast.
I know how to pass it till the activity only.
fragmentDialog code:
public class YesNoDialogFragment extends DialogFragment {
private YesNoDialogFragmentListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
// Instantiate the NoticeDialogListener so we can send events to the
// host
mListener = (YesNoDialogFragmentListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
here is my activity code:
public class MainActivity extends FragmentActivity implements
YesNoDialogFragmentListener {
public static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showYesNoDialog();
}
#Override
public void onDialogPositiveClick() {
// how to send result to receiver ??
finish();
}
here is my receiver code:
#Override
public void onReceive(final Context context, final Intent intent) {
Log.v(Constants.LOGTAG, "OutgoingCallReceiver onReceive");
if (intent.getAction()
.equals(OutgoingCallReceiver.OUTGOING_CALL_ACTION)) {
Log.v(Constants.LOGTAG,
"OutgoingCallReceiver NEW_OUTGOING_CALL received");
// get phone number from bundle
String phoneNumber = intent.getExtras().getString(
OutgoingCallReceiver.INTENT_PHONE_NUMBER);
if ((phoneNumber != null)
&& phoneNumber
.equals(OutgoingCallReceiver.ABORT_PHONE_NUMBER)) {
Toast.makeText(
context,
"NEW_OUTGOING_CALL intercepted to number 123-123-1234 - aborting call",
Toast.LENGTH_LONG).show();
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
SharedPreferences sharedPreferences = context
.getSharedPreferences(Constants.SHARED_PREF_NAME,
Context.MODE_PRIVATE);
boolean isBloacked = sharedPreferences.getBoolean(
Constants.IS_NUMBER_BLOCKED, true);
if (isBloacked) {
// dialog and then:
setResultData(null);
}
}
as you can see i tried to share the activity result via shared preferences, how come the code is async and the setResultData(null); is called before the dialog is shown?
from what I know there is no way to end the call besides setResultData(null);
You have to go through an activity (or a fragment) and then pass it to the receiver. Whenever you start a dialog, it has a parent activity, and that is where the result is sent. Just add something to your activity that passes the result on to your receiver.
You might actually consider altering your design to put more of your logic into the activity. Receivers are generally intended to be pretty lightweight objects that receive notification of something, pass it on to somewhere else. and then go away. Anyway, I obviously don't know your code, so maybe this doesn't make sense.
EDIT
Sorry, I understand your problem better now. I'm used to only working with setResultData when one activity has launched another activity, and the 2nd one wants to send something back to the 1st one. But you are using it to stop an ordered broadcast, right?
Unfortunately, Android does now allow you to do what you are trying to do. This section of the doc specifically says that you cannot show a dialog from within a broadcast:
http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle
I think what you need to do is always return setResultData(null) right after starting your activity. If the user then clicks "no" in your dialog, then you are done. But if the user clicks "yes" (I'm assuming there is a "yes") then you would have to go ahead and make the call, and make sure you don't catch it again in your receiver.
Does that make sense? Sorry for my confusion earlier.

onBackPressed() not working while coming from another activity

I have three activities: First, Second and Third. I used this method in Second activity:
public void onBackPressed() {
super.onBackPressed();
finish();
}
and this on Third activity:
public void onBackPressed() {
super.onBackPressed();
Intent i = new Intent(Third.this, Second.class);
startActivity(i);
finish();
}
The problem is when I press back button after coming from the Third activity, I am going into First activity instead of finish(). I am successfully exiting the application when I click back button right after coming from first activity but not after coming from Third activity.
How to solve this problem?
EDIT: Thanks for the answers guys,the answer of "Ved Prakash" solved the problem for me.But i have a weird problem now.When i press back button the app is successfully exiting but the app which i minimized to Recent Apps button is coming on to the screen and exiting.For example,if i have opened Setting app before opening my app,when i press back button,my app is exiting and immediately Settings app is also opening and exiting itself.What might be the problem?
Your problem is that you don't seem to understand how Activities work. The finish() function ends the current Activity, and then you receive the previous Activity from the backstack.
My recommendation is that you should use a single Activity, and hold Fragments inside it. If you want it so that pressing the Back button ends the application at any screen that is displayed, you could do the following:
Activity XML:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/initial_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Activity that holds the Fragments:
public class InitialActivity extends FragmentActivity implements ReplaceWith
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_initial);
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
int backCount = getSupportFragmentManager().getBackStackEntryCount();
if (backCount == 0)
{
finish();
}
}
});
if (savedInstanceState == null)
{
getSupportFragmentManager().beginTransaction().add(R.id.initial_container, new FirstFragment()).commit();
}
}
#Override
public void replaceWith(Fragment fragment)
{
getSupportFragmentManager().beginTransaction().replace(R.id.initial_container, fragment).commit();
}
}
Example for a Fragment:
public class FirstFragment extends Fragment implements View.OnClickListener
{
private ReplaceWith activity_replaceWith;
private ImageView exampleImage;
public FirstFragment()
{
super();
}
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
activity_replaceWith = (ReplaceWith) activity;
}
catch (ClassCastException e)
{
Log.e(getClass().getSimpleName(), "Activity of " + getClass().getSimpleName() + "must implement ReplaceWith interface!", e);
throw e;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_first, container, false);
exampleImage = (ImageView) rootView.findViewById(R.id.fragment_first_example_image);
exampleImage.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v)
{
if(v == exampleImage)
{
activity_replaceWith.replaceWith(new SecondFragment());
//please note that this should be done only if you are planning
//only on single-screen applications
//with no other layouts based on orientation or size
//otherwise, the Activity needs to be responsible for this, not the Fragment
}
}
}
This way, when you press the Back button, your application would end from any displayed screen.
Ok your code is wrong.
If you will look at activity source, you see that activity.onBackPressed() is calling finish(). So if call super.onBackPressed() you don't need to call finish.
Finish() is not stopping your application, it's stopping current activity.
Your code on third activity very strange. You are trying to stop activity and start another same activity.
What exactly you want to achieve?
If you want to exit application from your third activity, you need to clear your backstack. But I think you have problem with structure of your app.
Ok. then you should finish your first activity when you go to second activity like this(If you are using intent for that):
Intent it=new Intent(FirstActivity.this,SecondActivity.class);
finish();
startactivity(it);
and same for Second Activity:
Intent it=new Intent(SecondActivity.this,ThirdActivity.class);
finish();
startactivity(it);
this done your work...when you are in third activity the above activities are finished..
and when you press backButton you will be exit from application..
Good luck.
You can use -
public static final int FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that
activity, 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.
And here is how -
When the user wishes to exit all open activities, they should press a button which loads the first Activity that runs when your app starts, in my case "MainActivity".
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);
The above code clears all the activities except for LoginActivity. LoginActivity is the first activity that is brought up when the user runs the program. Then put this code inside the LoginActivity's onCreate, to signal when it should self destruct when the 'Exit' message is passed.
if (getIntent().getBooleanExtra("EXIT", false)) {
finish();
}
This explanation part is also introduced at exit-an-android-app.

Android app shows screen before LoginActivity

I am making an Android app with authentication. The startup activity is MainActivity, but when a user is not logged in I start a new activity called LoginActivity.
My problem is that if a user is not logged in and starts the app, he see's a default android app screen (title bar and empty content area) for a split second before the LoginActivity launches.
How can I fix this?
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!userIsLoggedIn())
{
Intent LoginActivity = new Intent(getApplicationContext(), LoginActivity.class);
LoginActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(LoginActivity);
finish();
}
}
}
You can make your MainActivity translucent by setting the activity theme android:style/Theme.Translucent. Which makes the activity transparent so you won't see any thing till other activity starts.
But this has drawbacks. The animation that accours when you click to the application icon, you won't see that anymore and If your userIsLoggedIn() takes more than it should, it will look like the phone is froze for a second to the user.
For such situations, best practice is to have a splash screen activity or welcome screen activity appear as first screen for few seconds (1 or 2 sec). This screen is generally contains your company logo/image, like Facebook app. In this activity you put the logic to decide which activity to call next.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
if(alreadyLoggedIn)
startActivity(new Intent(SplashScreenActivity.this,MainActivity.class));
else
startActivity(new Intent(SplashScreenActivity.this,LoginActivity.class));
finish();
}
}, 1000);

Categories

Resources