/******************************************************************************* * Copyright 2013-2016 alladin-IT GmbH * * 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 at.alladin.rmbt.android.test; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.location.Location; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.support.v4.app.NotificationCompat; import android.util.Log; import at.alladin.openrmbt.android.R; import at.alladin.rmbt.android.main.RMBTMainActivity; import at.alladin.rmbt.android.test.RMBTTask.EndTaskListener; import at.alladin.rmbt.android.test.RMBTTask.RMBTTaskError; import at.alladin.rmbt.android.util.ConfigHelper; import at.alladin.rmbt.android.util.InformationCollector; import at.alladin.rmbt.android.util.NotificationIDs; import at.alladin.rmbt.client.QualityOfServiceTest; import at.alladin.rmbt.client.QualityOfServiceTest.Counter; import at.alladin.rmbt.client.RMBTClient; import at.alladin.rmbt.client.helper.IntermediateResult; import at.alladin.rmbt.client.helper.NdtStatus; import at.alladin.rmbt.client.helper.TestStatus; import at.alladin.rmbt.client.v2.task.QoSTestEnum; import at.alladin.rmbt.client.v2.task.result.QoSTestResultEnum; import at.alladin.rmbt.client.v2.task.service.TestMeasurement; import at.alladin.rmbt.client.v2.task.service.TrafficService; import at.alladin.rmbt.util.model.shared.exception.ErrorStatus; public class RMBTService extends Service implements EndTaskListener { public static String ACTION_START_TEST = "at.alladin.rmbt.android.startTest"; public static String ACTION_LOOP_TEST = "at.alladin.rmbt.android.loopTest"; public static String ACTION_ABORT_TEST = "at.alladin.rmbt.android.abortTest"; public static String BROADCAST_TEST_FINISHED = "at.alladin.rmbt.android.test.RMBTService.testFinished"; public static String BROADCAST_TEST_ABORTED = "at.alladin.rmbt.android.test.RMBTService.testAborted"; private final int FLAG_ABORTED = 1; private RMBTTask testTask; // private InformationCollector fullInfo; private Handler handler; private static final String DEBUG_TAG = "RMBTService"; private static WifiManager wifiManager; private static WifiLock wifiLock; private static WakeLock wakeLock; private boolean bound = false; private boolean loopMode; private static AtomicBoolean running = new AtomicBoolean(); public static long DEADMAN_TIME = 120 * 1000; private final Runnable deadman = new Runnable() { @Override public void run() { System.err.println("DEADMAN"); stopTest(BROADCAST_TEST_FINISHED); } }; // private BroadcastReceiver mNetworkStateIntentReceiver; // This is the object that receives interactions from clients. See // RemoteService for a more complete example. private final IBinder localRMBTBinder = new RMBTBinder(); private boolean completed = false; /** * Class for clients to access. Because we know this service always runs in * the same process as its clients, we don't need to deal with IPC. */ public class RMBTBinder extends Binder { public RMBTService getService() { // Return this instance of RMBTService so clients can call public // methods return RMBTService.this; } } @Override public void onCreate() { Log.d(DEBUG_TAG, "created"); super.onCreate(); handler = new Handler(); // initialise the locks loopMode = ConfigHelper.isLoopMode(this); // initialise the locks wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "RMBTWifiLock"); wakeLock = ((PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE)).newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "RMBTWakeLock"); // mNetworkStateIntentReceiver = new BroadcastReceiver() { // @Override // public void onReceive(Context context, Intent intent) { // if // (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) // { // // final boolean connected = ! // intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, // false); // if (! connected) // stopTest(); // } // } // }; // final IntentFilter networkStateChangedFilter = new IntentFilter(); // networkStateChangedFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); // // registerReceiver(mNetworkStateIntentReceiver, // networkStateChangedFilter); } @Override public void onDestroy() { Log.d(DEBUG_TAG, "destroyed"); super.onDestroy(); if (testTask != null) { Log.d(DEBUG_TAG, "RMBTTest stopped by onDestroy"); testTask.cancel(); } removeNotification(); unlock(); if (testTask != null) { testTask.cancel(); testTask = null; } handler.removeCallbacks(addNotificationRunnable); handler.removeCallbacks(deadman); running.set(false); // unregisterReceiver(mNetworkStateIntentReceiver); } @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { String action = null; if (intent != null) action = intent.getAction(); Log.i(DEBUG_TAG, "onStartCommand; action="+action); if (ACTION_ABORT_TEST.equals(action)) { Log.i(DEBUG_TAG, "ACTION_ABORT_TEST received"); stopTest(BROADCAST_TEST_ABORTED); return START_NOT_STICKY; } if (ACTION_START_TEST.equals(action) || ACTION_LOOP_TEST.equals(action)) { if (testTask != null && testTask.isRunning()) { if (ACTION_LOOP_TEST.equals(action)) // do not cancel test if running in loop mode return START_STICKY; testTask.cancel(); // otherwise cancel } completed = false; running.set(true); // lock wifi + power lock(); testTask = new RMBTTask(getApplicationContext()); testTask.setEndTaskListener(this); testTask.execute(handler); Log.d(DEBUG_TAG, "RMBTTest started"); handler.postDelayed(addNotificationRunnable, 200); handler.postDelayed(deadman, DEADMAN_TIME); return START_STICKY; } return START_NOT_STICKY; } public void stopTest(final String broadcastMessage) { if (testTask != null) { Log.d(DEBUG_TAG, "RMBTTest stopped"); testTask.cancel(); taskEnded(FLAG_ABORTED); sendBroadcast(new Intent(broadcastMessage)); } } public boolean isTestRunning() { return testTask != null && testTask.isRunning(); } private void addNotificationIfTestRunning() { if (isTestRunning() && ! bound) { final Resources res = getResources(); final PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent( getApplicationContext(), RMBTMainActivity.class), 0); final Notification notification = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.stat_icon_test) .setContentTitle(res.getText(R.string.test_notification_title)) .setContentText(res.getText(R.string.test_notification_text)) .setTicker(res.getText(R.string.test_notification_ticker)) .setContentIntent(contentIntent) .build(); startForeground(NotificationIDs.TEST_RUNNING, notification); } } private void removeNotification() { handler.removeCallbacks(addNotificationRunnable); stopForeground(true); } @Override public IBinder onBind(final Intent intent) { bound = true; return localRMBTBinder; } private final Runnable addNotificationRunnable = new Runnable() { @Override public void run() { addNotificationIfTestRunning(); } }; @Override public boolean onUnbind(final Intent intent) { bound = false; handler.postDelayed(addNotificationRunnable, 200); return true; } @Override public void onRebind(final Intent intent) { bound = true; removeNotification(); } public IntermediateResult getIntermediateResult(final IntermediateResult result) { if (testTask != null) return testTask.getIntermediateResult(result); else return null; } public boolean isConnectionError() { if (testTask != null) return testTask.isConnectionError(); else return false; } public RMBTTaskError getError() { if (testTask != null) { return testTask.getError(); } else { return RMBTTaskError.NONE; } } public Integer getSignal() { if (testTask != null) return testTask.getSignal(); else return null; } public int getSignalType() { if (testTask != null) return testTask.getSignalType(); else return InformationCollector.SINGAL_TYPE_NO_SIGNAL; } public String getOperatorName() { if (testTask != null) return testTask.getOperatorName(); else return null; } public int getNetworkType() { if (testTask != null) return testTask.getNetworkType(); else return 0; } public Location getLocation() { if (testTask != null) return testTask.getLocation(); else return null; } public String getServerName() { if (testTask != null) return testTask.getServerName(); else return null; } // protected Status getStatus() // { // if (testTask != null) // return testTask.getStatus(); // else // return null; // } public String getIP() { if (testTask != null) return testTask.getIP(); else return null; } public long getStartTimeMillis() { return testTask != null ? testTask.getStartTimeMillis() : 0; } public String getTestUuid(boolean clearUUID) { if (testTask != null) { return testTask.getTestUuid(); } else { return ConfigHelper.getLastTestUuid(getApplicationContext(), clearUUID); } } public float getNDTProgress() { if (testTask != null) return testTask.getNDTProgress(); else return 0; } public NdtStatus getNdtStatus() { if (testTask != null) return testTask.getNdtStatus(); else return null; } /** * * @return */ public float getQoSTestProgress() { if (testTask != null) return testTask.getQoSTestProgress(); else return 0; } /** * * @return */ public QualityOfServiceTest getQoSTest() { if (testTask != null) { return testTask.getQoSTest(); } return null; } /** * * @return */ public int getQoSTestSize() { if (testTask != null) return testTask.getQoSTestSize(); else return 0; } /** * * @return */ public QoSTestEnum getQoSTestStatus() { if (testTask != null) return testTask.getQoSTestStatus(); else return null; } /** * * @return */ public Map<QoSTestResultEnum, Counter> getQoSGroupCounterMap() { if (testTask != null) { return testTask.getQoSGroupCounterMap(); } else { return null; } } public void lock() { try { if (!wakeLock.isHeld()) wakeLock.acquire(); if (!wifiLock.isHeld()) wifiLock.acquire(); Log.d(DEBUG_TAG, "Lock"); } catch (final Exception e) { Log.e(DEBUG_TAG, "Error getting Lock: " + e.getMessage()); } } public static void unlock() { if (wakeLock != null && wakeLock.isHeld()) wakeLock.release(); if (wifiLock != null && wifiLock.isHeld()) wifiLock.release(); Log.d(DEBUG_TAG, "Unlock"); } @Override public void taskEnded(int... flag) { if (running.get()) { running.set(false); unlock(); removeNotification(); handler.removeCallbacks(deadman); completed = true; if (!contains(flag, FLAG_ABORTED)) { System.out.println("TASK ENDED flags: " + Arrays.toString(flag)); sendBroadcast(new Intent(BROADCAST_TEST_FINISHED)); } stopSelf(); if (testTask != null) { ConfigHelper.setLastTestUuid(getApplicationContext(), testTask.getTestUuid()); } Log.i("RMBTService", "stopped!"); } } public boolean isCompleted() { return completed; } public void runNdt() { if (testTask != null) { testTask.runNDT(); } } public boolean isLoopMode() { return loopMode; } public static boolean isRunning() { return running.get(); } public RMBTClient getRMBTClient() { if (testTask != null) return testTask.getRmbtClient(); return null; } public TrafficService getSpeedTestTrafficService() { if (testTask != null) return testTask.getSpeedTestTrafficService(); return null; } public TrafficService getQoSTrafficService() { if (testTask != null) return testTask.getQoSTrafficService(); return null; } public Map<TestStatus, TestMeasurement> getTrafficMeasurementMap() { if (testTask != null) return testTask.getTrafficMeasurementMap(); return new HashMap<TestStatus, TestMeasurement>(); } public Set<ErrorStatus> getErrorStatusList() { if (testTask != null) { return testTask.getErrorStatusList(); } return null; } public InformationCollector getInformationCollector() { if (testTask != null) { return testTask.getInformationCollector(); } return null; } public static boolean contains(int[] list, int i) { if (list == null) return false; for (final int li : list) { if (li == i) return true; } return false; } }