/*
* This source is part of the
* _____ ___ ____
* __ / / _ \/ _ | / __/___ _______ _
* / // / , _/ __ |/ _/_/ _ \/ __/ _ `/
* \___/_/|_/_/ |_/_/ (_)___/_/ \_, /
* /___/
* repository.
*
* Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org)
* Copyright (C) 2013-2015 Carmen Alvarez (c@rmen.ca)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ca.rmen.android.networkmonitor.app.service;
import android.app.Notification;
import android.app.Service;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import ca.rmen.android.networkmonitor.Constants;
import ca.rmen.android.networkmonitor.app.dbops.backend.clean.DBPurge;
import ca.rmen.android.networkmonitor.app.email.ReportEmailer;
import ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences;
import ca.rmen.android.networkmonitor.app.prefs.PreferencesMigrator;
import ca.rmen.android.networkmonitor.app.service.datasources.NetMonDataSources;
import ca.rmen.android.networkmonitor.app.service.scheduler.Scheduler;
import ca.rmen.android.networkmonitor.provider.NetMonColumns;
import ca.rmen.android.networkmonitor.util.Log;
/**
* This service periodically retrieves network state information and writes it to the database.
*/
public class NetMonService extends Service {
private static final String TAG = Constants.TAG + NetMonService.class.getSimpleName();
private PowerManager mPowerManager;
private long mLastWakeUp = 0;
private NetMonDataSources mDataSources;
private ReportEmailer mReportEmailer;
private Scheduler mScheduler;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate Service is enabled: starting monitor loop");
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
// Show our ongoing notification
Notification notification = NetMonNotification.createOngoingNotification(this);
startForeground(NetMonNotification.NOTIFICATION_ID_ONGOING, notification);
// Prepare our data sources
mDataSources = new NetMonDataSources();
mDataSources.onCreate(this);
mReportEmailer = new ReportEmailer(this);
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(mSharedPreferenceListener);
scheduleTests();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
@Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(mSharedPreferenceListener);
mDataSources.onDestroy();
NetMonNotification.dismissNotifications(this);
mScheduler.onDestroy();
super.onDestroy();
}
/**
* Start scheduling tests, using the scheduler class chosen by the user in the advanced settings.
*/
private void scheduleTests() {
Log.v(TAG, "scheduleTests");
NetMonPreferences prefs = NetMonPreferences.getInstance(this);
PreferencesMigrator prefsMigrator = new PreferencesMigrator(this);
prefsMigrator.migratePreferences();
Class<?> schedulerClass = prefs.getSchedulerClass();
Log.v(TAG, "Will use scheduler " + schedulerClass);
//noinspection TryWithIdenticalCatches
try {
if (mScheduler == null || !mScheduler.getClass().getName().equals(schedulerClass.getName())) {
Log.v(TAG, "Creating new scheduler " + schedulerClass);
if (mScheduler != null) mScheduler.onDestroy();
mScheduler = (Scheduler) schedulerClass.newInstance();
mScheduler.onCreate(this);
mScheduler.schedule(mTask, prefs.getUpdateInterval());
} else {
Log.v(TAG, "Rescheduling scheduler " + mScheduler);
int interval = prefs.getUpdateInterval();
mScheduler.setInterval(interval);
}
} catch (InstantiationException e) {
Log.e(TAG, "setScheduler Could not create scheduler " + schedulerClass + ": " + e.getMessage(), e);
} catch (IllegalAccessException e) {
Log.e(TAG, "setScheduler Could not create scheduler " + schedulerClass + ": " + e.getMessage(), e);
}
}
private final Runnable mTask = new Runnable() {
@Override
public void run() {
Log.v(TAG, "running task");
// Retrieve the log
WakeLock wakeLock = null;
try {
NetMonPreferences prefs = NetMonPreferences.getInstance(NetMonService.this);
// Periodically wake up the device to prevent the data connection from being cut.
long wakeInterval = prefs.getWakeInterval();
long now = System.currentTimeMillis();
long timeSinceLastWake = now - mLastWakeUp;
Log.d(TAG, "wakeInterval = " + wakeInterval + ", lastWakeUp = " + mLastWakeUp + ", timeSinceLastWake = " + timeSinceLastWake);
if (wakeInterval > 0 && timeSinceLastWake > wakeInterval) {
Log.d(TAG, "acquiring lock");
//noinspection deprecation
wakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
wakeLock.acquire();
mLastWakeUp = now;
}
// Insert this ContentValues into the DB.
Log.v(TAG, "Inserting data into DB");
// Put all the data we want to log, into a ContentValues.
ContentValues values = new ContentValues();
values.put(NetMonColumns.TIMESTAMP, System.currentTimeMillis());
values.putAll(mDataSources.getContentValues());
getContentResolver().insert(NetMonColumns.CONTENT_URI, values);
new DBPurge(NetMonService.this, prefs.getDBRecordCount()).execute(null);
// Send mail
mReportEmailer.send();
} catch (Throwable t) {
Log.v(TAG, "Error in monitorLoop: " + t.getMessage(), t);
} finally {
if (wakeLock != null && wakeLock.isHeld()) wakeLock.release();
}
}
};
private final OnSharedPreferenceChangeListener mSharedPreferenceListener = (sharedPreferences, key) -> {
Log.v(TAG, "onSharedPreferenceChanged: " + key);
// Listen for the user disabling the service
if (NetMonPreferences.PREF_SERVICE_ENABLED.equals(key)) {
if (!sharedPreferences.getBoolean(key, NetMonPreferences.PREF_SERVICE_ENABLED_DEFAULT)) {
Log.v(TAG, "Preference to enable service was turned off");
stopSelf();
}
}
// Reschedule our task if the user changed the interval
else if (NetMonPreferences.PREF_UPDATE_INTERVAL.equals(key) || NetMonPreferences.PREF_SCHEDULER.equals(key)) {
scheduleTests();
}
// Update the notification if the priority changed
else if (NetMonPreferences.PREF_NOTIFICATION_PRIORITY.equals(key)) {
// Show our ongoing notification
Notification notification = NetMonNotification.createOngoingNotification(this);
startForeground(NetMonNotification.NOTIFICATION_ID_ONGOING, notification);
}
};
}