I need to show a Pincode screen when the user is inactive for more than 1 minute.
I found this answer that gave me a good solution for my needs and I implemented it on my BaseActivity.
But now I am having a problem with the onUserInteraction() method, which is being called twice (and triggering my Runnable twice) everytime I press a button and start a new activity, because when I come back after 1 minute to the previous screen, the pincode screen is showing.
I've changed my Runnable to be static, but I lose the context to start the pincode activity.
What could I do to start the activity from the runnable or to make sure the onUserInteraction() is being triggered only when something is tapped on the screen?
My current code:
public class BaseActivity {
private static final String TAG = BaseActivity.class.getSimpleName();
static private Handler disconnectHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
private Runnable disconnectCallback = new Runnable() {
#Override
public void run() {
Intent intent = new Intent(BaseActivity.this, CustomPinActivity.class);
startActivity(intent);
}
};
public void resetDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
disconnectHandler.postDelayed(disconnectCallback, getResources().getInteger(R.integer.disconnect_timeout));
}
public void stopDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
}
#Override
public void onUserInteraction() {
resetDisconnectTimer();
}
#Override
protected void onResume() {
super.onResume();
resetDisconnectTimer();
}
#Override
public void onStop() {
super.onStop();
stopDisconnectTimer();
}
}
Manifest:
<activity
android:name=".CustomPinActivity"
android:launchMode="singleTop"
android:label="#string/title_activity_pincode" />
<activity android:name=".base.BaseActivity"
android:launchMode="singleTop" />
Well, I think the problem is the method onUserInteraction(). The documentation says:
All calls to your activity's onUserLeaveHint() callback will be accompanied by calls to onUserInteraction().
The link here. The documentation for onUserLeaveHint() says:
This callback and onUserInteraction() are intended to help activities manage status bar notifications intelligently; specifically, for helping activities determine the proper time to cancel a notification.
Second link here.
I understand, that onUserInteraction() method will be called each time an activity is paused, and before the pause. So I would use a flag like:
private boolean mStartingActivity;
private Runnable disconnectCallback = new Runnable() {
#Override
public void run() {
mStartingActivity = true;
Intent intent = new Intent(BaseActivity.this, CustomPinActivity.class);
startActivity(intent);
}
};
#Override
public void onUserInteraction() {
if(!mStartingActivity)
resetDisconnectTimer();
}
#Override
protected void onResume() {
super.onResume();
resetDisconnectTimer();
mStartingActivity = false;
}
I gess, there are more elegant solutions. I hope it helps.
Related
I want my app to close when I press the back button on MainActivity. Currently when I press it on MainActivity, it returns to previous activity.
#Override
public void onBackPressed() {
YourActivity.this.finish();
}
It's worth noting that changing the default behavior is not a good idea.
You can use System.exit(0).
#Override
public void onBackPressed() {
System.exit(0);
}
Why would you want your app to not go back to previous activities?
If your MainActivity is started by an activity you don't want to go back to, its better to add flags to the intent that started MainActivity so the previous activity would not stay in the Task-stack.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
If you dont want to do that, you must override the OnBackPress() to remove/finish the Tasks under the MainActivity in the stack.
This can be done with a LocalBroadcaster for example, even though its quite ugly.
In the activity you want to close:
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter("Your filter");
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, filter);
}
#Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
In your MainActivity:
#Override
public void onBackPressed() {
Intent intentBroadcast = new Intent("Your filter");
LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(intentBroadcast);
finish();
}
I am learning Android concepts Activity and BroadCastReceiver. I want to update the content of Activity from the BroadtCastReceiver both are in different java class.
It is something like
MyActivity.java and MyBroadtCastReceiver.java
Is this possible to do this in Android ?
A BroadcastReceiver can be used in many ways but when it comes to something as specific as updating the UI components of an Activity, there is little advantage to declaring / defining a BroadcastReceiver in it's own Java class file.
Reasoning - the BroadcastReceiver has to have some prior "knowledge" of the Activity and what it is required to do in order to update the UI. In effect the BroadcastReceiver is tied to the Activity itself and it makes sense to declare / define it as an inner class.
Another important aspect is the Activity needs to be in a "running" (i.e., visible) state in order to guarantee manipulation of UI components. In this case, registering the receiver in onResume() and unregistering in onPause() will help prevent problems.
Using a generic template I'd do something like the following...
class MyActivity extends Activity {
boolean mIsReceiverRegistered = false;
MyBroadcastReceiver mReceiver = null;
// onCreate(...) here
#Override
protected void onResume() {
// Other onResume() code here
if (!mIsReceiverRegistered) {
if (mReceiver == null)
mReceiver = new MyBroadcastReceiver();
registerReceiver(mReceiver, new IntentFilter("YourIntentAction"));
mIsReceiverRegistered = true;
}
}
#Override
protected void onPause() {
if (mIsReceiverRegistered) {
unregisterReceiver(mReceiver);
mReceiver = null;
mIsReceiverRegistered = false;
}
// Other onPause() code here
}
private void updateUI(Intent intent) {
// Do what you need to do
}
private class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
}
}
EDIT: A couple of extra notes...
The life-cycle of a BroadcastReceiver is between entering and leaving onReceive(...). Once it has returned from onReceive(...) the instance remains in a dormant state waiting for the next broadcast.
Directly related to point 1 - a BroadcastReceiver isn't designed for "heavy lifting". Basically the onReceive(...) method should be kept as simple as possible. Any methods it calls should also be as light-weight as possible...get in, do your stuff, get out then wait for the next broadcast. If updating the UI is going to take some time (perhaps updating a ListView by re-querying a database for a large amount of data for example), consider calling code which performs asynchronously (an AsyncTask for example).
Yes its possible. This is what i do.
Class i send the broadcast from (BackgroundActivity.java):
public static final String BROADCAST_BUFFER_SEND_CODE = "com.example.SEND_CODE";
onCreate(){
bufferIntentSendCode = new Intent(BROADCAST_BUFFER_SEND_CODE);
}
private void sendBufferingBroadcastSendCode() {
bufferIntentSendCode.putExtra("buffering", "1");
sendBroadcast(bufferIntentSendCode);
}
The class it will receive the broadcast(SendCode.java):
onResume(){
registerReceiver(broadcastBufferReceiver, new IntentFilter(BackgroundActivity.BROADCAST_BUFFER_SEND_CODE));
}
// set up broadcast receiver
private BroadcastReceiver broadcastBufferReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent bufferIntent) {
SendCode.this.LoadMessages(alarmNumber);
}
};
I unregister it in onPause
this.unregisterReceiver(broadcastBufferReceiver);
Register a new BroadcastReceiver object in your activity with same intent-filters as your MyBroadtCastReceiver. Since BroadcastReceiver and MyBroadtCastReceiver has same intent-filters both of their onReceive() will be invoked. Whatever update that you want to do in Activity can be done in onReceive of your BroadcastReceiver.
You can do like this:
public class MyActivity extends Activity{
// used to listen for intents which are sent after a task was
// successfully processed
private BroadcastReceiver mUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
new UpdateUiTask().execute();
}
};
#Override
public void onResume() {
registerReceiver(mUpdateReceiver, new IntentFilter(
YOUR_INTENT_ACTION));
super.onResume();
}
#Override
public void onPause() {
unregisterReceiver(mUpdateReceiver);
super.onPause();
}
// used to update the UI
private class UpdateUiTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... voids) {
Context context = getApplicationContext();
String result = "test";
// Put the data obtained after background task.
return result;
}
#Override
protected void onPostExecute(String result) {
// TODO: UI update
}
}
}
Squonk-s answer only works, if the Activity is active currently.
If you dont want to declare / define your BroadcastReceiver (BR) in an other Activity, or if you want to make some changes even if the app is not foreground, than your solution would look something like this.
First, you declare the BR, and save, or override the data needed to show in Acitvity.
public class MyBR extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// override the data. Eg: save to SharedPref
}
}
Then in Activity, you show the data
TextView tv = findViewById(R.id.tv);
tv.setText(/*get the data Eg: from SharedPref*/);
And you should use a Timer to refresh the tv as well:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView tv = findViewById(R.id.tv);
tv.setText(/*get the data Eg: from SharedPref*/);
}
});
}
}, REFRESH_RATE, REFRESH_RATE);
REFRESH_RATE could be something like 1 second, but you decide.
try like this it may help you.
Define this method in activity's oncreate method in which you want to update ui,
BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//your code to update ui
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("giveyourappname"));
Define this action at place from where you want to update ui,
try{
ActivityManager am = (ActivityManager) this .getSystemService(ACTIVITY_SERVICE);
List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
Log.d("Activity", "Current Activity ::" + taskInfo.get(0).topActivity.getClassName());
Log.d("Package", "Package Name : "+ componentInfo.getPackageName());
if(componentInfo.getPackageName().equals("your application package name")){
Intent intent = new Intent("giveyourappname");
//add data you wnat to pass in intent
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}catch(Throwable e){
e.printStackTrace();
}
In my app, whenever I receive a push notification, I will perform a check if my mainActivity is visible to the user to do something...
I have a static boolean value that is set true inside onResume of mainActivity, and false inside it's onPause.
What should I do inside the onMessage
#Override
protected void onMessage(Context context, Intent intent)
{
if(mainActivity == visible)
//do something inside mainactivity.. change text inside edittext
else
//do something else
}
any insights ?
I'm not a fan of keeping static references to activities. I think they're a can of worms ready to explode on you. So you'll suggest an alternative to #TeRRo answer:
on your global BroadcastReceiver onMessage you'll send a LocalBroadcast that your activity will be listening to. Like this:
private static final String ACTION_PUSH_RECEIVED = "com.myapp.mypackage.action.pushReceived";
public static final IntentFilter BROADCAST_INTENT_FILTER = new IntentFilter(ACTION_PUSH_RECEIVED);
#Override
protected void onMessage(Context context, Intent intent) {
Intent i = new Intent(ACTION_PUSH_RECEIVED);
i.putExtra( ... add any extra data you want... )
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
}
and now we make the activity listen to it:
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(context)
.registerReceiver(mBroadcastReceiver, BroadcastReceiverClass.BROADCAST_INTENT_FILTER);
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(context)
.unregisterReceiver(mBroadcastReceiver);
super.onPause();
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
// read any data you might need from intent and do your action here
}
}
To avoid this, you should manage activities references. Add the name of the application in the manifest file:
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (currActivity != null && currActivity.equals(this))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just extend MyBaseActivity. Now, you can get your current activity from application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
Or why don't you use the Local broadcasts when you receive the push notification, and receive it in your activity, and do respective changes or actions.
And if they are UI intensive tasks, bind your activity to a service, and receive the push notification and perform the action in this service and use the result in the activity.
In my application, there is a service class. I want to start an intent 10 seconds later with this service. When I try a basic toast message instead of starting intent, it works. However, when I write startActivity(intent) an error occurs. Here is my code. Where am I making mistake?
public class EkraniKilitle extends Service {
Handler yardimci;
Intent kilitEkrani;
final static long ZAMAN = 10000;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
kilitEkrani = new Intent(EkraniKilitle.this, KilitEkrani.class);
yardimci = new Handler();
yardimci.postDelayed(new Runnable() {
#Override
public void run() {
servisiDurdur();
startActivity(kilitEkrani);
}
}, ZAMAN);
}
public void servisiDurdur() {
stopService(new Intent(this, EkraniKilitle.class));
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
i guess you need to add your second activity to the manifest
after </activity> add <activity android:name=".MySecondClass"/>
Call startActivity(kilitEkrani); before servisiDurdur(); and to stop your current service all what you need is to call stopSelf() you do not have to use stopService
I have a BroadCastReceiver that is listen for incoming short messages. In SmsReceiver I want to start an Activity to process the sms. In many situation the Activity is running while getting message and I don't want to start it again.
In fact I want to see that if that Activity is already running (visible or not killed yet) just take it to front and otherwise start it with new task.
Any idea?
I mixed some ideas from here and other places and finally solved the problem. I write the solution here for other people that may have similar situations:
In amy Activity:
static boolean isRunning = false;
#Override
public void onStart() {
super.onStart();
isRunning = true;
}
public void onStop() {
isRunning = false;
super.onStop();
}
public static boolean isRuuning() {
return isRunning;
}
#Override
public void onCreate(Bundle savedInstanceState) {
smsReceiver = new SmsReceiver();
smsReceiver.setActivity(this);
// ...
}
Inside my SmsReceiver:
static MyActivity myActivity;
public void setActivity(MyActivity MyActivity) {
SmsReceiver.myActivity = myActivity;
}
if( MyActivity.isRuuning() ) {
SmsReceiver.myActivity.receiveNewMessage(smsBody);
} else {
// Create an intent and start it
}
This works fine for me.