Reputation: 47
I've tried to make an app that opens up a service, that changes the wallpaper on your phone every 5 hours.
For testing purposes I've only changed the timer for 1 minute just to see if it works (because when it's on 5 hours it doesn't work),
and indeed it changes the wallpaper every single minute. Even when I close my app and the service is closed I have a statement to restart it so that works.
Unfortunately when the phone turns black (timeout for the screen). and I turn it back on it's like it stuck up all the time. It needed to go inside the listener while the phone was suspended, so it goes inside the timerTask like, 10 times in a row immediately (or the times it was offline..and it should have gone inside). In other words if I put the phone on rest for 10 minutes and then turn it back on, it will just change my wallpaper 10 times in a row.
So that's one problem. The other one is that if I change the timer for 5 hours it doesn't change the wallpaper at all.
Can someone help me or know why this is happening to me ?
this is my code >
my service >
package com.greenroad.candidate.mywallpaperchanger;
import android.app.Service;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by pitsponet on 31/08/2015.
*/
public class myService extends Service {
int oneSecond = 1000;
int oneMinute = oneSecond*60;
int oneHour = oneMinute*60;
int timerDeley = oneMinute;
private Timer timer;
//this is the tast or the reciver the timer will go into every time it has being called
private TimerTask timerTask = new TimerTask() {
@Override
public void run() {
//shows a toast saying timer listener has entered
Handler mainHandler = new Handler(getApplicationContext().getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "timer listener Entered", Toast.LENGTH_LONG).show();
}
});
//gets the picture modifire to know what picture to choose to change the wallpaper to
// Access the default SharedPreferences
SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
Integer pictureModifireInt = pref.getInt("pictureModifire", 0);
//updates teh picture modifire by one
pictureModifireInt++;
/////holds a list with all the images that are avilable to change
int displayPicture = R.drawable.captain;
ArrayList<Integer> pictureNames = new ArrayList<>();
pictureNames.add(R.drawable.captain);
pictureNames.add(R.drawable.flash);
pictureNames.add(R.drawable.superman);
pictureNames.add(R.drawable.thor);
pictureNames.add(R.drawable.wonder);
pictureNames.add(R.drawable.a);
pictureNames.add(R.drawable.b);
pictureNames.add(R.drawable.c);
pictureNames.add(R.drawable.d);
pictureNames.add(R.drawable.e);
pictureNames.add(R.drawable.f);
pictureNames.add(R.drawable.g);
pictureNames.add(R.drawable.h);
pictureNames.add(R.drawable.i);
pictureNames.add(R.drawable.j);
pictureNames.add(R.drawable.k);
pictureNames.add(R.drawable.l);
pictureNames.add(R.drawable.m);
pictureNames.add(R.drawable.n);
pictureNames.add(R.drawable.o);
//logs the stored prefrence and select the correct image at place > picture modifire
Log.d("myLog", "storedPreference: " + pictureModifireInt);
displayPicture = pictureNames.get(pictureModifireInt-1);
//stores the picture modifire back in the shared prefrences or initlizes it if it reached the last image
if(pictureModifireInt > 19){
// Edit the saved preferences
Log.d("myLog", "putting in pictureModifire : : " + 0);
editor.putInt("pictureModifire", 0);
editor.commit();
} else {
Log.d("myLog", "putting in pictureModifire : : " + pictureModifireInt);
editor.putInt("pictureModifire", pictureModifireInt);
editor.commit();
}
//most important part of the code
//gets the dimentions of the phones screen and changes the wallpaper
//it has to get the dimentions so that the wallpaper will be in full screen
//maybe he can't do this part when he is in suspend mode ?
WindowManager wm= (WindowManager) getSystemService(MainActivity.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Bitmap bmap2 = BitmapFactory.decodeResource(getResources(), displayPicture);
Bitmap bitmap = Bitmap.createScaledBitmap(bmap2, width, height, true);
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
//just shoes a post to let knnow what wallpaper has been changed, and that the walpaper indeed changed
mainHandler = new Handler(getApplicationContext().getMainLooper());
final Integer finalPictureModifireInt = pictureModifireInt-1;
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "wallpaper changed to : "+ finalPictureModifireInt+" and started a new timer", Toast.LENGTH_LONG).show();
}
});
}
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//show a toast to indicae that a new service was created
Toast.makeText(getApplicationContext(), "a new service created",
Toast.LENGTH_LONG).show();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyLog", "a new service started");
final Handler mainHandler = new Handler(getApplicationContext().getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
//show a toast to indicae that a new service was started
Toast.makeText(getApplicationContext(), "serviceStarterd", Toast.LENGTH_LONG).show();
// Access the default SharedPreferences
SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
//open a boolean to tell if the service is activated for the first time it will say false
boolean serviceStateOn = pref.getBoolean("isServiceActivated", false);
if(serviceStateOn == false){
//if ther serviceStateOn is false then there is no service running and it's fine to run a timer task
Toast.makeText(getApplicationContext(), "a New Timer Started with Delay: "+timerDeley, Toast.LENGTH_LONG).show();
editor.putBoolean("isServiceActivated", true); // getting String
editor.commit();
timer = new Timer();
timer.scheduleAtFixedRate(timerTask, timerDeley, timerDeley);
} else {
//if ther serviceStateOn is true then there is a service runing so just don't do anything
Log.d ("myLog", "Service is on so do nothing");
}
}
});
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getApplicationContext(), "service stoped",
Toast.LENGTH_LONG).show();
}
}
my manifest file >
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.greenroad.candidate.mywallpaperchanger" >
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".myService"
android:exported="false"
/>
</application>
</manifest>
my main acticity >
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.IOException;
public class MainActivity extends ActionBarActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
//declaring all the buttons
Button comixButtonSuperman, comixButtonFlash, comixButtonCaptainAmerica, comixButtonThor, comixButtonWonderWoman;
Button startServiceButton, stopServiceButton;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//casting and connecting the buttons to the actual buttons
comixButtonSuperman = (Button) findViewById(R.id.BT_wallpaper1);
comixButtonFlash = (Button) findViewById(R.id.BT_wallpaper2);
comixButtonCaptainAmerica = (Button) findViewById(R.id.BT_wallpaper3);
comixButtonThor = (Button) findViewById(R.id.BT_wallpaper4);
comixButtonWonderWoman = (Button) findViewById(R.id.BT_wallpaper5);
startServiceButton = (Button) findViewById(R.id.BT_startService);
stopServiceButton = (Button) findViewById(R.id.BT_stopService);
//adding listeners for all the buttons
comixButtonSuperman.setOnClickListener(this);
comixButtonFlash.setOnClickListener(this);
comixButtonCaptainAmerica.setOnClickListener(this);
comixButtonThor.setOnClickListener(this);
comixButtonWonderWoman.setOnClickListener(this);
startServiceButton.setOnClickListener(this);
stopServiceButton.setOnClickListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d ("myLog", "Application exists here");
// when going to suspend the service is destroyd, so we should change the boolean to indicate this
//also this will make the service statement added in the service possible.
SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE);
SharedPreferences.Editor editor7 = pref.edit();
editor7.putBoolean("isServiceActivated", false); // getting String
editor7.commit();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//maybe will add options in a later date
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.BT_wallpaper1: // superman button
//was used for testings
break;
case R.id.BT_wallpaper2: // flash button
//was used for testings
break;
case R.id.BT_wallpaper3: // captain america button
//was used for testings
break;
case R.id.BT_wallpaper4: // thor button
//was used for testings
break;
case R.id.BT_wallpaper5: // wonder woman button
//was used for testings
break;
case R.id.BT_startService: // starts the service
//starts the service up
Intent i= new Intent(this, myService.class);
startService(i);
break;
case R.id.BT_stopService: // stops the service
//stop the service
Intent j= new Intent(this, myService.class);
stopService(j);
//updates ths shared prefrence that there is no service suning any moew
SharedPreferences pref = getApplicationContext().getSharedPreferences("myGlobalPrefTable", MODE_PRIVATE);
SharedPreferences.Editor editor7 = pref.edit();
editor7.putBoolean("isServiceActivated", false); // getting String
editor7.commit();
break;
}
}
}
Upvotes: 0
Views: 69
Reputation: 2537
I believe for this case you should use the AlarmManager instead of timer + handler. It gives you a way to perform time-based operations outside the lifetime of your application.
Here is an example of scheduling using AlarmManager
https://stackoverflow.com/a/8801990/1163224
I decided to add as nipped of code how to use AlarmManager to make my answer more complete
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.Toast;
public class Alarm extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
// Put here YOUR code.
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
wl.release();
}
public void SetAlarm(Context context)
{
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
Add to Manifest.xml:
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<receiver android:process=":remote" android:name=".Alarm"></receiver>
Service
public class YourService extends Service
{
Alarm alarm = new Alarm();
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
alarm.SetAlarm(this);
return START_STICKY;
}
....
}
In the Link above is a full code of how to create a service and start a service on boot
Hope you find my answer useful. :)
Upvotes: 1