How to achieve Android ScreenSaver via service or application - android

After some research, I concluded there is nth like screen saver in androd. But there are some similar like Live-Wallpapers in Launcher screen or lock Screen.
I attempted a small wayout using service.
In my Activity after inactive for certain time I started a service.
My service started twice after the inactivity.
I want the service start once and as well whole over my app.How to do that?
Here are the codes I used.
User Inactive:
serviceHandler = new Handler();
serviceRunnable = new Runnable() {
#Override
public void run() {
Log.e("run times","Myservice");
startService(new Intent(getBaseContext(), MyService.class));
serviceHandler.removeCallbacks(serviceRunnable);
}
};
#Override
public void onUserInteraction() {
super.onUserInteraction();
serviceHandler.removeCallbacks(serviceRunnable);
stopService(new Intent(getBaseContext(), MyService.class));
serviceHandler.postDelayed(serviceRunnable, 8000);
}
MyService:
public class MyService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(MyService.this, "Service Started", Toast.LENGTH_SHORT).show();
ArrayList<String> imagelist = new ArrayList<>();
imagelist.add("");
Intent i = new Intent(this, ScreenSaverActivity.class);
i.putExtra("imageList", imagelist);
i.putExtra("delay", 3000);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
}
}
ScreenSaver Activity is:
public class ScreenSaverActivity extends Activity {
ImageView imgScreenSaver;
LinearLayout screenSaverLayout;
Handler screenSaverHandler;
Runnable screenSaverRunnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_saver);
screenSaverLayout = (LinearLayout) findViewById(R.id.layout_screen_saver);
imgScreenSaver = (ImageView) findViewById(R.id.img_screenSaver);
Bundle bundle = getIntent().getExtras();
repeatScreenSaver(bundle.getStringArrayList("imageList"), bundle.getInt("delay"));
// repeatScreenSaver("",bundle.getInt("delay"));
}
private void repeatScreenSaver(final ArrayList<String> imageList, final int milliseconds) {
screenSaverHandler = new Handler();
screenSaverRunnable = new Runnable() {
#Override
public void run() {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imgScreenSaver.getLayoutParams());
Random random = new Random();
params.setMargins(random.nextInt(500), random.nextInt(500),
random.nextInt(200), random.nextInt(200));
imgScreenSaver.setLayoutParams(params);
Ion.with(ScreenSaverActivity.this)
.load(imageList.get(
new Random().nextInt(imageList.size()
)
)
)
.withBitmap()
.error(R.mipmap.ic_launcher)
.intoImageView(imgScreenSaver);
screenSaverHandler.postDelayed(this, milliseconds);
}
};
screenSaverHandler.postDelayed(screenSaverRunnable, milliseconds);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
screenSaverHandler.removeCallbacks(screenSaverRunnable);
finish();
return super.onKeyDown(keyCode, event);
}
And the screensaver layout is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/layout_screen_saver"
android:background="#a0000000">
<ImageView
android:id="#+id/img_screenSaver"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
I've added following code in manifest:
<service android:name=".service.MyService" />
as MyService is inside the package .service

I couldn't find any reliable answer but I got my solution within the application itself using reference to many answers for userInactivity, use of Application.class, currentAppInForeground() and many others. I've included the whole project for screenSaver itself here.
I used Application.class for it.
Here I first found a user inactivity via a thread which runs in Application.class
Then I kept a condition to show screen saver i.e
if(applicationIsInForeGround() && !screenSaverActive && !videoPlaying){
// start screen saver activity
}
The main drawback here is the thread runs even if the app is closed. It might stop when the app is force stopped or device is restarted or the app is uninstalled.

Related

Android: Service is killed and restarted after a while

