I have registered my activity to handle the ACTION_DIAL intent but in certain cases I want to basically ignore the intent. In onCreate, I'm checking SharedPreferences for a bool that means user has access to dial, if not then I call finish() and then return; But this still shows a window flashing open and then closed, how can I avoid that?
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean hasDialer = prefs.getBoolean(Preferences.HAS_DIALER, false);
// Check if ACTION_DIAL intent was launched to bring user into the app
String number = getIntent().getDataString();
if (!TextUtils.isEmpty(number))
{
if (hasDialer)
{
launchDialer = true;
}
else
{
finish();
return;
}
}
}
You could register the ACTION_DIAL in a broadcast receiver (directly in the manifest) or in a service (now this depends on what else are you planning to do) and have the same logic in there. You can start activities from there if you need to.
Related
Here is the use case:
1. User logs into the app and presses the hardware home button and app is sent to background
2. I run a handler in the background to check if the inactivity time out is 5 mins. Then I need to call the logout API and start the loginactivity, Without launching or bringing the app to foreground
Here is what I have tried
if (!mIsAppInForeground) {
Log.d("App in background", "App in background and timing out");
activity.startService(new Intent(activity,LogOutBackGroundService.class).addFlags( Intent.FLAG_ACTIVITY_MULTIPLE_TASK ));
}
public class LogOutBackGroundService extends Service {
public static final String HAS_SIGNED_OUT = "hasSignedOut";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
intent.putExtra(HAS_SIGNED_OUT, true);
startActivity(new Intent(this, LoginActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
The app is timing out properly and login activity is being launched, but the app is being brought to foreground (i.e app is being launched). I want this to happen in the background only. Only when the user relaunches the app, he should see the login screen again
startactivity(intent) pops up the backstack activity or creates a new one if it doesn't exist.. so your solution is there is onResume() and onPause().. onPause() is called when you the activity is gone, onResume() is called when you see the activity, so my advice to you is create a boolean, it can be in a singleton class
public class MySingletonClass {
public static boolean startloginpage; // by default its false
}
then you in mainactivity or the activity that the user will launch or come back to, put the code in its onresume
#Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
if(MySingletonClass.startloginpage){ //check if your boolean is true
// if it checks out then call do what you want to do when the user times run out
}else{
// if it doesn't check out continue without telling user to login,
}
}
in your service remove the intent code and put this
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
intent.putExtra(HAS_SIGNED_OUT, true);
MySingletonClass.startloginpage = true;
return START_NOT_STICKY;
}
In a typical logout scenario , clicking on logout button should just start the login activity clearing the login details. In your case after 5 mins you should try to clear the stored token for login ( assuming you store the login details for the user to login automatically when required). When the user launches the app next time your LAUNCHER activity would check for the stored token to launch the required activity.
Currently when I run my application and if phone rings , phone get preference and my application is killed. Is there any way either my application takes a preference i.e. let phone call to hit voice mail or shift my app to background for short period of time , till user take a call , and bring back to foreground once he complete. thanks
you can do one thing. You can pause your application during the incoming call and after that, resume the application from the same place. I know this is not the exact solution of your issue but somehow, it will reduce your work load. hope this will help.
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
// needed for logging
String TAG = "PhoneCallListener";
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
// phone ringing
Log.i(TAG, "RINGING, number: " + incomingNumber);
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// active
Log.i(TAG, "OFFHOOK");
isPhoneCalling = true;
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// run when class initial and phone call ended,
// need detect flag from CALL_STATE_OFFHOOK
Log.i(TAG, "IDLE");
if (isPhoneCalling) {
Log.i(TAG, "restart app");
// restart call application
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
isPhoneCalling = false;
}
}
}
}
and also add this permission to manifest.xml file
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
I had come across a similar issue, resolved this by overriding onPause() and onResume() methods, save all the required variables in onPause() and restore these in onResume().
#Override
protected void onResume(){
super.onResume();
load();
}
#Override
protected void onPause(){
super.onPause();
save();
}
private void save() {
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("DeviceName", deviceName);
editor.putString("ConnectOption", connectOption.toString());
editor.commit();
}
private void load() {
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
deviceName = sharedPreferences.getString("DeviceName","");
String connectop = sharedPreferences.getString("ConnectOption","USB"); //You could provide a default value here
}
I think this is the default feature of android that any application
go inactive if incoming call is in active. We cannot change this.
While the user is in the phone call, though, they can change to another
app simply by pressing the home button and starting another app from
the home screen, or by double-pressing the home button and switching to another app, including yours.
I make a phone call from an Activity and when call ends I want to come back to application. I tried all the solutions available on stackoverflow. One of them used to work for few minutes but not working now.
I tried using recreate() method which successfully calls onCreate method of an Activity but app is not in foreground. I tried using various flags such as FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_CLEAR_TASK, FLAG_ACTIVITY_NO_HISTORY. But does not work.
Code to go back to application from call app :
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
#Override
public void onCallStateChanged(int state, String incomingNumber) {
// If call ringing
if (state == TelephonyManager.CALL_STATE_RINGING) {
}
// Else if call active
else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
isPhoneCalling = true;
}
// Else if call idle
else if (state == TelephonyManager.CALL_STATE_IDLE) {
if (isPhoneCalling) {
isPhoneCalling = false;
MyActivity.this.recreate();
}
}
}
}
This is my solution, it works perfectly on 4.3 - other OS versions not tested yet, but everything should be fine.
Registering the listener in MainActivity:
TelephonyManager tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
listener = new ListenToPhoneState();
tManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
The PhoneStateListener from MainActivty:
private class ListenToPhoneState extends PhoneStateListener {
private String LOG_TAG = "mainactivity";
private boolean isCallFinished = false;
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// wait for phone to go offhook (probably set a boolean flag) so
// you know your app initiated the call.
isCallFinished = true;
Log.i(LOG_TAG, "OFFHOOK");
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// when this state occurs, and your flag is set, restart your
// app
if (isCallFinished) {
isCallFinished = false;
Intent i = new Intent(getApplicationContext(),
MainActivity.class);
// this needs if you want some special action after the phone call
//ends, that is different from your normal lauch configuration
i.setAction("SHOW_PHONE_CALL_LIST");
startActivity(i);
finish();
}
Log.i(LOG_TAG, "IDLE");
}
}
}
I start the phone call from a fragment, but that doesn't make any difference:
Uri uri = Uri.parse("tel:" + Uri.encode(callIt));
Intent intent = new Intent(Intent.ACTION_CALL, uri);
startActivity(intent);
getActivity().finish();
You have to call finish() on the activity that starts the call, otherwise after the phone call, your app will stay behing the default Phone application.
When your app is starting, you can have a look at the intent, and you can set up your after call configuration. Call this in your onCreate() method:
if (intent.getAction().equals("SHOW_PHONE_CALL_LIST")) {
//perfom after call config here
}
I hope everything is clearly explained.
I think you must use a broadcast receiver and start the activity upon uphook. Also you need to declare permissions to read phone state.
Try to modify your code, that the important stuff is not in the onCreate() method but in the onResume() method, because when you come back from the phone call, the onCreate() method will not be triggered but the onResume() method. See http://developer.android.com/reference/android/app/Activity.html for more details on the Activity live cycle.
If that still does not help, use the flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
Try to use a context from the listener. Either the listener directly provides a context (so you can just call startActivity(…) or call getApplicationContext().startActivity(…)
In the end your code should something like this:
Intent intent = new Intent(RS_HomeScreenActivity.this,RS_HomeScreenActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
The solution is to launch an application with an extra included in bundle that says that app is launched as part of coming back from any other app.
When call ends, I launch an app using below code :
// Launch app
Intent i = new Intent(ActivityThatMadeCall.this,
LauncherActivity.class);
i.putExtra("EXTRA_RETURNED_FROM_CALL_APP", true);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
Then in my launcher activity I check for the extra and if it exists then start the activty that placed call. :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(getIntent().getExtras().getString("EXTRA_RETURNED_FROM_CALL_APP") != null) {
startActivity(new Intent(this, ActivityThatMadeCall.class));
}
}
I am creating simple widget for contact management, which allows user to dial and send sms to desired contact.
It works fine as "normal widget", but when I add it as lockscreen widget on Android 4.2, sms app or dial app does not start.
Well in fact they star, but "behind" lockscreen, so user still must manually unlock screen to be able to dial/send sms.
I searched web for some solution, but nothing come in handy.
I' am aware of FLAG_DISABLE_KEYGUARD or FLAG_SHOW_WHEN_LOCKED, but since sms/dial apps are not "mine" so i dont know if they set up proper flag.
As a workaround i tried to create my activity which set those flag and then simply starts desired one (dial or sms), but this does not help.
There is a way to unlock screen, but this involves using KeyguardManager and KeyguardLock (which work fine), but in a result of using KeyguardLock.newKeyguardLock() I end up with phone not being able to turn lock automatically, surely because I do not release this lock (it causes lock to appear again, which is not what i want).
In fact, this widget should work simmilarly to default sms widget or mail widget on lock screen?
So, my question is, how to achieve that and start new activity from lockscreen?
Well, i found solution myself. it turned out i was close :)
To launch 3rd party app/activity, simplest solution is to create some kind of proxy activity, which will set proper flags on window and then launches desired activity and FINISHES.
sample code is shown below:
calling intent in widget (calling proxy):
#Override
public void onReceive(Context context, Intent intent) {
Utilities.printLog(TAG, "onReceive");
Utilities.printLog(TAG, "intent: " + intent);
if (intent.getAction().equals(ACTION)) {
final String number = intent.getStringExtra(EXTRAS);
Toast.makeText(context, "Selected number: " + number,
Toast.LENGTH_SHORT)
.show();
/** REMOVING KEYGUARD RECEIVER **/
// not really an option - lock is still holded by widget and screen
// cannot be locked again ;(
// KeyguardManager keyguardManager = (KeyguardManager) context
// .getSystemService(Context.KEYGUARD_SERVICE);
// KeyguardLock lock = keyguardManager
// .newKeyguardLock(Context.KEYGUARD_SERVICE);
// lock.disableKeyguard();
final Intent activity = new Intent(context, MainActivity.class);
activity.putExtras(intent.getExtras());
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
activity.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(activity);
}
super.onReceive(context, intent);
}
in proxy activity just call:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
final Intent callingIntent = getIntent();
final String actionToLaunch = callingIntent.getStringExtra(ContactsStackWidgetProvider.ACTION);
final String number = callingIntent.getStringExtra(ContactsStackWidgetProvider.EXTRAS);
final Intent activity = new Intent();
if (actionToLaunch.equals(Intent.ACTION_DIAL)) {
activity.setAction(Intent.ACTION_DIAL);
activity.setData(Uri.parse("tel:"+number));
} else if (actionToLaunch.equals(Intent.ACTION_SENDTO)) {
activity.setAction(Intent.ACTION_SENDTO);
activity.setData(Uri.parse("sms:"+number));
} else {
throw new IllegalArgumentException("Unrecognized action: "
+ actionToLaunch);
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(activity);
finish();//it is important to finish, but after a small delay
}
}, 50L);
}
I have an activity with a checkbox: if the chekbox is unchecked then stop the service. this is a snippet of my activity code:
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.android.savebattery.SaveBatteryService");
if (*unchecked*){
serviceIntent.putExtra("user_stop", true);
stopService(serviceIntent);
when I stop the service I pass a parameter "user_stop" to say at the service that has been a user to stop it and not the system (for low memory).
now I have to read the variable "user_stop" in void onDestroy of my service:
public void onDestroy() {
super.onDestroy();
Intent recievedIntent = getIntent();
boolean userStop= recievedIntent.getBooleanExtra("user_stop");
if (userStop) {
*** notification code ****
but it doesn't work! I can't use getIntent() in onDestroy!
any suggestion?
thanks
Simone
I see two ways of doing this:
Using Shared Preferences.
Using local broadcasts.
The first approach is an easy and straightforward way. But it is not very flexible. Basically you do:
a. Set "user stop" shared preference to true.
b. Stop service
c. In you service in onDestroy check what is the value of "user stop" preference.
The other approach is a better way but requires more code.
a. Define a string constant in you service class:
final public static string USER_STOP_SERVICE_REQUEST = "USER_STOP_SERVICE".
b. Create an inner class BroadcastReceiver class:
public class UserStopServiceReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
//code that handles user specific way of stopping service
}
}
c. Register this receiver in onCreate or onStart method:
registerReceiver(new UserStopServiceReceiver(), newIntentFilter(USER_STOP_SERVICE_REQUEST));
d. From any place you want to stop your service:
context.sendBroadcast(new Intent(USER_STOP_SERVICE_REQUEST));
Note that you can pass any custom arguments through Intent using this approach.
I don't think relying on onDestroy() is a good thing. There are couple of approaches you can take.
suggest to bind the service so that you could write your userstop notification in onUnbind http://developer.android.com/guide/topics/fundamentals.html#servlife
Other option (not sure if this works) is to post your variable to SharedPreferences and obtain it from onDestroy(). [You need to check if this works in debug mode or LogCat messages.
I have the same setup in my app using CheckBoxPreference in my activity and getSharedPreference in service class's onCreate. Checking the checkbox starts the service. Unchecking stops the service.
Listen and handle preference click in my Activity:
getPreferenceManager().findPreference("prefEnable").setOnPreferenceClickListener(new OnPreferenceClickListener()
{
// not used: Intent intent = new Intent(this, MyService.class);
#Override
public boolean onPreferenceClick(Preference preference) {
CheckBoxPreference cb = (CheckBoxPreference) preference;
if (cb.isChecked()) {
Log.d(TAG, "User enabled service");
// code to start service
} else {
Log.d(TAG, "User disabled service");
// code to stop service
}
return true;
}
});
Get my "prefEnable" preference within my service onCreate:
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
Boolean isEnabled = preferences.getBoolean("prefEnable", false);
Perhaps in your onDestroy, you can re-purpose this and say:
if (isEnabled==false) {
*** notification code ***
// You can pass the parameter in this simple way:-
Intent serviceIntent = new Intent(this,ListenLocationService.class);
serviceIntent.putExtra("From", "Main");
startService(serviceIntent);
//and get the parameter in onStart method of your service class
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Bundle extras = intent.getExtras();
if(extras == null)
Log.d("Service","null");
else
{
Log.d("Service","not null");
String from = (String) extras.get("From");
if(from.equalsIgnoreCase("Main"))
StartListenLocation();
}
}
Enjoy :)