20
20
import android .app .Notification ;
21
21
import android .app .NotificationManager ;
22
22
import android .app .PendingIntent ;
23
- import android .app .job .JobInfo ;
24
- import android .app .job .JobParameters ;
25
- import android .app .job .JobScheduler ;
26
- import android .app .job .JobService ;
27
- import android .content .ComponentName ;
23
+ import android .app .Service ;
24
+ import android .content .BroadcastReceiver ;
28
25
import android .content .Context ;
29
26
import android .content .Intent ;
27
+ import android .content .IntentFilter ;
30
28
import android .content .SharedPreferences ;
31
29
import android .hardware .Sensor ;
32
30
import android .hardware .SensorEvent ;
33
31
import android .hardware .SensorEventListener ;
34
32
import android .hardware .SensorManager ;
33
+ import android .os .Build ;
34
+ import android .os .IBinder ;
35
35
36
36
import java .text .NumberFormat ;
37
37
import java .util .Date ;
38
38
import java .util .Locale ;
39
39
40
40
import de .j4velin .pedometer .ui .Activity_Main ;
41
+ import de .j4velin .pedometer .util .API23Wrapper ;
41
42
import de .j4velin .pedometer .util .Logger ;
42
43
import de .j4velin .pedometer .util .Util ;
43
44
import de .j4velin .pedometer .widget .WidgetUpdateService ;
49
50
* This service won't be needed any more if there is a way to read the
50
51
* step-value without waiting for a sensor event
51
52
*/
52
- public class SensorListener extends JobService implements SensorEventListener {
53
+ public class SensorListener extends Service implements SensorEventListener {
53
54
54
55
private final static int NOTIFICATION_ID = 1 ;
55
- private final static int JOB_ID = 1 ;
56
+ private final static long MICROSECONDS_IN_ONE_MINUTE = 60000000 ;
56
57
private final static long SAVE_OFFSET_TIME = AlarmManager .INTERVAL_HOUR ;
57
58
private final static int SAVE_OFFSET_STEPS = 500 ;
58
59
59
60
private static int steps ;
60
61
private static int lastSaveSteps ;
61
62
private static long lastSaveTime ;
62
- private JobParameters jobParameters ;
63
+
64
+ private final BroadcastReceiver shutdownReceiver = new ShutdownRecevier ();
63
65
64
66
public final static String ACTION_UPDATE_NOTIFICATION = "updateNotificationState" ;
65
67
@@ -72,11 +74,12 @@ public void onAccuracyChanged(final Sensor sensor, int accuracy) {
72
74
73
75
@ Override
74
76
public void onSensorChanged (final SensorEvent event ) {
75
- if (BuildConfig .DEBUG ) Logger .log ("step count received: " +event .values [0 ]);
76
- if (event .values [0 ] < Integer .MAX_VALUE ) {
77
+ if (event .values [0 ] > Integer .MAX_VALUE ) {
78
+ if (BuildConfig .DEBUG ) Logger .log ("probably not a real value: " + event .values [0 ]);
79
+ return ;
80
+ } else {
77
81
steps = (int ) event .values [0 ];
78
82
updateIfNecessary ();
79
- jobFinished (jobParameters , false );
80
83
}
81
84
}
82
85
@@ -107,30 +110,68 @@ private void updateIfNecessary() {
107
110
}
108
111
}
109
112
110
- public static void schedulePeriodicJob (final Context context ) {
111
- if (BuildConfig .DEBUG ) Logger .log ("SensorListener schedulePeriodicJob" );
112
- ComponentName serviceComponent = new ComponentName (context , SensorListener .class );
113
- JobInfo .Builder builder = new JobInfo .Builder (JOB_ID , serviceComponent );
114
- builder .setPeriodic (AlarmManager .INTERVAL_HOUR );
115
- JobScheduler jobScheduler =
116
- (JobScheduler ) context .getSystemService (Context .JOB_SCHEDULER_SERVICE );
117
- jobScheduler .schedule (builder .build ());
113
+ @ Override
114
+ public IBinder onBind (final Intent intent ) {
115
+ return null ;
116
+ }
117
+
118
+ @ Override
119
+ public int onStartCommand (final Intent intent , int flags , int startId ) {
120
+ if (intent != null && intent .getBooleanExtra (ACTION_UPDATE_NOTIFICATION , false )) {
121
+ updateNotificationState ();
122
+ } else {
123
+ reRegisterSensor ();
124
+ registerBroadcastReceiver ();
125
+ updateIfNecessary ();
126
+ }
127
+
128
+ // restart service every hour to save the current step count
129
+ long nextUpdate = Math .min (Util .getTomorrow (),
130
+ System .currentTimeMillis () + AlarmManager .INTERVAL_HOUR );
131
+ if (BuildConfig .DEBUG ) Logger .log ("next update: " + new Date (nextUpdate ).toLocaleString ());
132
+ AlarmManager am =
133
+ (AlarmManager ) getApplicationContext ().getSystemService (Context .ALARM_SERVICE );
134
+ PendingIntent pi = PendingIntent
135
+ .getService (getApplicationContext (), 2 , new Intent (this , SensorListener .class ),
136
+ PendingIntent .FLAG_UPDATE_CURRENT );
137
+ if (Build .VERSION .SDK_INT >= 23 ) {
138
+ API23Wrapper .setAlarmWhileIdle (am , AlarmManager .RTC , nextUpdate , pi );
139
+ } else {
140
+ am .set (AlarmManager .RTC , nextUpdate , pi );
141
+ }
142
+
143
+ return START_STICKY ;
144
+ }
118
145
146
+ @ Override
147
+ public void onCreate () {
148
+ super .onCreate ();
149
+ if (BuildConfig .DEBUG ) Logger .log ("SensorListener onCreate" );
150
+ reRegisterSensor ();
151
+ updateNotificationState ();
119
152
}
120
153
121
154
@ Override
122
- public boolean onStartJob (JobParameters jobParameters ) {
123
- if (BuildConfig .DEBUG ) Logger .log ("SensorListener onStartJob" );
124
- this .jobParameters = jobParameters ;
125
- registerSensor ();
126
- return true ; // keep running until receiving a step value
155
+ public void onTaskRemoved (final Intent rootIntent ) {
156
+ super .onTaskRemoved (rootIntent );
157
+ if (BuildConfig .DEBUG ) Logger .log ("sensor service task removed" );
158
+ // Restart service in 500 ms
159
+ ((AlarmManager ) getSystemService (Context .ALARM_SERVICE ))
160
+ .set (AlarmManager .RTC , System .currentTimeMillis () + 500 , PendingIntent
161
+ .getService (this , 3 , new Intent (this , SensorListener .class ), 0 ));
127
162
}
128
163
129
164
@ Override
130
- public boolean onStopJob (JobParameters jobParameters ) {
131
- if (BuildConfig .DEBUG ) Logger .log ("SensorListener onStopJob" );
132
- unregisterSensor ();
133
- return false ;
165
+ public void onDestroy () {
166
+ super .onDestroy ();
167
+ if (BuildConfig .DEBUG ) Logger .log ("SensorListener onDestroy" );
168
+ try {
169
+ SensorManager sm = (SensorManager ) getSystemService (SENSOR_SERVICE );
170
+ sm .unregisterListener (this );
171
+ } catch (Exception e ) {
172
+ if (BuildConfig .DEBUG ) Logger .log (e );
173
+ e .printStackTrace ();
174
+ }
134
175
}
135
176
136
177
private void updateNotificationState () {
@@ -170,26 +211,38 @@ private void updateNotificationState() {
170
211
}
171
212
}
172
213
173
- private void registerSensor () {
174
- if (BuildConfig .DEBUG ) Logger .log ("re-register sensor listener" );
175
- SensorManager sm = (SensorManager ) getSystemService (SENSOR_SERVICE );
176
- if (BuildConfig .DEBUG ) {
177
- Logger .log ("step sensors: " + sm .getSensorList (Sensor .TYPE_STEP_COUNTER ).size ());
178
- if (sm .getSensorList (Sensor .TYPE_STEP_COUNTER ).size () < 1 ) return ; // emulator
179
- Logger .log ("default: " + sm .getDefaultSensor (Sensor .TYPE_STEP_COUNTER ).getName ());
180
- }
181
-
182
- sm .registerListener (this , sm .getDefaultSensor (Sensor .TYPE_STEP_COUNTER ),
183
- SensorManager .SENSOR_DELAY_FASTEST );
214
+ private void registerBroadcastReceiver () {
215
+ if (BuildConfig .DEBUG ) Logger .log ("register broadcastreceiver" );
216
+ IntentFilter filter = new IntentFilter ();
217
+ filter .addAction (Intent .ACTION_SHUTDOWN );
218
+ registerReceiver (shutdownReceiver , filter );
184
219
}
185
220
186
- private void unregisterSensor () {
221
+ private void reRegisterSensor () {
222
+ if (BuildConfig .DEBUG ) Logger .log ("re-register sensor listener" );
187
223
SensorManager sm = (SensorManager ) getSystemService (SENSOR_SERVICE );
188
224
try {
189
225
sm .unregisterListener (this );
190
226
} catch (Exception e ) {
191
227
if (BuildConfig .DEBUG ) Logger .log (e );
192
228
e .printStackTrace ();
193
229
}
230
+
231
+ if (BuildConfig .DEBUG ) {
232
+ Logger .log ("step sensors: " + sm .getSensorList (Sensor .TYPE_STEP_COUNTER ).size ());
233
+ if (sm .getSensorList (Sensor .TYPE_STEP_COUNTER ).size () < 1 ) return ; // emulator
234
+ Logger .log ("default: " + sm .getDefaultSensor (Sensor .TYPE_STEP_COUNTER ).getName ());
235
+ }
236
+
237
+ if (Build .VERSION .SDK_INT >= 27 ) {
238
+ // do not use batching on Android P and newer as we dont live long enough to recieve
239
+ // those value due to aggressive power saving
240
+ sm .registerListener (this , sm .getDefaultSensor (Sensor .TYPE_STEP_COUNTER ),
241
+ SensorManager .SENSOR_DELAY_FASTEST );
242
+ } else {
243
+ // enable batching with delay of max 5 min
244
+ sm .registerListener (this , sm .getDefaultSensor (Sensor .TYPE_STEP_COUNTER ),
245
+ SensorManager .SENSOR_DELAY_NORMAL , (int ) (5 * MICROSECONDS_IN_ONE_MINUTE ));
246
+ }
194
247
}
195
248
}
0 commit comments