diff --git a/client/client/build.gradle b/client/client/build.gradle index ad754179..7f19c6ce 100644 --- a/client/client/build.gradle +++ b/client/client/build.gradle @@ -176,7 +176,7 @@ android { //Publish location changes to server buildConfigField "boolean", "LOCATION_PUBLISHING_ENABLED", "false" //Collect WiFi scan results - buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "false" + buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "true" //Is user consent required for file upload from device to server buildConfigField "boolean", "REQUIRE_CONSENT_FOR_FILE_UPLOAD", "true" } @@ -307,7 +307,7 @@ android { //Publish location changes to server buildConfigField "boolean", "LOCATION_PUBLISHING_ENABLED", "false" //Collect WiFi scan results - buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "false" + buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "true" //Is user consent required for file upload from device to server buildConfigField "boolean", "REQUIRE_CONSENT_FOR_FILE_UPLOAD", "true" debuggable true @@ -576,7 +576,7 @@ android { //Publish location changes to server buildConfigField "boolean", "LOCATION_PUBLISHING_ENABLED", "true" //Collect WiFi scan results - buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "false" + buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "true" //Is user consent required for file upload from device to server buildConfigField "boolean", "REQUIRE_CONSENT_FOR_FILE_UPLOAD", "true" } @@ -709,7 +709,7 @@ android { //Publish location changes to server buildConfigField "boolean", "LOCATION_PUBLISHING_ENABLED", "true" //Collect WiFi scan results - buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "false" + buildConfigField "boolean", "WIFI_SCANNING_ENABLED", "true" //Is user consent required for file upload from device to server buildConfigField "boolean", "REQUIRE_CONSENT_FOR_FILE_UPLOAD", "true" } diff --git a/client/client/src/main/java/org/wso2/iot/agent/beans/Device.java b/client/client/src/main/java/org/wso2/iot/agent/beans/Device.java index 3e063a67..57ba9af9 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/beans/Device.java +++ b/client/client/src/main/java/org/wso2/iot/agent/beans/Device.java @@ -17,6 +17,8 @@ package org.wso2.iot.agent.beans; +import com.fasterxml.jackson.annotation.JsonInclude; + import org.wso2.iot.agent.AndroidAgentException; import org.wso2.iot.agent.utils.CommonUtils; @@ -26,6 +28,7 @@ * This class represents the basic information of * the carbon-device-mgt supported device */ +@JsonInclude(JsonInclude.Include.NON_NULL) public class Device { private String description; diff --git a/client/client/src/main/java/org/wso2/iot/agent/services/AgentStartupReceiver.java b/client/client/src/main/java/org/wso2/iot/agent/services/AgentStartupReceiver.java index 6f8bf0e8..378d8070 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/services/AgentStartupReceiver.java +++ b/client/client/src/main/java/org/wso2/iot/agent/services/AgentStartupReceiver.java @@ -95,6 +95,22 @@ public void onReceive(final Context context, Intent intent) { LocalNotification.startPolling(context); } + /** + * Clear the device info and wifi info payloads stored in shared preference + * when the device restarts. + */ + if(Preference.getString(context, Constants.LAST_DEVICE_INFO_SHARED_PREF) != null) { + Preference.putString(context, Constants.LAST_DEVICE_INFO_SHARED_PREF,null); + } + + if(Preference.getString(context, Constants.LAST_WIFI_SCAN_RESULT_SHARED_PREF) != null) { + Preference.putString(context, Constants.LAST_WIFI_SCAN_RESULT_SHARED_PREF,null); + } + + if(Preference.getString(context, Constants.LAST_APP_LIST_SHARED_PREF) != null) { + Preference.putString(context, Constants.LAST_APP_LIST_SHARED_PREF,null); + } + if (Intent.ACTION_BOOT_COMPLETED.equals(action) || Constants.AGENT_UPDATED_BROADCAST_ACTION.equals(action)) { if (Constants.OWNERSHIP_COSU.equals(Constants.DEFAULT_OWNERSHIP)) { Preference.putBoolean(context.getApplicationContext(), Constants.AGENT_FRESH_START, true); diff --git a/client/client/src/main/java/org/wso2/iot/agent/services/DeviceInfoPayload.java b/client/client/src/main/java/org/wso2/iot/agent/services/DeviceInfoPayload.java index ac8b0f5e..d6b894bc 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/services/DeviceInfoPayload.java +++ b/client/client/src/main/java/org/wso2/iot/agent/services/DeviceInfoPayload.java @@ -26,6 +26,8 @@ import android.os.Build; import android.support.v4.app.ActivityCompat; import android.telephony.TelephonyManager; +import android.util.ArrayMap; +import android.util.Base64; import android.util.Log; import com.fasterxml.jackson.core.JsonProcessingException; @@ -41,8 +43,15 @@ import org.wso2.iot.agent.utils.Constants; import org.wso2.iot.agent.utils.Preference; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This class handles building of the device information payload to be sent to the server. @@ -96,16 +105,31 @@ public void build() throws AndroidAgentException { * * @throws AndroidAgentException on error */ - @SuppressLint("HardwareIds") + @SuppressLint({"HardwareIds"}) private void getInfo() throws AndroidAgentException { + HashMap keyValPair = null; + if (Preference.getString(context, Constants.LAST_DEVICE_INFO_SHARED_PREF) != null) { + String lastUpdatedInfoString = Preference.getString(context, Constants.LAST_DEVICE_INFO_SHARED_PREF); + byte[] lastUpdatedInfoByteArray = Base64.decode(lastUpdatedInfoString, Base64.DEFAULT); + ByteArrayInputStream bais = new ByteArrayInputStream(lastUpdatedInfoByteArray); + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(bais); + keyValPair = (HashMap) ois.readObject(); + } catch (IOException e) { + throw new AndroidAgentException("Error occurred while deserialize Device object", e); + } catch (ClassNotFoundException e) { + throw new AndroidAgentException("Error occurred while casting to Device object", e); + } + } else { + keyValPair = new HashMap(); + } TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - if (!CommonUtils.isServiceRunning(context, NetworkInfoService.class)) { Intent serviceIntent = new Intent(context, NetworkInfoService.class); context.startService(serviceIntent); } - Location deviceLocation = CommonUtils.getLocation(context); if (device == null) { device = new Device(); @@ -113,158 +137,237 @@ private void getInfo() throws AndroidAgentException { deviceInfo = new DeviceInfo(context); Power power = phoneState.getBatteryDetails(); device.setDeviceIdentifier(deviceInfo.getDeviceId()); - device.setDescription(deviceInfo.getDeviceName()); + keyValPair.put(Constants.Device.DEVICE_IDENTIFIER, deviceInfo.getDeviceId()); device.setName(deviceInfo.getDeviceName()); - + device.setDescription(deviceInfo.getDeviceName()); + keyValPair.put(Constants.Device.DEVICE_NAME, deviceInfo.getDeviceName()); List properties = new ArrayList<>(); - - Device.Property property = new Device.Property(); - property.setName(Constants.Device.SERIAL); - property.setValue(deviceInfo.getDeviceSerialNumber()); - properties.add(property); - - if (telephonyManager != null - && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { + Device.Property property = null; + if ((keyValPair.get(Constants.Device.SERIAL) == null) || + !keyValPair.get(Constants.Device.SERIAL).toString().equals(deviceInfo.getDeviceSerialNumber())) { property = new Device.Property(); - property.setName(Constants.Device.IMEI); - property.setValue(telephonyManager.getDeviceId()); + property.setName(Constants.Device.SERIAL); + property.setValue(deviceInfo.getDeviceSerialNumber()); properties.add(property); + keyValPair.put(Constants.Device.SERIAL, deviceInfo.getDeviceSerialNumber().toString()); + } + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED) { + if ((keyValPair.get(Constants.Device.IMEI) == null) || !keyValPair.get(Constants.Device.IMEI).toString() + .equals(telephonyManager.getDeviceId())) { + property = new Device.Property(); + property.setName(Constants.Device.IMEI); + property.setValue(telephonyManager.getDeviceId()); + properties.add(property); + keyValPair.put(Constants.Device.IMEI, telephonyManager.getDeviceId()); + } + } + if ((keyValPair.get(Constants.Device.IMSI) == null) || + !keyValPair.get(Constants.Device.IMSI).toString().equals(deviceInfo.getIMSINumber())) { + property = new Device.Property(); + property.setName(Constants.Device.IMSI); + property.setValue(deviceInfo.getIMSINumber()); + properties.add(property); + keyValPair.put(Constants.Device.IMSI, deviceInfo.getIMSINumber()); + } + if ((keyValPair.get(Constants.Device.MAC) == null) || + !keyValPair.get(Constants.Device.MAC).toString().equals(deviceInfo.getMACAddress())) { + property = new Device.Property(); + property.setName(Constants.Device.MAC); + property.setValue(deviceInfo.getMACAddress()); + properties.add(property); + keyValPair.put(Constants.Device.MAC, deviceInfo.getMACAddress()); + } + if ((keyValPair.get(Constants.Device.MODEL) == null) || + !keyValPair.get(Constants.Device.MODEL).toString() + .equals(deviceInfo.getDeviceModel())) { + property = new Device.Property(); + property.setName(Constants.Device.MODEL); + property.setValue(deviceInfo.getDeviceModel()); + properties.add(property); + keyValPair.put(Constants.Device.MODEL, deviceInfo.getDeviceModel()); + } + if ((keyValPair.get(Constants.Device.VENDOR) == null) || + !keyValPair.get(Constants.Device.VENDOR).toString() + .equals(deviceInfo.getDeviceManufacturer())) { + property = new Device.Property(); + property.setName(Constants.Device.VENDOR); + property.setValue(deviceInfo.getDeviceManufacturer()); + properties.add(property); + keyValPair.put(Constants.Device.VENDOR, deviceInfo.getDeviceManufacturer()); + } + if ((keyValPair.get(Constants.Device.OS) == null) + || !keyValPair.get(Constants.Device.OS).toString().equals(deviceInfo.getOsVersion())) { + property = new Device.Property(); + property.setName(Constants.Device.OS); + property.setValue(deviceInfo.getOsVersion()); + properties.add(property); + keyValPair.put(Constants.Device.OS, deviceInfo.getOsVersion()); + } + if ((keyValPair.get(Constants.Device.OS_BUILD_DATE) == null) + || !keyValPair.get(Constants.Device.OS_BUILD_DATE).toString() + .equals(deviceInfo.getOSBuildDate())) { + property = new Device.Property(); + property.setName(Constants.Device.OS_BUILD_DATE); + property.setValue(deviceInfo.getOSBuildDate()); + properties.add(property); + keyValPair.put(Constants.Device.OS_BUILD_DATE, deviceInfo.getOSBuildDate()); } - - property = new Device.Property(); - property.setName(Constants.Device.IMSI); - property.setValue(deviceInfo.getIMSINumber()); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MAC); - property.setValue(deviceInfo.getMACAddress()); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MODEL); - property.setValue(deviceInfo.getDeviceModel()); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.VENDOR); - property.setValue(deviceInfo.getDeviceManufacturer()); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.OS); - property.setValue(deviceInfo.getOsVersion()); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.OS_BUILD_DATE); - property.setValue(deviceInfo.getOSBuildDate()); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.NAME); - property.setValue(deviceInfo.getDeviceName()); - properties.add(property); - if (deviceLocation != null) { double latitude = deviceLocation.getLatitude(); double longitude = deviceLocation.getLongitude(); if (latitude != 0 && longitude != 0) { + if ((keyValPair.get(Constants.Device.MOBILE_DEVICE_LATITUDE) == null) + || !keyValPair.get(Constants.Device.MOBILE_DEVICE_LATITUDE).toString() + .equals(String.valueOf(latitude))) { + property = new Device.Property(); + property.setName(Constants.Device.MOBILE_DEVICE_LATITUDE); + property.setValue(String.valueOf(latitude)); + properties.add(property); + keyValPair.put(Constants.Device.MOBILE_DEVICE_LATITUDE, String.valueOf(latitude)); + } + if ((keyValPair.get(Constants.Device.MOBILE_DEVICE_LONGITUDE) == null) + || !keyValPair.get(Constants.Device.MOBILE_DEVICE_LONGITUDE).toString() + .equals(String.valueOf(longitude))) { + property = new Device.Property(); + property.setName(Constants.Device.MOBILE_DEVICE_LONGITUDE); + property.setValue(String.valueOf(longitude)); + properties.add(property); + keyValPair.put(Constants.Device.MOBILE_DEVICE_LONGITUDE, String.valueOf(longitude)); + } + } + } + if (registrationId != null) { + if ((keyValPair.get(Constants.Device.FCM_TOKEN) == null) + || !keyValPair.get(Constants.Device.FCM_TOKEN).toString() + .equals(registrationId)) { property = new Device.Property(); - property.setName(Constants.Device.MOBILE_DEVICE_LATITUDE); - property.setValue(String.valueOf(latitude)); - properties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MOBILE_DEVICE_LONGITUDE); - property.setValue(String.valueOf(longitude)); + property.setName(Constants.Device.FCM_TOKEN); + property.setValue(registrationId); properties.add(property); + keyValPair.put(Constants.Device.FCM_TOKEN, registrationId); } } - - if (registrationId != null) { + List deviceInfoProperties = new ArrayList<>(); + if ((keyValPair.get(Constants.Device.ENCRYPTION_STATUS) == null) || !keyValPair + .get(Constants.Device.ENCRYPTION_STATUS).toString() + .equals(String.valueOf(deviceInfo.isEncryptionEnabled()))) { property = new Device.Property(); - property.setName(Constants.Device.FCM_TOKEN); - property.setValue(registrationId); - properties.add(property); + property.setName(Constants.Device.ENCRYPTION_STATUS); + property.setValue(String.valueOf(deviceInfo.isEncryptionEnabled())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.ENCRYPTION_STATUS, String.valueOf(deviceInfo.isEncryptionEnabled())); } - - List deviceInfoProperties = new ArrayList<>(); - - property = new Device.Property(); - property.setName(Constants.Device.ENCRYPTION_STATUS); - property.setValue(String.valueOf(deviceInfo.isEncryptionEnabled())); - deviceInfoProperties.add(property); - if ((deviceInfo.getSdkVersion() >= Build.VERSION_CODES.LOLLIPOP)) { + if ((keyValPair.get(Constants.Device.PASSCODE_STATUS) == null) || !keyValPair + .get(Constants.Device.PASSCODE_STATUS).toString() + .equals(String.valueOf(deviceInfo.isPasscodeEnabled()))) { + property = new Device.Property(); + property.setName(Constants.Device.PASSCODE_STATUS); + property.setValue(String.valueOf(deviceInfo.isPasscodeEnabled())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.PASSCODE_STATUS, String.valueOf(deviceInfo.isPasscodeEnabled())); + } + } + if ((keyValPair.get(Constants.Device.BATTERY_LEVEL) == null) || + !keyValPair.get(Constants.Device.BATTERY_LEVEL).toString() + .equals(String.valueOf(Math.round(power.getLevel())))) { property = new Device.Property(); - property.setName(Constants.Device.PASSCODE_STATUS); - property.setValue(String.valueOf(deviceInfo.isPasscodeEnabled())); + property.setName(Constants.Device.BATTERY_LEVEL); + int batteryLevel = Math.round(power.getLevel()); + property.setValue(String.valueOf(batteryLevel)); deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.BATTERY_LEVEL, String.valueOf(batteryLevel)); } - - property = new Device.Property(); - property.setName(Constants.Device.BATTERY_LEVEL); - int batteryLevel = Math.round(power.getLevel()); - property.setValue(String.valueOf(batteryLevel)); - deviceInfoProperties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MEMORY_INFO_INTERNAL_TOTAL); - property.setValue(String.valueOf(phoneState.getTotalInternalMemorySize())); - deviceInfoProperties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MEMORY_INFO_INTERNAL_AVAILABLE); - property.setValue(String.valueOf(phoneState.getAvailableInternalMemorySize())); - deviceInfoProperties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MEMORY_INFO_EXTERNAL_TOTAL); - property.setValue(String.valueOf(phoneState.getTotalExternalMemorySize())); - deviceInfoProperties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.MEMORY_INFO_EXTERNAL_AVAILABLE); - property.setValue(String.valueOf(phoneState.getAvailableExternalMemorySize())); - deviceInfoProperties.add(property); - - property = new Device.Property(); - property.setName(Constants.Device.NETWORK_OPERATOR); - property.setValue(String.valueOf(deviceInfo.getNetworkOperatorName())); - deviceInfoProperties.add(property); - - if (telephonyManager != null - && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { + if ((keyValPair.get(Constants.Device.MEMORY_INFO_INTERNAL_TOTAL) == null) || !keyValPair + .get(Constants.Device.MEMORY_INFO_INTERNAL_TOTAL).toString() + .equals(String.valueOf(phoneState.getTotalInternalMemorySize()))) { + property = new Device.Property(); + property.setName(Constants.Device.MEMORY_INFO_INTERNAL_TOTAL); + property.setValue(String.valueOf(phoneState.getTotalInternalMemorySize())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.MEMORY_INFO_INTERNAL_TOTAL, + String.valueOf(phoneState.getTotalInternalMemorySize())); + } + if ((keyValPair.get(Constants.Device.MEMORY_INFO_INTERNAL_AVAILABLE) == null) || !keyValPair + .get(Constants.Device.MEMORY_INFO_INTERNAL_AVAILABLE).toString() + .equals(String.valueOf(phoneState.getAvailableInternalMemorySize()))) { + property = new Device.Property(); + property.setName(Constants.Device.MEMORY_INFO_INTERNAL_AVAILABLE); + property.setValue(String.valueOf(phoneState.getAvailableInternalMemorySize())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.MEMORY_INFO_INTERNAL_AVAILABLE, + String.valueOf(phoneState.getAvailableInternalMemorySize())); + } + if ((keyValPair.get(Constants.Device.MEMORY_INFO_EXTERNAL_TOTAL) == null) || !keyValPair + .get(Constants.Device.MEMORY_INFO_EXTERNAL_TOTAL).toString() + .equals(String.valueOf(phoneState.getTotalExternalMemorySize()))) { + property = new Device.Property(); + property.setName(Constants.Device.MEMORY_INFO_EXTERNAL_TOTAL); + property.setValue(String.valueOf(phoneState.getTotalExternalMemorySize())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.MEMORY_INFO_EXTERNAL_TOTAL, + String.valueOf(phoneState.getTotalExternalMemorySize())); + } + if ((keyValPair.get(Constants.Device.MEMORY_INFO_EXTERNAL_AVAILABLE) == null) || !keyValPair + .get(Constants.Device.MEMORY_INFO_EXTERNAL_AVAILABLE).toString() + .equals(String.valueOf(phoneState.getAvailableExternalMemorySize()))) { + property = new Device.Property(); + property.setName(Constants.Device.MEMORY_INFO_EXTERNAL_AVAILABLE); + property.setValue(String.valueOf(phoneState.getAvailableExternalMemorySize())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.MEMORY_INFO_EXTERNAL_AVAILABLE, + String.valueOf(phoneState.getAvailableExternalMemorySize())); + } + if ((keyValPair.get(Constants.Device.NETWORK_OPERATOR) == null) || !keyValPair + .get(Constants.Device.NETWORK_OPERATOR).toString() + .equals(String.valueOf(deviceInfo.getNetworkOperatorName()))) { + property = new Device.Property(); + property.setName(Constants.Device.NETWORK_OPERATOR); + property.setValue(String.valueOf(deviceInfo.getNetworkOperatorName())); + deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.NETWORK_OPERATOR, + String.valueOf(deviceInfo.getNetworkOperatorName())); + } + if (telephonyManager != null && ActivityCompat + .checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED) { String mPhoneNumber = telephonyManager.getLine1Number(); - if (mPhoneNumber != null) { + + if ((mPhoneNumber != null) && ((keyValPair.get(Constants.Device.PHONE_NUMBER) == null) || !keyValPair + .get(Constants.Device.PHONE_NUMBER).toString().equals(mPhoneNumber))) { property = new Device.Property(); property.setName(Constants.Device.PHONE_NUMBER); property.setValue(mPhoneNumber); deviceInfoProperties.add(property); + keyValPair.put(Constants.Device.PHONE_NUMBER, mPhoneNumber); } } - try { String network = NetworkInfoService.getNetworkStatus(); - if (network != null) { + if ((network != null) && ((keyValPair.get(Constants.Device.NETWORK_INFO) == null) || !keyValPair + .get(Constants.Device.NETWORK_INFO).toString().equals(network))) { property = new Device.Property(); property.setName(Constants.Device.NETWORK_INFO); property.setValue(network); properties.add(property); + keyValPair.put(Constants.Device.NETWORK_INFO, network); } if (Constants.WIFI_SCANNING_ENABLED) { - // adding wifi scan results.. - property = new Device.Property(); - property.setName(Constants.Device.WIFI_SCAN_RESULT); - property.setValue(NetworkInfoService.getWifiScanResult()); - properties.add(property); + String wifiScanResult = NetworkInfoService.getWifiScanResult(context); + if ((network != null) && ((keyValPair.get(Constants.Device.WIFI_SCAN_RESULT) == null) || !keyValPair + .get(Constants.Device.WIFI_SCAN_RESULT).toString().equals(wifiScanResult))) { + property = new Device.Property(); + property.setName(Constants.Device.WIFI_SCAN_RESULT); + property.setValue(wifiScanResult); + properties.add(property); + keyValPair.put(Constants.Device.WIFI_SCAN_RESULT, wifiScanResult); + } } } catch (AndroidAgentException e) { Log.e(TAG, "Error retrieving network status. " + e.getMessage()); } - RuntimeInfo runtimeInfo = new RuntimeInfo(context); String cpuInfoPayload; try { @@ -275,11 +378,14 @@ private void getInfo() throws AndroidAgentException { throw new AndroidAgentException(errorMsg, e); } - property = new Device.Property(); - property.setName(Constants.Device.CPU_INFO); - property.setValue(cpuInfoPayload); - properties.add(property); - + if ((keyValPair.get(Constants.Device.CPU_INFO) == null) || + !keyValPair.get(Constants.Device.CPU_INFO).toString().equals(cpuInfoPayload)) { + property = new Device.Property(); + property.setName(Constants.Device.CPU_INFO); + property.setValue(cpuInfoPayload); + properties.add(property); + keyValPair.put(Constants.Device.CPU_INFO, cpuInfoPayload); + } String ramInfoPayload; try { ramInfoPayload = mapper.writeValueAsString(runtimeInfo.getRAMInfo()); @@ -288,43 +394,39 @@ private void getInfo() throws AndroidAgentException { Log.e(TAG, errorMsg, e); throw new AndroidAgentException(errorMsg, e); } - - property = new Device.Property(); - property.setName(Constants.Device.RAM_INFO); - property.setValue(ramInfoPayload); - properties.add(property); - + if ((keyValPair.get(Constants.Device.RAM_INFO) == null) || (keyValPair.get(Constants.Device.RAM_INFO) != null + && !keyValPair.get(Constants.Device.RAM_INFO).toString().equals(ramInfoPayload))) { + property = new Device.Property(); + property.setName(Constants.Device.RAM_INFO); + property.setValue(ramInfoPayload); + properties.add(property); + keyValPair.put(Constants.Device.RAM_INFO, ramInfoPayload); + } List batteryProperties = new ArrayList<>(); property = new Device.Property(); property.setName(Constants.Device.BATTERY_LEVEL); property.setValue(String.valueOf(power.getLevel())); batteryProperties.add(property); - property = new Device.Property(); property.setName(Constants.Device.SCALE); property.setValue(String.valueOf(power.getScale())); batteryProperties.add(property); - property = new Device.Property(); property.setName(Constants.Device.BATTERY_VOLTAGE); property.setValue(String.valueOf(power.getVoltage())); batteryProperties.add(property); - property = new Device.Property(); property.setName(Constants.Device.HEALTH); property.setValue(String.valueOf(power.getHealth())); batteryProperties.add(property); - property = new Device.Property(); property.setName(Constants.Device.STATUS); property.setValue(String.valueOf(power.getStatus())); batteryProperties.add(property); - property = new Device.Property(); property.setName(Constants.Device.PLUGGED); property.setValue(String.valueOf(power.getPlugged())); batteryProperties.add(property); - String batteryInfoPayload; try { batteryInfoPayload = mapper.writeValueAsString(batteryProperties); @@ -333,12 +435,14 @@ private void getInfo() throws AndroidAgentException { Log.e(TAG, errorMsg, e); throw new AndroidAgentException(errorMsg, e); } - - property = new Device.Property(); - property.setName(Constants.Device.BATTERY_INFO); - property.setValue(batteryInfoPayload); - properties.add(property); - + if ((keyValPair.get(Constants.Device.BATTERY_INFO) == null) || + !keyValPair.get(Constants.Device.BATTERY_INFO).toString().equals(batteryInfoPayload)) { + property = new Device.Property(); + property.setName(Constants.Device.BATTERY_INFO); + property.setValue(batteryInfoPayload); + properties.add(property); + keyValPair.put(Constants.Device.BATTERY_INFO, batteryInfoPayload); + } // building device info json payload String deviceInfoPayload; try { @@ -348,12 +452,25 @@ private void getInfo() throws AndroidAgentException { Log.e(TAG, errorMsg, e); throw new AndroidAgentException(errorMsg, e); } - property = new Device.Property(); - property.setName(Constants.Device.INFO); - property.setValue(deviceInfoPayload); - properties.add(property); - + if ((keyValPair.get(Constants.Device.INFO) == null) || !keyValPair + .get(Constants.Device.INFO).toString().equals(deviceInfoPayload)) { + property = new Device.Property(); + property.setName(Constants.Device.INFO); + property.setValue(deviceInfoPayload); + properties.add(property); + keyValPair.put(Constants.Device.INFO, deviceInfoPayload); + } device.setProperties(properties); + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + try { + ObjectOutputStream oos = new ObjectOutputStream(bao); + oos.writeObject(keyValPair); + String stringObject = null; + stringObject = Base64.encodeToString(bao.toByteArray(), Base64.DEFAULT); + Preference.putString(context, Constants.LAST_DEVICE_INFO_SHARED_PREF, stringObject); + } catch (IOException e) { + throw new AndroidAgentException("Error occurred while serializing policy operation object", e); + } } /** diff --git a/client/client/src/main/java/org/wso2/iot/agent/services/NetworkInfoService.java b/client/client/src/main/java/org/wso2/iot/agent/services/NetworkInfoService.java index 7a51ec40..2cb60ebc 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/services/NetworkInfoService.java +++ b/client/client/src/main/java/org/wso2/iot/agent/services/NetworkInfoService.java @@ -33,6 +33,7 @@ import android.telephony.PhoneStateListener; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; +import android.util.Base64; import android.util.Log; import com.fasterxml.jackson.core.JsonProcessingException; @@ -44,9 +45,18 @@ import org.wso2.iot.agent.AndroidAgentException; import org.wso2.iot.agent.beans.Device; import org.wso2.iot.agent.utils.Constants; +import org.wso2.iot.agent.utils.Preference; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.logging.Level; public class NetworkInfoService extends Service { @@ -61,6 +71,7 @@ public class NetworkInfoService extends Service { private TelephonyManager telephonyManager; private static final int DEFAULT_AGE = 0; + private static final String SSID = "ssid"; private static final String MAC_ADDRESS = "macAddress"; private static final String SIGNAL_STRENGTH = "signalStrength"; private static final String AGE = "age"; @@ -175,13 +186,16 @@ public static String getNetworkStatus() throws AndroidAgentException { property.setName(Constants.Device.MOBILE_CONNECTION_TYPE); property.setValue(info.getSubtypeName()); properties.add(property); + property = new Device.Property(); + property.setName(Constants.Device.MOBILE_SIGNAL_STRENGTH); + property.setValue(String.valueOf(getCellSignalStrength())); + properties.add(property); } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { property = new Device.Property(); property.setName(Constants.Device.WIFI_SSID); // NetworkInfo API of Android seem to add extra "" to SSID, therefore escaping it. property.setValue(String.valueOf(thisInstance.getWifiSSID()).replaceAll("\"", "")); properties.add(property); - property = new Device.Property(); property.setName(Constants.Device.WIFI_SIGNAL_STRENGTH); property.setValue(String.valueOf(thisInstance.getWifiSignalStrength())); @@ -189,11 +203,6 @@ public static String getNetworkStatus() throws AndroidAgentException { } } - property = new Device.Property(); - property.setName(Constants.Device.MOBILE_SIGNAL_STRENGTH); - property.setValue(String.valueOf(getCellSignalStrength())); - properties.add(property); - try { payload = mapper.writeValueAsString(properties); } catch (JsonProcessingException e) { @@ -214,25 +223,66 @@ public static void setCellSignalStrength(int cellSignalStrength) { NetworkInfoService.cellSignalStrength = cellSignalStrength; } - public static String getWifiScanResult() throws AndroidAgentException { + private static double compareSignalStrength(int previousSignalStrength, int newSignalStrength) { + int val = ((newSignalStrength - previousSignalStrength) / newSignalStrength) * 100; + if (val >= 0) { + return val; + } else { + return -1 * val; + } + } + + public static String getWifiScanResult(Context context) throws AndroidAgentException { if (wifiScanResults != null) { + Map wifiScanResultsMap = null; + if (Preference.getString(context, Constants.LAST_WIFI_SCAN_RESULT_SHARED_PREF) != null) { + String lastUpdatedInfoString = Preference.getString(context, Constants.LAST_WIFI_SCAN_RESULT_SHARED_PREF); + byte[] lastUpdatedInfoByteArray = Base64.decode(lastUpdatedInfoString, Base64.DEFAULT); + ByteArrayInputStream bais = new ByteArrayInputStream(lastUpdatedInfoByteArray); + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(bais); + wifiScanResultsMap = (HashMap) ois.readObject(); + } catch (IOException e) { + throw new AndroidAgentException("Error occurred while deserialize lastWifiScanResultsMap object", e); + } catch (ClassNotFoundException e) { + throw new AndroidAgentException("Error occurred while casting to lastWifiScanResultsMap object", e); + } + } else { + wifiScanResultsMap = new HashMap<>(); + } try { JSONArray scanResults = new JSONArray(); JSONObject scanResult; for (ScanResult result : wifiScanResults) { - scanResult = new JSONObject(); - scanResult.put(MAC_ADDRESS, result.BSSID); - scanResult.put(SIGNAL_STRENGTH, result.level); - scanResult.put(AGE, DEFAULT_AGE); - scanResult.put(CHANNEL, result.frequency); - scanResult.put(SNR, result.level); // temporarily added - scanResults.put(scanResult); + if (!wifiScanResultsMap.containsKey(result.wifiSsid.toString()) || compareSignalStrength( + Integer.valueOf(wifiScanResultsMap.get(result.wifiSsid.toString())), result.level) >= 0.2) { + scanResult = new JSONObject(); + scanResult.put(SSID, result.wifiSsid); + scanResult.put(MAC_ADDRESS, result.BSSID); + scanResult.put(SIGNAL_STRENGTH, result.level); + scanResult.put(AGE, DEFAULT_AGE); + scanResult.put(CHANNEL, result.frequency); + scanResult.put(SNR, result.level); // temporarily added + scanResults.put(scanResult); + wifiScanResultsMap.put(result.wifiSsid.toString(), result.level); + } } if (Constants.DEBUG_MODE_ENABLED) { Log.d(TAG, "Wifi scan result: " + scanResults.toString()); } // scanning for next round thisInstance.startWifiScan(); + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + try { + ObjectOutputStream oos = new ObjectOutputStream(bao); + oos.writeObject(wifiScanResultsMap); + String stringObject = null; + stringObject = Base64.encodeToString(bao.toByteArray(), Base64.DEFAULT); + Preference.putString(context, Constants.LAST_WIFI_SCAN_RESULT_SHARED_PREF, stringObject); + } catch (IOException e) { + throw new AndroidAgentException("Error occurred while serializing lastWifiScanResultsMap object", e); + } return scanResults.toString(); } catch (JSONException e) { String msg = "Error occurred while retrieving wifi scan results"; diff --git a/client/client/src/main/java/org/wso2/iot/agent/services/operation/OperationManager.java b/client/client/src/main/java/org/wso2/iot/agent/services/operation/OperationManager.java index 3958b4d1..3dc2d0c7 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/services/operation/OperationManager.java +++ b/client/client/src/main/java/org/wso2/iot/agent/services/operation/OperationManager.java @@ -40,6 +40,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; import org.apache.commons.io.input.ReversedLinesFileReader; import org.json.JSONArray; @@ -90,8 +94,10 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Calendar; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public abstract class OperationManager implements APIResultCallBack, VersionBasedOperations { @@ -284,6 +290,34 @@ public void getApplicationList(org.wso2.iot.agent.beans.Operation operation) thr JSONArray result = new JSONArray(); RuntimeInfo runtimeInfo = new RuntimeInfo(context); Map applications = runtimeInfo.getAppMemory(); + Gson gson = new Gson(); + JsonElement element = null; + if (Preference.getString(context, Constants.LAST_APP_LIST_SHARED_PREF) == null) { + element = gson.toJsonTree(apps, new TypeToken>() { + }.getType()); + if (!element.isJsonArray()) { + throw new AndroidAgentException("Invalid JSON format. Not JSON array."); + } + String applicationList = element.getAsJsonArray().toString().replace(" ", ""); + Preference.putString(context, Constants.LAST_APP_LIST_SHARED_PREF, applicationList); + } else { + String previousAppList = Preference.getString(context, Constants.LAST_APP_LIST_SHARED_PREF); + element = gson.toJsonTree(apps, new TypeToken>() { + }.getType()); + if (!element.isJsonArray()) { + throw new AndroidAgentException("Invalid JSON format. Not JSON array."); + } + String newApplicationList = element.getAsJsonArray().toString().replace(" ", ""); + if (previousAppList.equals(newApplicationList)) { + operation.setOperationResponse(Constants.NO_APPLIST_CHANGE); + operation.setStatus(resources.getString(R.string.operation_value_completed)); + resultBuilder.build(operation); + return; + } else { + Preference.putString(context, Constants.LAST_APP_LIST_SHARED_PREF, newApplicationList); + } + } + for (DeviceAppInfo infoApp : apps) { JSONObject app = new JSONObject(); try { @@ -1164,7 +1198,7 @@ public void connectToRemoteSession(org.wso2.iot.agent.beans.Operation operation) Object serverUrl = payload.get("serverUrl"); Object uuidToValidateDevice = payload.get("uuidToValidateDevice"); if (serverUrl != null) { - if(uuidToValidateDevice != null) { + if (uuidToValidateDevice != null) { // Initialize web socket session WebSocketSessionHandler.getInstance(context).initializeSession(serverUrl.toString(), operation.getId(), uuidToValidateDevice.toString()); diff --git a/client/client/src/main/java/org/wso2/iot/agent/utils/CommonUtils.java b/client/client/src/main/java/org/wso2/iot/agent/utils/CommonUtils.java index 8e296283..2bcc305f 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/utils/CommonUtils.java +++ b/client/client/src/main/java/org/wso2/iot/agent/utils/CommonUtils.java @@ -40,6 +40,7 @@ import android.util.Log; import android.widget.Toast; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; @@ -259,6 +260,7 @@ public static boolean isNetworkAvailable(Context context) { public static String toJSON (Object obj) throws AndroidAgentException { try { ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return mapper.writeValueAsString(obj); } catch (JsonMappingException e) { throw new AndroidAgentException("Error occurred while mapping class to json", e); diff --git a/client/client/src/main/java/org/wso2/iot/agent/utils/Constants.java b/client/client/src/main/java/org/wso2/iot/agent/utils/Constants.java index fbcf8e9d..40a929a3 100644 --- a/client/client/src/main/java/org/wso2/iot/agent/utils/Constants.java +++ b/client/client/src/main/java/org/wso2/iot/agent/utils/Constants.java @@ -216,6 +216,14 @@ public class Constants { public static final int DEFAULT_START_INTERVAL = BuildConfig.DEFAULT_START_TIME; public static final boolean FCM_FALLBACK_PULL_ENABLED = BuildConfig.FCM_FALLBACK_PULL_ENABLED; + /** + * Device info payload. + */ + public static final String LAST_DEVICE_INFO_SHARED_PREF = "lastDeviceObject"; + public static final String LAST_WIFI_SCAN_RESULT_SHARED_PREF = "lastWifiScanResultsMap"; + public static final String LAST_APP_LIST_SHARED_PREF = "lastApplicationList"; + public static final String NO_APPLIST_CHANGE = "SAME_APPLICATION_LIST"; + /** * HTTP clients */ @@ -484,6 +492,8 @@ public final class Device { public static final String PID = "PID"; public static final String SHARED_DIRTY = "SHARED_DIRTY"; public static final String PHONE_NUMBER = "PHONE_NUMBER"; + public static final String DEVICE_IDENTIFIER = "DEVICE_IDENTIFIER"; + public static final String DEVICE_NAME = "DEVICE_NAME"; private Device() { throw new AssertionError();