I am a bit inexperienced programmer. I am working on an android project which will play specific video in some cases. My client have defined some square zones on a map which my app saves these zones in database. Each zone has four components : Min and Max of Lat and Lng. I keep track of the current location of the user via GPS(and offline). My goal is to check if the user is inside one of defined zones, if yes video will be played, else nothing. This checking process should be done every second so it must be optimized. my question is : what is the best algorithm ? How to implement this algorithm in order to check between zones as fast as possible ? Any help would be greatly appreciated.
You can use a service like this
public class YourService extends Service {
private final static String TAG = "yourtag";
public static final String YOURTIMEOUT = "com.example.timeout";
public static final String TIMER = "com.example.timer";
private Intent bi = new Intent(YOURTIMEOUT );
private CountDownTimer cdt = null;
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction(YOURTIMEOUT );
registerReceiver(receiver, filter);
}
private void newCountdown() {
cdt = new CountDownTimer(1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
sendBroadcast(bi);
}
};
cdt.start();
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case YOURTIMEOUT :
newCountdown();
break;
}
}
};
#Override
public void onDestroy() {
cdt.cancel();
unregisterReceiver(receiver);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
newCountdown();
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
Obviously this is every second so there's no point for the countdown, but if you decide to change the every second part then it comes quite handy.
Get your interested activity to catch the intent with YOURTIMEOUT tag and run your checking code when you get it. Make sure to stop the service when your activity goes on pause.
Related
I have MainActivity and on its onResume method I call pattern lock to create and confirm user identity. User visits and leave this MainActivity back and forth while active on the app as well as when phone is in sleep mode and user unlocks it. These both scenarios will call onRestart, onStart and onResume methods, but I only want to revoke the pattern in unlock scenario.
handlePattern() method needs a proper distinguishing to be called.
How to distinguish this when I call the handlePattern method ?
MainActivity.class
onCreate(){}
onResume(){
//help needed to know that user is just visiting activity in app back and forth
or came back after unlocking the screen.
if(isPatternCallRequired){
handlePattern()
}
}
In your onStop() method call you can check if the player is in sleep mode and cache the boolean.
PowerManager pm = (PowerManager)
_context.getSystemService(Context.POWER_SERVICE);
boolean isInSleepMode = !pm.isScreenOn();
Check for the build version
if( Build.VERSION.SDK_INT >= 20)
// use isInteractive()
else
// use isScreenOn()
in onRestart which will get called when you resume from sleep - based on the cached value you can show the pattern to unlock.
You may need to reset the cached value once you are done using it.
onResume may not be a right API for the call as it will be called even when your activity loads.
Edited answer based on your comment
You can try ActivityLifecycleCallbacks too like this,
First, Register your Application in your Application class.
public class StackApp extends Application {
private static final String TAG = StackApp.class.getSimpleName();
public static final String INTENT_ACTION_APP_STATE_CHANGE = "intent_action_app_state_change";
public static final String INTENT_DATA_IS_IN_BACKGROUND = "intent_data_is_in_background";
private static int mNumRunningActivities = 0;
private static AtomicBoolean mIsAppInForeground = new AtomicBoolean();
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= 14) {
// registerActivityLifecycleCallbacks is supported only from the SDK version 14.
registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
mNumRunningActivities++;
if (mNumRunningActivities == 1) {
notifyAppState(false);
Log.i(TAG, "APP IN FOREGROUND");
}
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
mNumRunningActivities--;
if (mNumRunningActivities == 0) {
notifyAppState(true);
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
/**
* To notify App state whether its in ForeGround or in Background
*
* #param isInBackground
*/
private void notifyAppState(boolean isInBackground) {
if (isInBackground) {
mIsAppInForeground.set(false);
} else {
mIsAppInForeground.set(true);
}
sendAppStateChangeBroadcast(isInBackground);
}
public static boolean isInForeground() {
return mIsAppInForeground.get();
}
private void sendAppStateChangeBroadcast(boolean isInBackground) {
Log.i(TAG, "sendAppStateChangeBroadcast - isInBackground : " + isInBackground);
Intent intent = new Intent();
intent.setAction(INTENT_ACTION_APP_STATE_CHANGE);
intent.putExtra(INTENT_DATA_IS_IN_BACKGROUND, isInBackground);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
And register the broadcast and listen whether the App is going background or foreground like this Sample Activity example
public class SampleMyActivity extends AppCompatActivity {
private OnAppStateReceiver mAppStateReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_my);
mAppStateReceiver = new OnAppStateReceiver();
IntentFilter filter = new IntentFilter(StackApp.INTENT_ACTION_APP_STATE_CHANGE);
LocalBroadcastManager.getInstance(this).registerReceiver(mAppStateReceiver, filter);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mAppStateReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mAppStateReceiver);
}
}
private class OnAppStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!TextUtils.isEmpty(action) && StackApp.INTENT_ACTION_APP_STATE_CHANGE.equalsIgnoreCase(action)) {
boolean isGoingBackground = intent.getBooleanExtra(StackApp.INTENT_DATA_IS_IN_BACKGROUND, false);
if (isGoingBackground) {
//Your app is not vissible to the use
} else {
// App is visible to the user.
}
}
}
}
}
Note: If you want to listen in Multiple Activity you can create a base
class and add the listener there and you can do the operation, In that
case you can reduce a lot of code.
I had previously managed to get my service to continue running. But today after I went back to the application to keep working with the app I noticed that the service gets disconnected after the app is closed which was not happening before.
I start the service in my main activity like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
setContentView(R.layout.activity_main);
Intent i = new Intent(MainActivity.this, SystemWebService.class);
SystemWebService.setMain(this);
MainActivity.this.startService(i);
}
The code in the SystemWebService class looks like this:
public class SystemWebService extends Service {
private static WebView webdemo;
private static MainActivity ma;
//Context dex;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
// let the service continue until stopped
Toast.makeText(this, "Service has started", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onDestroy(){
super.onDestroy();
Toast.makeText(this, "Service has been destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public void onCreate() {
super.onCreate();
}
public static void setMain(MainActivity a) {
ma = a;
SystemWebService sws = new SystemWebService();
sws.setView();
}
}
This is the code that sets the webview
public void setView() {
webdemo = (WebView) ma.findViewById(R.id.webdemo);
webdemo.addJavascriptInterface(new SystemWebService.WebAppInterface(this), "Android");
webdemo.setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest url){
return false;
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
webdemo.getSettings().setJavaScriptEnabled(true);
webdemo.getSettings().setDomStorageEnabled(true);
webdemo.getSettings().setAllowFileAccessFromFileURLs(true);
webdemo.getSettings().setAllowUniversalAccessFromFileURLs(true);
}
webdemo.loadUrl("file:///android_asset/_wv.html");
}
The webview establishes a connection to our server and I would normally see data display on the logs. Before I would continue to see the flux of data passing even after the application was closed but as of right not I am not seeing anything, only the message "Application terminated".
I can't seem to understand what is happening.
Passing a reference of your activity to the service, and keeping a static instance of it is not the recommended way of development. It can lead to unexpected behaviour during the life cycle of your activity or the service.
Use the Bound Services instead. Check the documentation here : https://developer.android.com/guide/components/bound-services.html
I'm making a litle game in android studio where I want background music to play when the user is interacting with the application (and have it turned on in the settings). For this I used a service for playing backgroundmusic. As you can see below
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class BackgroundMusicService extends Service {
MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this, R.raw.backgroundmusic);
player.setLooping(true); // Set looping
}
public int onStartCommand(Intent intent, int flags, int startId) {
player.start();
return 1;
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
#Override
public void onLowMemory() {
}
}
I want my backgroundmusic to play on all my activities, but stop when the user leaves the application, as it is impossible to detect a menu button press or a home button press in android. I tried to solve it like this.
import java.util.Timer;
import java.util.TimerTask;
public class LeaveAppDetector extends BackgroundMusicService{
private boolean Deactivated;
private int Time = 700;
private int wait = 0;
private Timer timer = new Timer();
public void Activate() {
Deactivated = false;
timer.schedule(new TimerTask() {
#Override
public void run() {
if (wait >= 1) {
if (!getDeactivate()) {
//app has been closed
StopPlaying();
StopTimer();
} else {StopTimer();} //app has not been closed
}
wait++;
}
}, Time);
}
public void Deactivate() { //call at the start of each activity
Deactivated = true;
}
private boolean getDeactivate() {
return Deactivated;
}
private void StopTimer() {
if (timer != null) {
timer.cancel();
timer.purge();
}
}
}
The idea is that when an activity starts, it calls Deactivate(); and when it closes, it calls Activate(); so that the value of Activated is updated after a short period of time. I added the following method to my BackgrondMusicService class in order to be able to turn it off remotely
public void StopPlaying() {
player.stop();
player.release();
}
Now the problem, it gives me the error that the reference to the mediaplayers in the method I just showed, is one referring to a null object, and I don't know why or why it won't work. Can someone help?
You need to use a Bound Service like this answer suggest:
https://stackoverflow.com/a/2660696/3742122
If you only want the service running while activities are using it, consider getting rid of startService(). Instead, use bindService() in the onStart() methods of the activities that need the service, and call unbindService() in their corresponding onStop() methods. You can use BIND_AUTO_CREATE to have the service be lazy-started when needed, and Android will automatically stop the service after all connections have been unbound.
I'm making simple android app which should have counter which counts from 60 seconds down to 0 seconds. I have one idea how to do it, but I'm not sure if it is the smartest way to do it. And I'm not sure how to make it work in the code.
Idea:
In the .xml file I have added textView. I would make MyService class that extends Service which will be called by the .java file inside OnCreate function (because I want that counting starts immediately). MyService will change content of textView every second (I will have int counter which will be decreased every second and then text of textView will be changed).
Is there any better way to do it?
Here is MyService class:
public class MyService extends Service {
//for timer:
int counter = 0;
static final int UPDATE_INTERVAL = 1000;
private Timer timer = new Timer();
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doSomethingRepeatedly();
return START_STICKY;
}
private void doSomethingRepeatedly() {
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
//code for changing the content
}
}, 0, UPDATE_INTERVAL);
}
#Override
public void onDestroy() {
super.onDestroy();
//za timer
if (timer != null){
timer.cancel();
}
}
}
Do I have to put this code in separate .java file?
I'm not sure how to write code for changing the content of textView, because I'm not sure if I can call id of textView because it is in the separated file?
These would be functions for starting the Services:
public void startService(View view) {
startService(new Intent(getBaseContext(), MyService.class));
}
public void stopService(View view) {
stopService(new Intent(getBaseContext(), MyService.class));
}
Where do I have to put them?
Use a CountDownTimer.
Schedule a countdown until a time in the future, with regular
notifications on intervals along the way. Example of showing a 30
second countdown in a text field:
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
The calls to onTick(long) are synchronized to this object so that one
call to onTick(long) won't ever occur before the previous callback is
complete. This is only relevant when the implementation of
onTick(long) takes an amount of time to execute that is significant
compared to the countdown interval.
Halo, the first i want to know the idle time at my android application. after that, i will do something if it is a idle time mode.
I follow this link.
Application idle time
my program work properly, but suddenly the problem show up. I can't move to the other page (for example to the login page) or pop up a message using alertdialog because its in a thread. Do you have any solutions?
public class ControlActivity extends Activity {
private static final String TAG=ControlActivity.class.getName();
/**
* Gets reference to global Application
* #return must always be type of ControlApplication! See AndroidManifest.xml
*/
public ControlApplication getApp()
{
return (ControlApplication )this.getApplication();
}
#Override
public void onUserInteraction()
{
super.onUserInteraction();
getApp().touch();
Log.d(TAG, "User interaction to "+this.toString());
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}}
here is my ControlApplication.java
public class ControlApplication extends Application {
private static final String TAG=ControlApplication.class.getName();
private Waiter waiter;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Starting application"+this.toString());
//setContentView(R.layout.activity_main);
waiter=new Waiter(5*60*1000); //5 mins
waiter.start();
Toast.makeText(ControlApplication.this, "start", Toast.LENGTH_LONG).show();
}
public void touch()
{
waiter.touch();
Toast.makeText(ControlApplication.this, "touch", Toast.LENGTH_LONG).show();
} }
here is the Waiter.java
public class Waiter extends Thread implements Runnable{
private static final String TAG=Waiter.class.getName();
private long lastUsed;
private long period;
private boolean stop;
Context activity;
public Waiter(long period)
{
this.period=period;
stop=false;
}
#SuppressLint("ParserError")
public void run()
{
long idle=0;
this.touch();
do
{
idle=System.currentTimeMillis()-lastUsed;
Log.d(TAG, "Application is idle for "+idle +" ms");
try
{
Thread.sleep(5000); //check every 5 seconds
}
catch (InterruptedException e)
{
Log.d(TAG, "Waiter interrupted!");
}
if(idle > period)
{
idle=0;
//do something here - e.g. call popup or so
//Toast.makeText(activity, "Hello", Toast.LENGTH_LONG).show();
stopCounter();
}
}
while(!stop);
Log.d(TAG, "Finishing Waiter thread");
}
public synchronized void touch()
{
lastUsed=System.currentTimeMillis();
}
public synchronized void forceInterrupt()
{
this.interrupt();
}
//soft stopping of thread
public synchronized void stopCounter()
{
stop=true;
}
public synchronized void setPeriod(long period)
{
this.period=period;
}}
I tried to create a new class and call a method to intent. Its also fail. tried to pop up a message from that method its also fail.
do you guys have any other solutions for idle time? thanks.
Regards,
Alfred Angkasa
In you active activity, instead of this thread, do:
public class Graph extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
while(idle = 0) {
idle = System.currentTimeMillis()-lastUsed;
if(idle != period) {
Intent goNextActivity = new Intent(com.package.theactivity);
else {
idle == 0;
}
}
}
}
I just found by myself the answer by search on google and try for 5 hours.. :D
I hope my answer will help you too.
First, I mix the ControlApplication and Waiter with ControlActivity. Thats mean I don't need both files. My ControlActivity will extends the activity (its use for me to intent to the other page if in idle mode), and i will implements runnable(its use for me to run the thread).
after that i have a method called onUserInteraction(), this method help me to get the user interaction, whenever the user touch or click something.
in the onCreate, i initiate all the variable including lastUsed, period, and stop.
why should I initiate that? because you need to know how many seconds to know that your apps is on idle mode or not. that was period use. Stop variable is use for me to iterate and searching every 5 seconds(you can also make it every second to check idle or not) my apps is idle or not. I initiate lastUsed by calling method touch. I copied touch method from ControlApplication into my ControlActivity. By calling touch method, I can know when is my lastused. After that I start my thread.
in my run method, i set idle = 0. and do some looping to check. i check every 5 seconds to know my apps is on idle mode or not.
idle = System.System.currentTimeMillis()-lastUsed -> i used this to know if the idle is already suite with the period or not using if method.
if the idle is greater than period, my apps must be in idle mode. after that i stop the iteration and using handler to manage it.
i set handler.sendEmptyMessage(0), and create Handler. At handler i move to the other page.
this is my full code.
public class MainActivity extends Activity implements Runnable {
private static final String TAG= MainActivity.class.getName();
private long lastUsed;
private int period;
private boolean stop;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
period = 10000;
stop=false;
touch();
Thread currentThread = new Thread(this);
currentThread.start();
Toast.makeText(getApplicationContext(), "Start", Toast.LENGTH_SHORT).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public void onUserInteraction()
{
super.onUserInteraction();
touch();
Log.d(TAG, "User interaction to "+this.toString());
}
public synchronized void touch()
{
lastUsed=System.currentTimeMillis();
Toast.makeText(getApplicationContext(), "touch", Toast.LENGTH_SHORT).show();
}
public void moveIntent() {
Intent intent = new Intent(this, AfterIdle.class);
startActivity(intent);
}
public void validate(View view) {
switch (view.getId()) {
case R.id.button1 :
Intent intent = new Intent(this, AfterIdle.class);
startActivity(intent);
break;
}
}
#Override
public void run() {
// TODO Auto-generated method stub
long idle;
while (!stop) {
idle=System.currentTimeMillis()-lastUsed;
try
{
Thread.sleep(5000); //check every 5 seconds
}
catch (InterruptedException e)
{
Log.d(TAG, "Waiter interrupted!");
}
if (idle > period) {
idle = 0;
stop = true;
}
}
handler.sendEmptyMessage(0);
}
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
moveIntent();
}
};}
I hope this code will help another people if they have the same problem that i faced last time. I wish someone would correct the answer for me if my answer is wrong.
thanks.
Regards,
Alfred Angkasa