Skip to content
This repository has been archived by the owner on Jun 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #188 from denzilferreira/development
Browse files Browse the repository at this point in the history
Sync with development
  • Loading branch information
denzilferreira authored Apr 18, 2017
2 parents 3d24083 + a7c663f commit 06d34e7
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 63 deletions.
2 changes: 1 addition & 1 deletion aware-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ android {
versionCode version_code
versionName version_readable
targetSdkVersion 25
minSdkVersion 10 //Android 2.3.3
minSdkVersion 11 //Android 3.0
}

signingConfigs {
Expand Down
2 changes: 1 addition & 1 deletion aware-core/src/main/java/com/aware/utils/Aware_Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public void onReceive(Context context, Intent intent) {
CONTEXT_PRODUCER.onContext();
}
}
if (intent.getAction().equals(Aware.ACTION_AWARE_SYNC_DATA) && Aware.getSetting(context, Aware_Preferences.STATUS_WEBSERVICE).equals("true")) {
if (intent.getAction().equals(Aware.ACTION_AWARE_SYNC_DATA)) {
if (DATABASE_TABLES != null && TABLES_FIELDS != null && CONTEXT_URIS != null) {
for (int i = 0; i < DATABASE_TABLES.length; i++) {
Intent webserviceHelper = new Intent(context, WebserviceHelper.class);
Expand Down
2 changes: 1 addition & 1 deletion aware-core/src/main/java/com/aware/utils/Aware_Sensor.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void onReceive(Context context, Intent intent) {
CONTEXT_PRODUCER.onContext();
}
}
if (intent.getAction().equals(Aware.ACTION_AWARE_SYNC_DATA) && Aware.getSetting(context, Aware_Preferences.STATUS_WEBSERVICE).equals("true")) {
if (intent.getAction().equals(Aware.ACTION_AWARE_SYNC_DATA)) {
if (DATABASE_TABLES != null && TABLES_FIELDS != null && CONTEXT_URIS != null) {
for (int i = 0; i < DATABASE_TABLES.length; i++) {
Intent webserviceHelper = new Intent(context, WebserviceHelper.class);
Expand Down
66 changes: 59 additions & 7 deletions aware-core/src/main/java/com/aware/utils/SSLManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.concurrent.ExecutionException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;

/**
* Created by denzil on 15/12/15.
* This class will make sure we have the latest server SSL certificate to allow downloads from self-hosted servers
Expand All @@ -37,6 +45,7 @@ public class SSLManager {
* Handle a study URL. Fetch data from query parameters if it is there. Otherwise,
* use the classic method of downloading the certificate over http. Enforces the key
* management policy.
*
* @param context app context
* @param url full URL, including protocol and query arguments
* @param block if true, this method blocks, otherwise downloading is in background.
Expand Down Expand Up @@ -68,14 +77,57 @@ public static void handleUrl(Context context, String url, boolean block) {
Log.d(Aware.TAG, "Certificates: Already present and key_management=once: " + hostname);
}
} else {
if (!hasCertificate(context, hostname)) {
if (Aware.DEBUG) Log.d(Aware.TAG, "Certificates: Downloading certificate: " + hostname);
downloadCertificate(context, hostname, block);
try {
URL javaURL = new URL(url);
if (!hasCertificate(context, hostname) && (getCertificateExpiration(javaURL) != null && System.currentTimeMillis() >= getCertificateExpiration(javaURL).getTime())) {
if (Aware.DEBUG)
Log.d(Aware.TAG, "Certificates: Downloading certificate: " + hostname);

downloadCertificate(context, hostname, block);
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
}

/**
* Taken from https://www.experts-exchange.com/questions/27668989/Getting-SSL-Certificate-expiry-date.html
*
* @param url
* @return
*/
public static Date getCertificateExpiration(URL url) {
try {
URLConnection conn = url.openConnection();
if (conn instanceof HttpsURLConnection) {
// retrieve the N-length signing chain for the server certificates
// certs[0] is the server's certificate
// certs[1] - certs[N-1] are the intermediate authorities that signed the cert
// certs[N] is the root certificate authority of the chain
Certificate[] certs = ((HttpsURLConnection) conn).getServerCertificates();
if (certs.length > 0 && certs[0] instanceof X509Certificate) {
// certs[0] is an X.509 certificate, return its "notAfter" date
return ((X509Certificate) certs[0]).getNotAfter();
}
}
// connection is not HTTPS or server is not signed with an X.509 certificate, return null
return null;
} catch (SSLPeerUnverifiedException spue) {
// connection to server is not verified, unable to get certificates
return null;
} catch (IllegalStateException ise) {
// shouldn't get here -- indicates attempt to get certificates before
// connection is established
return null;
} catch (IOException ioe) {
// error connecting to URL -- this must be caught last since
// other exceptions are subclasses of IOException
return null;
}
}

/**
* Classic method: Download certificate unconditionally. This is the old
* method of certificate fetching. This method blocks if the block parameter is true,
Expand Down Expand Up @@ -263,7 +315,7 @@ private static void setCertificate(Context context, String hostname, String cert
* Load HTTPS certificate from server: server.crt
*
* @param context context
* @param server server URL, http://{hostname}/index.php
* @param server server URL, http://{hostname}/index.php
* @return FileInputStream of certificate
* @throws FileNotFoundException
*/
Expand All @@ -275,7 +327,7 @@ public static InputStream getHTTPS(Context context, String server) throws FileNo

File root_folder;
if (!context.getResources().getBoolean(R.bool.standalone)) {
root_folder = new File(Environment.getExternalStoragePublicDirectory("AWARE")+ "/credentials"); // sdcard/AWARE/ (shareable, does not delete when uninstalling)
root_folder = new File(Environment.getExternalStoragePublicDirectory("AWARE") + "/credentials"); // sdcard/AWARE/ (shareable, does not delete when uninstalling)
} else {
root_folder = new File(ContextCompat.getExternalFilesDirs(context, null)[0] + "/AWARE/credentials"); // sdcard/Android/<app_package_name>/AWARE/ (not shareable, deletes when uninstalling package)
}
Expand All @@ -298,7 +350,7 @@ public static InputStream getHTTPS(Context context, String server) throws FileNo
* NOTE: different from getHTTPS. Here, we have the MQTT server address/IP as input parameter.
*
* @param context context
* @param server server hostname
* @param server server hostname
* @return Input stream of opened certificate.
* @throws FileNotFoundException
*/
Expand All @@ -308,7 +360,7 @@ static InputStream getCertificate(Context context, String server) throws FileNot

File root_folder;
if (!context.getResources().getBoolean(R.bool.standalone)) {
root_folder = new File(Environment.getExternalStoragePublicDirectory("AWARE")+ "/credentials"); // sdcard/AWARE/ (shareable, does not delete when uninstalling)
root_folder = new File(Environment.getExternalStoragePublicDirectory("AWARE") + "/credentials"); // sdcard/AWARE/ (shareable, does not delete when uninstalling)
} else {
root_folder = new File(ContextCompat.getExternalFilesDirs(context, null)[0] + "/AWARE/credentials"); // sdcard/Android/<app_package_name>/AWARE/ (not shareable, deletes when uninstalling package)
}
Expand Down
94 changes: 43 additions & 51 deletions aware-core/src/main/java/com/aware/utils/WebserviceHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
Expand All @@ -64,28 +61,29 @@ public class WebserviceHelper extends Service {
private static int notificationID = 0;
private static int total_rows_synced = 0;

private static SyncQueue mSyncFastQueue;
private static Looper mServiceLooperFastQueue;
static ExecutorService executorFastQueue;
private SyncQueue mSyncFastQueue;
private Looper mServiceLooperFastQueue;
private ExecutorService executorFastQueue;

private static SyncQueue mSyncSlowQueueA;
private static Looper mServiceLooperSlowQueueA;
static ExecutorService executorSlowQueueA;
private SyncQueue mSyncSlowQueueA;
private Looper mServiceLooperSlowQueueA;
private ExecutorService executorSlowQueueA;

private static SyncQueue mSyncSlowQueueB;
private static Looper mServiceLooperSlowQueueB;
static ExecutorService executorSlowQueueB;
private SyncQueue mSyncSlowQueueB;
private Looper mServiceLooperSlowQueueB;
private ExecutorService executorSlowQueueB;

private static boolean nextSlowQueue = false;

private static ArrayList<String> highFrequencySensors = new ArrayList<>();
private static final ArrayList<String> highFrequencySensors = new ArrayList<>();
private static final ArrayList<String> dontClearSensors = new ArrayList<>();

// Handler that receives messages from the thread
private final class SyncQueue extends Handler {
ExecutorService executor;
public int currentMessage;
public SyncQueue(Looper looper, ExecutorService executor) {
int currentMessage;

SyncQueue(Looper looper, ExecutorService executor) {
super(looper);
// One thread to sync data with the server
this.executor = executor;
Expand Down Expand Up @@ -132,16 +130,13 @@ public void onCreate() {

notificationID = 0;

HandlerThread threadFast = new HandlerThread("SyncFastQueue",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
HandlerThread threadFast = new HandlerThread("SyncFastQueue", android.os.Process.THREAD_PRIORITY_BACKGROUND);
threadFast.start();

HandlerThread threadSlowA = new HandlerThread("SyncSlowAQueue",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
HandlerThread threadSlowA = new HandlerThread("SyncSlowAQueue", android.os.Process.THREAD_PRIORITY_BACKGROUND);
threadSlowA.start();

HandlerThread threadSlowB = new HandlerThread("SyncSlowBQueue",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
HandlerThread threadSlowB = new HandlerThread("SyncSlowBQueue", android.os.Process.THREAD_PRIORITY_BACKGROUND);
threadSlowB.start();

// Get the HandlerThread's Looper and use it for our Handler
Expand Down Expand Up @@ -196,7 +191,6 @@ private void notifyUser(Context mContext, String message, boolean dismiss, boole
private int getBatchSize() {
double availableRam;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {

String load;
try (RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r")) {
load = reader.readLine();
Expand Down Expand Up @@ -258,7 +252,6 @@ public int onStartCommand(Intent intent, int flags, int startId) {
boolean DEBUG = Aware.getSetting(getApplicationContext(), Aware_Preferences.DEBUG_FLAG).equals("true");

if (intent.getAction().equals(ACTION_AWARE_WEBSERVICE_SYNC_TABLE)) {

if (Aware.getSetting(getApplicationContext(), Aware_Preferences.WEBSERVICE_CHARGING).equals("true")) {
Intent batt = getApplicationContext().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int plugged = batt.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
Expand All @@ -273,24 +266,23 @@ public int onStartCommand(Intent intent, int flags, int startId) {
}

//Check if we are supposed to sync over WiFi only
if (Aware.getSetting(getApplicationContext(), Aware_Preferences.WEBSERVICE_WIFI_ONLY).equals("true")) {
ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
if (!(activeNetwork != null && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI && activeNetwork.isConnected())) {
if (Aware.DEBUG)
Log.d(Aware.TAG, "Sync data only over Wi-Fi. Will try again later...");
if (!isWifiNeededAndConnected()) {
if (Aware.DEBUG)
Log.d(Aware.TAG, "Sync data only over Wi-Fi. Will try again later...");

stopSelf();
return START_REDELIVER_INTENT;
}
stopSelf();
return START_REDELIVER_INTENT;
}

// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
String table = intent.getStringExtra(EXTRA_TABLE);

if (Aware.DEBUG) Log.d(Aware.TAG, "Processing " + table);

int tableHash = table.hashCode();
if(mSyncFastQueue.currentMessage != tableHash && mSyncSlowQueueA.currentMessage != tableHash && mSyncSlowQueueB.currentMessage != tableHash &&
!mSyncFastQueue.hasMessages(tableHash) && !mSyncSlowQueueA.hasMessages(tableHash) && !mSyncSlowQueueB.hasMessages(tableHash)){
if (mSyncFastQueue.currentMessage != tableHash && mSyncSlowQueueA.currentMessage != tableHash && mSyncSlowQueueB.currentMessage != tableHash
&& !mSyncFastQueue.hasMessages(tableHash) && !mSyncSlowQueueA.hasMessages(tableHash) && !mSyncSlowQueueB.hasMessages(tableHash)) {
if (!highFrequencySensors.contains(table)) { //Non High Frequency sensors go together
Message msg = buildMessage(mSyncFastQueue, intent, DEBUG, DEVICE_ID, WEBSERVER, WEBSERVICE_SIMPLE, WEBSERVICE_REMOVE_DATA, MAX_POST_SIZE, startId, notificationID++);
mSyncFastQueue.sendMessage(msg);
Expand All @@ -310,6 +302,15 @@ public int onStartCommand(Intent intent, int flags, int startId) {
return START_REDELIVER_INTENT;
}

public boolean isWifiNeededAndConnected() {
if (Aware.getSetting(getApplicationContext(), Aware_Preferences.WEBSERVICE_WIFI_ONLY).equals("true")) {
ConnectivityManager connManager = (ConnectivityManager) getApplicationContext().getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI && activeNetwork.isConnected());
}
return true;
}

private Message buildMessage(SyncQueue queue, Intent intent, boolean DEBUG, String DEVICE_ID, String WEBSERVER, boolean WEBSERVICE_SIMPLE, boolean WEBSERVICE_REMOVE_DATA, int MAX_POST_SIZE, int startId, int notificationID) {
Message msg = queue.obtainMessage(intent.getStringExtra(EXTRA_TABLE).hashCode());
Bundle bundle = new Bundle();
Expand All @@ -329,7 +330,6 @@ private Message buildMessage(SyncQueue queue, Intent intent, boolean DEBUG, Stri
msg.setData(bundle);
msg.arg1 = startId;
return msg;

}

/**
Expand Down Expand Up @@ -570,13 +570,13 @@ private void performDatabaseSpaceMaintenance(Uri CONTENT_URI, long last, String[
cal.add(Calendar.MONTH, -1);
if (Aware.DEBUG)
Log.d(Aware.TAG, " Cleaning locally any data older than last month (yyyy/mm/dd): " + cal.get(Calendar.YEAR) + '/' + (cal.get(Calendar.MONTH) + 1) + '/' + cal.get(Calendar.DAY_OF_MONTH));
rowsDeleted = mContext.getContentResolver().delete(CONTENT_URI, "timestamp < " + cal.getTimeInMillis()+ deleteSessionBasedSensors, null);
rowsDeleted = mContext.getContentResolver().delete(CONTENT_URI, "timestamp < " + cal.getTimeInMillis() + deleteSessionBasedSensors, null);
break;
case 3: //Daily
cal.add(Calendar.DAY_OF_YEAR, -1);
if (Aware.DEBUG)
Log.d(Aware.TAG, "Cleaning locally any data older than today (yyyy/mm/dd): " + cal.get(Calendar.YEAR) + '/' + (cal.get(Calendar.MONTH) + 1) + '/' + cal.get(Calendar.DAY_OF_MONTH) + " from " + CONTENT_URI.toString());
rowsDeleted = mContext.getContentResolver().delete(CONTENT_URI, "timestamp < " + cal.getTimeInMillis()+ deleteSessionBasedSensors, null);
rowsDeleted = mContext.getContentResolver().delete(CONTENT_URI, "timestamp < " + cal.getTimeInMillis() + deleteSessionBasedSensors, null);
break;
case 4: //Always (experimental)
if (highFrequencySensors.contains(DATABASE_TABLE))
Expand Down Expand Up @@ -659,18 +659,9 @@ private long syncBatch(Cursor context_data) throws JSONException {
return lastSynced;
}

boolean isWifiNeededAndConnected() {
if (Aware.getSetting(mContext, Aware_Preferences.WEBSERVICE_WIFI_ONLY).equals("true")) {
ConnectivityManager connManager = (ConnectivityManager) mContext.getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI && activeNetwork.isConnected());
}
return true;
}

private boolean isTableAllowedForMaintenance(String table_name){
private boolean isTableAllowedForMaintenance(String table_name) {
//we need to keep the schedulers and aware_studies tables and on those tables that contain
if(table_name.equalsIgnoreCase("aware_studies") || table_name.equalsIgnoreCase("scheduler"))
if (table_name.equalsIgnoreCase("aware_studies") || table_name.equalsIgnoreCase("scheduler"))
return false;
return true;
}
Expand All @@ -683,7 +674,6 @@ public String call() throws Exception {
String response = createRemoteTable();

if (response != null || WEBSERVICE_SIMPLE) {

try {
String[] columnsStr = getTableColumnsNames(CONTENT_URI);
String latest = getLatestRecordInDatabase();
Expand All @@ -694,8 +684,10 @@ public String call() throws Exception {
if (Aware.DEBUG) {
Log.d(Aware.TAG, "Sync " + DATABASE_TABLE + " exists: " + (response != null && response.length() == 0));
if (!latest.equals("[]")) Log.d(Aware.TAG, "Latest: " + latest);
if (study_condition.length() > 0) Log.d(Aware.TAG, "Since: " + study_condition);
if (total_records > 0) Log.d(Aware.TAG, "Rows to sync: " + total_records);
if (study_condition.length() > 0)
Log.d(Aware.TAG, "Since: " + study_condition);
if (total_records > 0)
Log.d(Aware.TAG, "Rows to sync: " + total_records);
}

if (total_records > 0) {
Expand Down
2 changes: 1 addition & 1 deletion aware-phone/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ android {
versionCode version_code
versionName version_readable
targetSdkVersion 25
minSdkVersion 10 //Android 2.3.3
minSdkVersion 11 //Android 2.3.3
}

signingConfigs {
Expand Down
Loading

0 comments on commit 06d34e7

Please sign in to comment.