I know that is a well known subject, but I have tried lot of things. I have an simple application, dedicated to a specific user, application has an mainActivity which is displaying some status on screen and it's starting two services, one is making request from a server (at every 5 minutes) and one which is sending sms and replay to server (at every ten minutes).
The application is running on a Samsung pocket 2 with Android 4.4.2, this device is used only for this application. While the device is connected to ADB the services are working just fine, but if I disconnect the phone and let it running normally, the services are killed repeatable and restarted after a while. The messaged are send with very much delay. I would be thankful for any suggestions.
Here is my code:
Main activity:
public class MainActivity extends Activity {
private TextView _internet;
private TextView _signal;
private TextView _server;
private BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
IntentFilter intentFilter = new IntentFilter(Constants.SS);
receiverWorker();
registerReceiver(receiver, intentFilter);
startService(new Intent(this, RefreshDBService.class));
startService(new Intent(this, SmsService.class));
}
private void receiverWorker() {
receiver = new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
checkState();
}};
}
public void refreshButonClicked(View v) {
checkState();
}`
Here is my first service:
public class RefreshDBService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
if(Checks.checkInternetConnection(getApplicationContext())){
if(ServerOperations.isServerAvailable(getApplicationContext())){
String inputData = ServerOperations.makeRequest(Constants.GET_DATA_ROUTE, ServerOperations.getMessagesFromServer(getApplicationContext()));
ArrayList<DataSmsObj> dataFromServer=null;
if(inputData!=null && !inputData.isEmpty()){
dataFromServer = ServerOperations.fromJsonToObjects(inputData);
if(dataFromServer.size()>0){
_dataSource.open();
_dataSource.insertDataFromServer(dataFromServer);
_dataSource.close();
}
}
System.out.println("check server for messages in pending status, received -> "+ dataFromServer.size());
}else{
System.out.println("no server");
sentErrorToUI(Constants.NO_SERVER);
}
}else{
System.out.println("no internet");
sentErrorToUI(Constants.NO_INTERNET);
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE/2, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
}
public IBinder onBind(Intent intent) {
return null;
}
private void sentErrorToUI(String message){
Intent intent = new Intent(Constants.SS);
intent.putExtra(Constants.SS, message);
System.out.println("trimit" +message);
sendBroadcast(intent);
}
}
And this is the second one:
public class SmsService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
sendFeedbackToServer();
List<DataSmsObj> dataToSent = new ArrayList<DataSmsObj>();
_dataSource.open();
dataToSent = _dataSource.getDataToSent();
_dataSource.close();
System.out.println("messages to sent: "+ dataToSent.size());
for (int i = 0; i < dataToSent.size(); i++) {
//here the messages are send, the code is to long to put it here, but if is need i can do it afterwards
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
public IBinder onBind(Intent intent) {
return null;
}
If you are using a background Service with a scheduled task, it could be killed by the system. The only way to prevent the killing is a foreground Service. Quoting the documentation:
A foreground service is a service that the user is actively aware of and is not a candidate for the system to kill when low on memory.
You have to call the method startForeground() inside your Service using a Notification to show it. For further information you can check: https://developer.android.com/guide/components/services.html#Foreground
By the way, I recommend you to use the new JobScheduler api above api 21.
https://developer.android.com/reference/android/app/job/JobScheduler.html
Android kills service based on priority stack.
Android: keeping a background service alive (preventing process death)
What is START_STICKY,START_NOT_STICKY and START_REDELIVER_INTENT Service
Above links might help you.
Your devices will sleeps if it is unplugged from computer . So, the solutions :
Use startForeground method to prevent service to be killed and/or use AlarmManager in order to charge event.
It is possible to use start_stiky flag but it just restarts the process if it killed by system.

Why the body of onStartCommand() is getting executed only once?

To know the difference between IntentService and Service in Android, I created the below posted small test of a Service class. The MainActivity has a Button, when pressed, the
service will be started using startService() as shown below in the code, which will result in a call to onStartCommand(). In onStartCommand(), i run a loop for 10 seconds, and I
expected that, that loop will block the UI "the butoon". Actually that what happened exactly when I first time start the Service, but when I press the button after the 10 seconds
elapsed, it will result in a call to onStartCommand() but the log message inside the onStartCommand() never get displayed plus the UI is never blocked.
can anyone please explain what the body of the onStartCommand() is executed and blocks the UI only when the Service first started and never afterwards?
MainActivity
public class MainActivity extends AppCompatActivity {
private Button mbtnSend = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mbtnSend = (Button) findViewById(R.id.btn_send);
this.mbtnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), MyService.class);
startService(intent);
}
});
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(this.mBCR_VALUE_SENT, new IntentFilter(MyIntentService.INTENT_ACTION));
this.mbtnSend = (Button) findViewById(R.id.btn_send);
this.mbtnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), MyIntentService.class);
intent.putExtra("intent_key", ++i);
startService(intent);
}
});
}
}
MyIntentService:
public class MyService extends Service{
private final String TAG = this.getClass().getSimpleName();
private long mStartTime;
#Override
public void onCreate() {
super.onCreate();
Log.w(TAG, SubTag.msg("onCreate"));
this.mStartTime = TimeUtils.getTSSec();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w(TAG, SubTag.msg("onStartCommand"));
while ( (TimeUtils.getTSSec() - this.mStartTime) <=10) {
Log.w(TAG, SubTag.msg("time: " + (TimeUtils.getTSSec() - this.mStartTime)));
SystemClock.sleep(1000);
}
return Service.START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.w(TAG, SubTag.msg("onBind"));
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.w(TAG, SubTag.msg("onDestroy"));
}
}
You are setting mStartTime to TimeUtils.getTSSec() in onCreate(), which means that it will get intialized only once.
Afterwards, onStartCommand() is called, but the mStartTime timestamp is not being updated, so the while loop never runs.
I believe that moving the line where you initialize mStartTime to onStartCommand() before the while loop will make your thread hang again.

android: service is not stopped properly?

Currently im writing a camera app which should take pictures in a regular time intervall. For this my activity creates a IntentService, which starts a TimerTask with the desired delay. First time I start my app everything works fine. The pictures are taken in an regular time intervall of 10 seconds. But if i pause and resume my application the pictures are taken more frequently.
Here is my activity:
public class AndroidCameraExample extends Activity implements PictureTakenListener {
private static String CLASSTAG = "Android Surveillance Camera";
private Button captureButton;
private Context context;
private LinearLayout layoutForPreview;
private SurveillanceCamera camera;
// for calling the background service
private Intent backgroundServiceIntent = null;
// will send a notification if time has lapsed and we should
// take a new picture
private SurveillanceBroadcastReceiver receiver = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
layoutForPreview = (LinearLayout) findViewById(R.id.camera_preview);
camera = new SurveillanceCamera(this, layoutForPreview);
captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(PictureCaptureListener);
camera.addPictureTakenListener(this);
startSurveillance();
}
private void startSurveillance() {
Settings.surveillanceIsActive = true;
camera.start();
startBackroundService();
registerBroadcastReceiver();
}
private void stopSurveillance() {
Settings.surveillanceIsActive = false;
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
if (backgroundServiceIntent != null) {
stopService(backgroundServiceIntent);
backgroundServiceIntent = null;
}
camera.stop();
}
private void startBackroundService() {
if (isServiceRunning(SurveillanceBackgroundService.class)) {
Log.d(Settings.APPTAG, "The Service is already running");
}
if (backgroundServiceIntent == null) {
backgroundServiceIntent = new Intent(this, SurveillanceBackgroundService.class);
startService(backgroundServiceIntent);
}
}
private boolean isServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
private void registerBroadcastReceiver() {
if (receiver == null) {
IntentFilter filter = new IntentFilter(SurveillanceBroadcastReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new SurveillanceBroadcastReceiver();
registerReceiver(receiver, filter);
}
}
public void onResume() {
super.onResume();
startSurveillance();
}
#Override
protected void onPause() {
super.onPause();
stopSurveillance();
}
class SurveillanceBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
camera.takePicture();
}
}
My Service
public class SurveillanceBackgroundService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
notifyTimeLapsed();
}
}, 100, Settings.timeIntervall * 1000);
}
private void notifyTimeLapsed() {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(SurveillanceBroadcastReceiver.ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
}
}
I aleady checked that the service isn't running (in background) while the app is paused and started again afterwards, so I don't see any reason why the pictureTaking Event should be triggered more ofter after resuming.
I also use a small wrapper class for camera handling but i don't think this causes the problem. if you need to code for suggesting any solutions i will post it here anyway.
Any hints or help for this`?
EDIT: I overwrite onDestroy and onStart to Cancel the Timer and start it again but the problem stays the same. After resume more pictures are taken than before.
UPDATE: If I remove the method onStart the timer seems to get canceled directly and isn't started again? I added some Logger output in the methods and get this information:
05-15 18:56:03.478: I/com.test.androidcameraexample(10061): SurveillanceBackgroundService onHandleIntent
05-15 18:56:03.498: I/com.test.androidcameraexample(10061): SurveillanceBackgroundService onDestroy
#Override
protected void onHandleIntent(Intent intent) {
if (t == null) {
t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
notifyTimeLapsed();
}
}, 100, Settings.timeIntervall * 1000);
}
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (t == null) {
t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
notifyTimeLapsed();
}
}, 100, Settings.timeIntervall * 1000);
}
}
#Override
public void onDestroy() {
super.onDestroy();
t.cancel();
t = null;
}
My original answer was this:
You need to call either Timer.cancel() or TimerTask.cancel()
on the Timer or TimerTask that the service created, or else the
timer task will keep running in a background thread.
And then I added this:
To get this to work reliably, you could specify one Intent action
for starting the timer, and another action for stopping the timer.
But, there is actually a big (and subtle) problem with storing a Timer variable in an IntentService. An IntentService creates its own background thread, and it quickly kills itself (after onHandleIntent () returns) if there are no intents in its queue -- which would also mean your Timer value would be lost. So, even if you have 2 intent actions (for starting and stopping the timer), there is no way to guarantee that the stop action would have access to the original Timer value (since it could very well be creating a brand new IntentService instance)!
So, I recommend that you use the AlarmManager to schedule periodic alarms. See here for some training on how to do that.

Android starting intent activity error in service

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

Stopping Service results in orphaned thread

I am continuing to study from the book "Pro Android 2," working through the Service example that consists of two classes: BackgroundService.java and MainActivity.java. The MainActivity class is shown below and has a couple buttons. The unbind button, unbindBtn, stops the Service but doesn't appear to do much else like kill the thread the Service started.
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "starting service");
Button bindBtn = (Button)findViewById(R.id.bindBtn);
bindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent backgroundService = new Intent(MainActivity.this, com.marie.mainactivity.BackgroundService.class);
startService(backgroundService);
}
});
Button unbindBtn = (Button)findViewById(R.id.unbindBtn);
unbindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
stopService(new Intent(MainActivity.this, BackgroundService.class));
}
});
}
}
The documentation says "if your service is going to do any CPU intensive work or blocking operations..., you should create a new thread within the service to do that work." And that's exactly what the BackgroundService class does below. As you can see below I've added a while(true) loop in the thread's run() method to see what happens to the thread when I stop the Service.
public class BackgroundService extends Service {
private NotificationManager notificationMgr;
#Override
public void onCreate() {
super.onCreate();
notificationMgr = NotificationManager)getSystemService(NOTIFICATION_SERVICE);
displayNotificationMessage("starting Background Service");
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
}
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here...
long count = 0;
while (true) {
if (count++ > 1000000)
{
count = 0;
Log.d("ServiceWorker", "count reached");
}
}
//stop the service when done...
//BackgroundService.this.stopSelf();
}
}
#Override
public void onDestroy()
{
displayNotificationMessage("stopping Background Service");
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void displayNotificationMessage(String message)
{
Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
notification.setLatestEventInfo(this, "Background Service", message, contentIntent);
notificationMgr.notify(R.id.app_notification_id, notification);
}
}
When I press the unbind button, unbindBtn, in the MainActivity class I trust the Service in this example will be stopped. But from what I can see in logcat the thread that was started by the Service continues to run. It's like the thread is now some kind of orphan with no apparent way to stop it. I've seen other source code use a while(true) loop in a thread's run() method. This seems bad unless a way to break out of the loop is provided. Is that typically how it's done? Or are there other ways to kill a thread after the Service that started it has stopped?
You should provide a 'running' boolean.
while(running) {
//do your stuff
}
You want to make it something that you can update. Perhaps your Service's onDestroy() method should call a stopProcessing() method on your Runnable, which will set the 'running' boolean to false.

Categories

Resources