summaryrefslogtreecommitdiff
path: root/android/sdl_android/src/main/java/com/smartdevicelink/managers
diff options
context:
space:
mode:
authorBilal Alsharifi <599206+bilal-alsharifi@users.noreply.github.com>2020-04-29 13:02:16 -0400
committerGitHub <noreply@github.com>2020-04-29 13:02:16 -0400
commitb7a905eba90d49bb9132e69ab295713238d4abcc (patch)
tree54a21a344b63a21f3bd9391b34f869a2ba99881d /android/sdl_android/src/main/java/com/smartdevicelink/managers
parent797b7a14a7fd67fdf6faa504865e4e22228858ef (diff)
parent9fe2e3481ba6ca1f3c82f740ade9c76fe842ed20 (diff)
downloadsdl_android-b7a905eba90d49bb9132e69ab295713238d4abcc.tar.gz
Merge pull request #1337 from smartdevicelink/release/4.11-RC4.11.0
v4.11 Release
Diffstat (limited to 'android/sdl_android/src/main/java/com/smartdevicelink/managers')
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java35
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java13
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java14
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java189
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenDeviceIconManager.java214
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java36
-rw-r--r--android/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java51
7 files changed, 478 insertions, 74 deletions
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
index 41202fab6..b0ff164cd 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManager.java
@@ -44,6 +44,7 @@ import android.util.Log;
import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.managers.audio.AudioStreamManager;
import com.smartdevicelink.managers.file.FileManager;
+import com.smartdevicelink.managers.file.FileManagerConfig;
import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate;
import com.smartdevicelink.managers.lockscreen.LockScreenConfig;
@@ -120,6 +121,7 @@ public class SdlManager extends BaseSdlManager{
private SdlManagerListener managerListener;
private List<Class<? extends SdlSecurityBase>> sdlSecList;
private LockScreenConfig lockScreenConfig;
+ private FileManagerConfig fileManagerConfig;
private ServiceEncryptionListener serviceEncryptionListener;
// Managers
@@ -308,7 +310,7 @@ public class SdlManager extends BaseSdlManager{
protected void initialize(){
// Instantiate sub managers
this.permissionManager = new PermissionManager(_internalInterface);
- this.fileManager = new FileManager(_internalInterface, context);
+ this.fileManager = new FileManager(_internalInterface, context, fileManagerConfig);
if (lockScreenConfig.isEnabled()) {
this.lockScreenManager = new LockScreenManager(lockScreenConfig, context, _internalInterface);
}
@@ -513,6 +515,8 @@ public class SdlManager extends BaseSdlManager{
protected LockScreenConfig getLockScreenConfig() { return lockScreenConfig; }
+ protected FileManagerConfig getFileManagerConfig() { return fileManagerConfig; }
+
// SENDING REQUESTS
/**
@@ -863,6 +867,19 @@ public class SdlManager extends BaseSdlManager{
}
@Override
+ public RegisterAppInterfaceResponse getRegisterAppInterfaceResponse() {
+ return proxy.getRegisterAppInterfaceResponse();
+ }
+
+ @Override
+ public Object getCapability(SystemCapabilityType systemCapabilityType, OnSystemCapabilityListener scListener, boolean forceUpdate) {
+ if (proxy != null && proxy.getSystemCapabilityManager() != null) {
+ return proxy.getSystemCapabilityManager().getCapability(systemCapabilityType, scListener, forceUpdate);
+ }
+ return null;
+ }
+
+ @Override
public boolean isCapabilitySupported(SystemCapabilityType systemCapabilityType){
return proxy.isCapabilitySupported(systemCapabilityType);
}
@@ -1030,6 +1047,17 @@ public class SdlManager extends BaseSdlManager{
}
/**
+ * Sets the FileManagerConfig for the session.<br>
+ * <strong>Note: If not set, the default configuration value of 1 will be set for
+ * artworkRetryCount and fileRetryCount in FileManagerConfig</strong>
+ * @param fileManagerConfig - configuration options
+ */
+ public Builder setFileManagerConfig (final FileManagerConfig fileManagerConfig){
+ sdlManager.fileManagerConfig = fileManagerConfig;
+ return this;
+ }
+
+ /**
* Sets the LockScreenConfig for the session. <br>
* <strong>Note: If not set, the default configuration will be used.</strong>
* @param lockScreenConfig - configuration options
@@ -1181,6 +1209,11 @@ public class SdlManager extends BaseSdlManager{
sdlManager.lockScreenConfig = new LockScreenConfig();
}
+ if(sdlManager.fileManagerConfig == null){
+ //if FileManagerConfig is not set use default
+ sdlManager.fileManagerConfig = new FileManagerConfig();
+ }
+
if (sdlManager.hmiLanguage == null){
sdlManager.hmiLanguage = Language.EN_US;
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
index a07653414..3e1702346 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/FileManager.java
@@ -65,6 +65,7 @@ public class FileManager extends BaseFileManager {
private final WeakReference<Context> context;
+ @Deprecated
public FileManager(ISdl internalInterface, Context context) {
// setup
@@ -73,6 +74,18 @@ public class FileManager extends BaseFileManager {
}
/**
+ * Constructor for FileManager
+ * @param internalInterface an instance of the ISdl interface that can be used for common SDL operations (sendRpc, addRpcListener, etc)
+ * @param context an instances of Context interface to global information for application
+ * @param fileManagerConfig an instance of the FileManagerConfig gives access to artworkRetryCount and fileRetryCount to let us if those file types can be re-upload if they fail
+ */
+ public FileManager(ISdl internalInterface, Context context, FileManagerConfig fileManagerConfig) {
+ // setup
+ super(internalInterface, fileManagerConfig);
+ this.context = new WeakReference<>(context);
+ }
+
+ /**
* Creates and returns a PutFile request that would upload a given SdlFile
* @param file SdlFile with fileName and one of A) fileData, B) Uri, or C) resourceID set
* @return a valid PutFile request if SdlFile contained a fileName and sufficient data
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
index e7db70ee6..5f14cb2ed 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlArtwork.java
@@ -51,38 +51,38 @@ public class SdlArtwork extends SdlFile implements Cloneable{
/**
* Creates a new instance of SdlArtwork
*/
- public SdlArtwork(){}
+ public SdlArtwork() {}
/**
* Creates a new instance of SdlArtwork
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
* @param fileType a FileType enum value representing the type of the file
* @param id an int value representing the android resource id of the file
* @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
*/
- public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, int id, boolean persistentFile) {
+ public SdlArtwork(String fileName, @NonNull FileType fileType, int id, boolean persistentFile) {
super(fileName, fileType, id, persistentFile);
}
/**
* Creates a new instance of SdlArtwork
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
* @param fileType a FileType enum value representing the type of the file
* @param uri a URI value representing a file's location. Currently, it only supports local files
* @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
*/
- public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile) {
+ public SdlArtwork(String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile) {
super(fileName, fileType, uri, persistentFile);
}
/**
* Creates a new instance of SdlArtwork
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
* @param fileType a FileType enum value representing the type of the file
* @param data a byte array representing the data of the file
* @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
*/
- public SdlArtwork(@NonNull String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile) {
+ public SdlArtwork(String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile) {
super(fileName, fileType, data, persistentFile);
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
index 3635c9551..5d7e73f5c 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/file/filetypes/SdlFile.java
@@ -38,63 +38,69 @@ import android.support.annotation.NonNull;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.StaticIconName;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
/**
* A class representing data to be uploaded to core
*/
public class SdlFile{
- private String fileName;
- private int id = -1;
- private Uri uri;
- private byte[] fileData;
- private FileType fileType;
- private boolean persistentFile;
- private boolean isStaticIcon;
+ private String fileName;
+ private int id = -1;
+ private Uri uri;
+ private byte[] fileData;
+ private FileType fileType;
+ private boolean persistentFile;
+ private boolean isStaticIcon;
+ private boolean shouldAutoGenerateName;
+ // Overwrite property by default is set to true in SdlFile constructors indicating that a file can be overwritten
+ private boolean overwrite = true;
/**
* Creates a new instance of SdlFile
*/
- public SdlFile(){}
+ public SdlFile() { }
/**
* Creates a new instance of SdlFile
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
* @param fileType a FileType enum value representing the type of the file
* @param id an int value representing the android resource id of the file
* @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
*/
- public SdlFile(@NonNull String fileName, @NonNull FileType fileType, int id, boolean persistentFile){
- this.fileName = fileName;
- this.fileType = fileType;
- this.id = id;
- this.persistentFile = persistentFile;
+ public SdlFile(String fileName, @NonNull FileType fileType, int id, boolean persistentFile){
+ setName(fileName);
+ setType(fileType);
+ setResourceId(id);
+ setPersistent(persistentFile);
}
/**
* Creates a new instance of SdlFile
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
* @param fileType a FileType enum value representing the type of the file
* @param uri a URI value representing a file's location. Currently, it only supports local files
* @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
*/
- public SdlFile(@NonNull String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile){
- this.fileName = fileName;
- this.fileType = fileType;
- this.uri = uri;
- this.persistentFile = persistentFile;
+ public SdlFile(String fileName, @NonNull FileType fileType, Uri uri, boolean persistentFile){
+ setName(fileName);
+ setType(fileType);
+ setUri(uri);
+ setPersistent(persistentFile);
}
/**
* Creates a new instance of SdlFile
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
* @param fileType a FileType enum value representing the type of the file
* @param data a byte array representing the data of the file
* @param persistentFile a boolean value that indicates if the file is meant to persist between sessions / ignition cycles
*/
- public SdlFile(@NonNull String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile){
- this.fileName = fileName;
- this.fileType = fileType;
- this.fileData = data;
- this.persistentFile = persistentFile;
+ public SdlFile(String fileName, @NonNull FileType fileType, byte[] data, boolean persistentFile){
+ setName(fileName);
+ setType(fileType);
+ setFileData(data);
+ setPersistent(persistentFile);
}
/**
@@ -102,18 +108,30 @@ public class SdlFile{
* @param staticIconName a StaticIconName enum value representing the name of a static file that comes pre-shipped with the head unit
*/
public SdlFile(@NonNull StaticIconName staticIconName){
- this.fileName = staticIconName.toString();
- this.fileData = staticIconName.toString().getBytes();
- this.persistentFile = false;
- this.isStaticIcon = true;
+ setName(staticIconName.toString());
+ setFileData(staticIconName.toString().getBytes());
+ setPersistent(false);
+ setStaticIcon(true);
}
/**
* Sets the name of the file
- * @param fileName a String value representing the name that will be used to store the file in the head unit
+ * @param fileName a String value representing the name that will be used to store the file in the head unit. You can pass null if you want the library to auto generate the name
*/
- public void setName(@NonNull String fileName){
- this.fileName = fileName;
+ public void setName(String fileName) {
+ if (fileName != null) {
+ this.shouldAutoGenerateName = false;
+ this.fileName = fileName;
+ } else {
+ this.shouldAutoGenerateName = true;
+ if (this.getFileData() != null) {
+ this.fileName = generateFileNameFromData(this.getFileData());
+ } else if (this.getUri() != null) {
+ this.fileName = generateFileNameFromUri(this.getUri());
+ } else if (this.getResourceId() != 0) {
+ this.fileName = generateFileNameFromResourceId(this.getResourceId());
+ }
+ }
}
/**
@@ -130,6 +148,9 @@ public class SdlFile{
*/
public void setResourceId(int id){
this.id = id;
+ if (shouldAutoGenerateName) {
+ this.fileName = generateFileNameFromResourceId(id);
+ }
}
/**
@@ -146,6 +167,9 @@ public class SdlFile{
*/
public void setUri(Uri uri){
this.uri = uri;
+ if (shouldAutoGenerateName && uri != null) {
+ this.fileName = generateFileNameFromUri(uri);
+ }
}
/**
@@ -162,6 +186,9 @@ public class SdlFile{
*/
public void setFileData(byte[] data){
this.fileData = data;
+ if (shouldAutoGenerateName && data != null) {
+ this.fileName = generateFileNameFromData(data);
+ }
}
/**
@@ -219,4 +246,98 @@ public class SdlFile{
public boolean isStaticIcon() {
return isStaticIcon;
}
-} \ No newline at end of file
+
+ /**
+ * Gets the overwrite property for an SdlFile by default its set to true
+ * @return a boolean value that indicates if a file can be overwritten.
+ */
+ public boolean getOverwrite() {
+ return overwrite;
+ }
+
+ /**
+ * Sets the overwrite property for an SdlFile by default its set to true
+ * @param overwrite a boolean value that indicates if a file can be overwritten
+ */
+ public void setOverwrite(boolean overwrite) {
+ this.overwrite = overwrite;
+ }
+
+ /**
+ * Generates a file name from data by hashing the data and returning the last 16 chars
+ * @param data a byte array representing the data of the file
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ private String generateFileNameFromData(@NonNull byte[] data) {
+ String result;
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("md5");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return null;
+ }
+ byte[] hash = new byte[0];
+ if (messageDigest != null) {
+ hash = messageDigest.digest(data);
+ }
+ StringBuilder stringBuilder = new StringBuilder(2 * hash.length);
+ for (byte b : hash) {
+ stringBuilder.append(String.format("%02x", b & 0xff));
+ }
+ String hashString = stringBuilder.toString();
+ result = hashString.substring(hashString.length() - 16);
+ return result;
+ }
+
+ /**
+ * Generates a file name from uri by hashing the uri string and returning the last 16 chars
+ * @param uri a URI value representing a file's location
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ private String generateFileNameFromUri(@NonNull Uri uri) {
+ return generateFileNameFromData(uri.toString().getBytes());
+ }
+
+ /**
+ * Generates a file name from resourceId by hashing the id and returning the last 16 chars
+ * @param id an int value representing the android resource id of the file
+ * @return a String value representing the name that will be used to store the file in the head unit
+ */
+ private String generateFileNameFromResourceId(int id) {
+ return generateFileNameFromData("ResourceId".concat(String.valueOf(id)).getBytes());
+ }
+
+ /**
+ * Used to compile hashcode for SdlFile for use to compare in overridden equals method
+ * @return Custom hashcode of SdlFile variables
+ */
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result += ((getName() == null) ? 0 : Integer.rotateLeft(getName().hashCode(), 1));
+ result += ((getUri() == null) ? 0 : Integer.rotateLeft(getUri().hashCode(), 2));
+ result += ((getFileData() == null) ? 0 : Integer.rotateLeft(getFileData().hashCode(), 3));
+ result += ((getType() == null) ? 0 : Integer.rotateLeft(getType().hashCode(), 4));
+ result += Integer.rotateLeft(Boolean.valueOf(isStaticIcon()).hashCode(), 5);
+ result += Integer.rotateLeft(Boolean.valueOf(isPersistent()).hashCode(), 6);
+ result += Integer.rotateLeft(Integer.valueOf(getResourceId()).hashCode(), 7);
+ return result;
+ }
+
+ /**
+ * Uses our custom hashCode for SdlFile objects
+ * @param o - The object to compare
+ * @return boolean of whether the objects are the same or not
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ // if this is the same memory address, it's the same
+ if (this == o) return true;
+ // if this is not an instance of SdlFile, not the same
+ if (!(o instanceof SdlFile)) return false;
+ // return comparison
+ return hashCode() == o.hashCode();
+ }
+}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenDeviceIconManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenDeviceIconManager.java
new file mode 100644
index 000000000..b2b8e6b14
--- /dev/null
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenDeviceIconManager.java
@@ -0,0 +1,214 @@
+package com.smartdevicelink.managers.lockscreen;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.smartdevicelink.util.AndroidTools;
+import com.smartdevicelink.util.DebugTool;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * <strong>LockScreenDeviceIconManager</strong> <br>
+ *
+ * The LockScreenDeviceIconManager handles the logic of caching and retrieving cached lock screen icons <br>
+ *
+ */
+class LockScreenDeviceIconManager {
+
+ private Context context;
+ private static final String SDL_DEVICE_STATUS_SHARED_PREFS = "sdl.lockScreenIcon";
+ private static final String STORED_ICON_DIRECTORY_PATH = "sdl/lock_screen_icon/";
+
+ interface OnIconRetrievedListener {
+ void onImageRetrieved(Bitmap icon);
+ void onError(String info);
+ }
+
+ LockScreenDeviceIconManager(Context context) {
+ this.context = context;
+ File lockScreenDirectory = new File(context.getCacheDir(), STORED_ICON_DIRECTORY_PATH);
+ lockScreenDirectory.mkdirs();
+ }
+
+ /**
+ * Will try to return a lock screen icon either from cache or downloaded
+ * if it fails iconRetrievedListener.OnError will be called with corresponding error message
+ * @param iconURL url that the lock screen icon is downloaded from
+ * @param iconRetrievedListener an interface that will implement onIconReceived and OnError methods
+ */
+ void retrieveIcon(String iconURL, OnIconRetrievedListener iconRetrievedListener) {
+ Bitmap icon = null;
+ try {
+ if (isIconCachedAndValid(iconURL)) {
+ DebugTool.logInfo("Icon Is Up To Date");
+ icon = getFileFromCache(iconURL);
+ if (icon == null) {
+ DebugTool.logInfo("Icon from cache was null, attempting to re-download");
+ icon = AndroidTools.downloadImage(iconURL);
+ if (icon != null) {
+ saveFileToCache(icon, iconURL);
+ } else {
+ iconRetrievedListener.onError("Icon downloaded was null");
+ return;
+ }
+ }
+ iconRetrievedListener.onImageRetrieved(icon);
+ } else {
+ // The icon is unknown or expired. Download the image, save it to the cache, and update the archive file
+ DebugTool.logInfo("Lock Screen Icon Update Needed");
+ icon = AndroidTools.downloadImage(iconURL);
+ if (icon != null) {
+ saveFileToCache(icon, iconURL);
+ iconRetrievedListener.onImageRetrieved(icon);
+ } else {
+ iconRetrievedListener.onError("Icon downloaded was null");
+ }
+ }
+ } catch (IOException e) {
+ iconRetrievedListener.onError("device Icon Error Downloading, Will attempt to grab cached Icon even if expired: \n" + e.toString());
+ icon = getFileFromCache(iconURL);
+ if (icon != null) {
+ iconRetrievedListener.onImageRetrieved(icon);
+ } else {
+ iconRetrievedListener.onError("Unable to retrieve icon from cache");
+ }
+ }
+ }
+
+ /**
+ * Will decide if a cached icon is available and up to date
+ * @param iconUrl url will be hashed and used to look up last updated timestamp in shared preferences
+ * @return True when icon details are in shared preferences and less than 30 days old, False if icon details are too old or not found
+ */
+ private boolean isIconCachedAndValid(String iconUrl) {
+ String iconHash = getMD5HashFromIconUrl(iconUrl);
+ SharedPreferences sharedPref = this.context.getSharedPreferences(SDL_DEVICE_STATUS_SHARED_PREFS, Context.MODE_PRIVATE);
+ String iconLastUpdatedTime = sharedPref.getString(iconHash, null);
+ if(iconLastUpdatedTime == null) {
+ DebugTool.logInfo("No Icon Details Found In Shared Preferences");
+ return false;
+ } else {
+ DebugTool.logInfo("Icon Details Found");
+ long lastUpdatedTime = 0;
+ try {
+ lastUpdatedTime = Long.parseLong(iconLastUpdatedTime);
+ } catch (NumberFormatException e) {
+ DebugTool.logInfo("Invalid time stamp stored to shared preferences, clearing cache and share preferences");
+ clearIconDirectory();
+ sharedPref.edit().clear().commit();
+ }
+ long currentTime = System.currentTimeMillis();
+
+ long timeDifference = currentTime - lastUpdatedTime;
+ long daysBetweenLastUpdate = timeDifference / (1000 * 60 * 60 * 24);
+ return daysBetweenLastUpdate < 30;
+ }
+ }
+
+ /**
+ * Will try to save icon to cache
+ * @param icon the icon bitmap that should be saved to cache
+ * @param iconUrl the url where the icon was retrieved will be hashed and used for file and file details lookup
+ */
+ private void saveFileToCache(Bitmap icon, String iconUrl) {
+ String iconHash = getMD5HashFromIconUrl(iconUrl);
+ File f = new File(this.context.getCacheDir() + "/" + STORED_ICON_DIRECTORY_PATH, iconHash);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ icon.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
+ byte[] bitmapData = bos.toByteArray();
+
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(f);
+ fos.write(bitmapData);
+ fos.flush();
+ fos.close();
+ writeDeviceIconParametersToSharedPreferences(iconHash);
+ } catch (Exception e) {
+ DebugTool.logError("Failed to save icon to cache");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Will try to retrieve icon bitmap from cached directory
+ * @param iconUrl the url where the icon was retrieved will be hashed and used to look up file location
+ * @return bitmap of device icon or null if it fails to find the icon or read from shared preferences
+ */
+ private Bitmap getFileFromCache(String iconUrl) {
+ String iconHash = getMD5HashFromIconUrl(iconUrl);
+ SharedPreferences sharedPref = this.context.getSharedPreferences(SDL_DEVICE_STATUS_SHARED_PREFS, Context.MODE_PRIVATE);
+ String iconLastUpdatedTime = sharedPref.getString(iconHash, null);
+
+ if (iconLastUpdatedTime != null) {
+ Bitmap cachedIcon = BitmapFactory.decodeFile(this.context.getCacheDir() + "/" + STORED_ICON_DIRECTORY_PATH + "/" + iconHash);
+ if(cachedIcon == null) {
+ DebugTool.logError("Failed to get Bitmap from decoding file cache");
+ clearIconDirectory();
+ sharedPref.edit().clear().commit();
+ return null;
+ } else {
+ return cachedIcon;
+ }
+ } else {
+ DebugTool.logError("Failed to get shared preferences");
+ return null;
+ }
+ }
+
+ /**
+ * Will write information about the icon to shared preferences
+ * icon information will have a look up key of the hashed icon url and the current timestamp to indicated when the icon was last updated.
+ * @param iconHash the url where the icon was retrieved will be hashed and used lookup key
+ */
+ private void writeDeviceIconParametersToSharedPreferences(String iconHash) {
+ SharedPreferences sharedPref = this.context.getSharedPreferences(SDL_DEVICE_STATUS_SHARED_PREFS, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString(iconHash, String.valueOf(System.currentTimeMillis()));
+ editor.commit();
+ }
+
+ /**
+ * Create an MD5 hash of the icon url for file storage and lookup/shared preferences look up
+ * @param iconUrl the url where the icon was retrieved
+ * @return MD5 hash of the icon URL
+ */
+ private String getMD5HashFromIconUrl(String iconUrl) {
+ String iconHash = null;
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] messageDigest = md.digest(iconUrl.getBytes());
+ BigInteger no = new BigInteger(1, messageDigest);
+ String hashtext = no.toString(16);
+ while (hashtext.length() < 32) {
+ hashtext = "0" + hashtext;
+ }
+ iconHash = hashtext;
+ } catch (NoSuchAlgorithmException e) {
+ DebugTool.logError("Unable to hash icon url");
+ e.printStackTrace();
+ }
+ return iconHash;
+ }
+
+ /**
+ * Clears all files in the directory where lock screen icons are cached
+ */
+ private void clearIconDirectory() {
+ File iconDir = new File(context.getCacheDir() + "/" + STORED_ICON_DIRECTORY_PATH);
+ if (iconDir.listFiles() != null) {
+ for (File child : iconDir.listFiles()) {
+ child.delete();
+ }
+ }
+ }
+}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
index 30ed1b575..2e81894ed 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java
@@ -54,9 +54,8 @@ import com.smartdevicelink.proxy.rpc.enums.LockScreenStatus;
import com.smartdevicelink.proxy.rpc.enums.PredefinedWindows;
import com.smartdevicelink.proxy.rpc.enums.RequestType;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
-import com.smartdevicelink.util.AndroidTools;
+import com.smartdevicelink.util.DebugTool;
-import java.io.IOException;
import java.lang.ref.WeakReference;
/**
@@ -82,11 +81,14 @@ public class LockScreenManager extends BaseSubManager {
private boolean mLockScreenHasBeenDismissed, lockscreenDismissReceiverRegistered, receivedFirstDDNotification;
private String mLockscreenWarningMsg;
private BroadcastReceiver mLockscreenDismissedReceiver;
+ private LockScreenDeviceIconManager mLockScreenDeviceIconManager;
public LockScreenManager(LockScreenConfig lockScreenConfig, Context context, ISdl internalInterface){
super(internalInterface);
this.context = new WeakReference<>(context);
+ this.mLockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
+
// set initial class variables
hmiLevel = HMILevel.HMI_NONE;
@@ -231,7 +233,7 @@ public class LockScreenManager extends BaseSubManager {
if (msg.getRequestType() == RequestType.LOCK_SCREEN_ICON_URL &&
msg.getUrl() != null) {
// send intent to activity to download icon from core
- deviceIconUrl = msg.getUrl();
+ deviceIconUrl = msg.getUrl().replace("http://", "https://");
downloadDeviceIcon(deviceIconUrl);
}
}
@@ -375,17 +377,25 @@ public class LockScreenManager extends BaseSubManager {
new Thread(new Runnable(){
@Override
public void run(){
- try{
- deviceLogo = AndroidTools.downloadImage(url);
- Intent intent = new Intent(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_DOWNLOADED);
- intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_EXTRA, deviceLogoEnabled);
- intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_BITMAP, deviceLogo);
- if (context.get() != null) {
- context.get().sendBroadcast(intent);
+ mLockScreenDeviceIconManager.retrieveIcon(url, new LockScreenDeviceIconManager.OnIconRetrievedListener() {
+ @Override
+ public void onImageRetrieved(Bitmap icon) {
+ deviceLogo = icon;
+ if(deviceLogo != null) {
+ Intent intent = new Intent(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_DOWNLOADED);
+ intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_EXTRA, deviceLogoEnabled);
+ intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_BITMAP, deviceLogo);
+ if (context.get() != null) {
+ context.get().sendBroadcast(intent);
+ }
+ }
}
- }catch(IOException e){
- Log.e(TAG, "device Icon Error Downloading");
- }
+
+ @Override
+ public void onError(String info) {
+ DebugTool.logError(info);
+ }
+ });
}
}).start();
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java
index bb257b915..b6f49a9a4 100644
--- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java
+++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/video/VideoStreamManager.java
@@ -65,6 +65,7 @@ import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.PredefinedWindows;
import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
import com.smartdevicelink.proxy.rpc.enums.TouchType;
+import com.smartdevicelink.proxy.rpc.enums.VideoStreamingState;
import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener;
import com.smartdevicelink.streaming.video.SdlRemoteDisplay;
import com.smartdevicelink.streaming.video.VideoStreamingParameters;
@@ -89,12 +90,13 @@ public class VideoStreamManager extends BaseVideoStreamManager {
private float[] touchScalar = {1.0f,1.0f}; //x, y
private HapticInterfaceManager hapticManager;
private SdlMotionEvent sdlMotionEvent = null;
- private HMILevel hmiLevel;
+ private OnHMIStatus currentOnHMIStatus;
private StreamingStateMachine stateMachine;
private VideoStreamingParameters parameters;
private IVideoStreamListener streamListener;
private boolean isTransportAvailable = false;
private boolean hasStarted;
+ private String vehicleMake = null;
// INTERNAL INTERFACES
@@ -113,7 +115,7 @@ public class VideoStreamManager extends BaseVideoStreamManager {
return;
}
VideoStreamingCapability capability = (VideoStreamingCapability) internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING);
- if(capability != null && capability.getIsHapticSpatialDataSupported()){
+ if(capability != null && Boolean.TRUE.equals(capability.getIsHapticSpatialDataSupported())){
hapticManager = new HapticInterfaceManager(internalInterface);
}
startEncoder();
@@ -125,10 +127,11 @@ public class VideoStreamManager extends BaseVideoStreamManager {
@Override
public void onServiceEnded(SdlSession session, SessionType type) {
if(SessionType.NAV.equals(type)){
- stateMachine.transitionToState(StreamingStateMachine.NONE);
if(remoteDisplay!=null){
stopStreaming();
}
+ stateMachine.transitionToState(StreamingStateMachine.NONE);
+ transitionToState(SETTING_UP);
}
}
@@ -144,13 +147,18 @@ public class VideoStreamManager extends BaseVideoStreamManager {
@Override
public void onNotified(RPCNotification notification) {
if(notification != null){
- OnHMIStatus onHMIStatus = (OnHMIStatus)notification;
+ OnHMIStatus onHMIStatus = (OnHMIStatus) notification;
if (onHMIStatus.getWindowID() != null && onHMIStatus.getWindowID() != PredefinedWindows.DEFAULT_WINDOW.getValue()) {
return;
}
- hmiLevel = onHMIStatus.getHmiLevel();
- if(hmiLevel.equals(HMILevel.HMI_FULL)){
- checkState();
+ OnHMIStatus prevOnHMIStatus = currentOnHMIStatus;
+ currentOnHMIStatus = onHMIStatus;
+ if (!HMILevel.HMI_NONE.equals(currentOnHMIStatus.getHmiLevel()) && VideoStreamManager.this.parameters == null) {
+ getVideoStreamingParams();
+ }
+ checkState();
+ if (hasStarted && (isHMIStateVideoStreamCapable(prevOnHMIStatus)) && (!isHMIStateVideoStreamCapable(currentOnHMIStatus))) {
+ internalInterface.stopVideoService();
}
}
}
@@ -171,12 +179,14 @@ public class VideoStreamManager extends BaseVideoStreamManager {
};
// MANAGER APIs
-
public VideoStreamManager(ISdl internalInterface){
super(internalInterface);
+ if(internalInterface != null && internalInterface.getRegisterAppInterfaceResponse() != null &&
+ internalInterface.getRegisterAppInterfaceResponse().getVehicleType() != null) {
+ vehicleMake = internalInterface.getRegisterAppInterfaceResponse().getVehicleType().getMake();
+ }
virtualDisplayEncoder = new VirtualDisplayEncoder();
- hmiLevel = HMILevel.HMI_NONE;
// Listen for video service events
internalInterface.addServiceListener(SessionType.NAV, serviceListener);
@@ -191,7 +201,6 @@ public class VideoStreamManager extends BaseVideoStreamManager {
@Override
public void start(CompletionListener listener) {
isTransportAvailable = internalInterface.isTransportForServiceAvailable(SessionType.NAV);
- getVideoStreamingParams();
checkState();
super.start(listener);
}
@@ -199,21 +208,26 @@ public class VideoStreamManager extends BaseVideoStreamManager {
private synchronized void checkState(){
if(this.getState() == SETTING_UP
&& isTransportAvailable
- && hmiLevel != null
- && hmiLevel.equals(HMILevel.HMI_FULL)
+ && isHMIStateVideoStreamCapable(currentOnHMIStatus)
&& parameters != null){
stateMachine.transitionToState(StreamingStateMachine.READY);
transitionToState(READY);
}
}
+ boolean isHMIStateVideoStreamCapable(OnHMIStatus onHMIStatus) {
+ HMILevel hmiLevel = (onHMIStatus != null && onHMIStatus.getHmiLevel() != null) ? onHMIStatus.getHmiLevel() : HMILevel.HMI_NONE;
+ VideoStreamingState videoStreamingState = (onHMIStatus != null && onHMIStatus.getVideoStreamingState() != null) ? onHMIStatus.getVideoStreamingState() : VideoStreamingState.STREAMABLE;
+ return (hmiLevel.equals(HMILevel.HMI_FULL) || hmiLevel.equals(HMILevel.HMI_LIMITED)) && videoStreamingState.equals(VideoStreamingState.STREAMABLE);
+ }
+
private void getVideoStreamingParams(){
if(internalInterface.getProtocolVersion().getMajor() >= 5) {
internalInterface.getCapability(SystemCapabilityType.VIDEO_STREAMING, new OnSystemCapabilityListener() {
@Override
public void onCapabilityRetrieved(Object capability) {
VideoStreamingParameters params = new VideoStreamingParameters();
- params.update((VideoStreamingCapability)capability); //Streaming parameters are ready time to stream
+ params.update((VideoStreamingCapability)capability, vehicleMake); //Streaming parameters are ready time to stream
VideoStreamManager.this.parameters = params;
checkState();
@@ -265,7 +279,7 @@ public class VideoStreamManager extends BaseVideoStreamManager {
@Override
public void onCapabilityRetrieved(Object capability) {
VideoStreamingParameters params = new VideoStreamingParameters();
- params.update((VideoStreamingCapability)capability); //Streaming parameters are ready time to stream
+ params.update((VideoStreamingCapability)capability, vehicleMake); //Streaming parameters are ready time to stream
startStreaming(params, encrypted);
}
@@ -298,13 +312,12 @@ public class VideoStreamManager extends BaseVideoStreamManager {
*/
protected void startStreaming(VideoStreamingParameters parameters, boolean encrypted){
this.parameters = parameters;
- if(hmiLevel != HMILevel.HMI_FULL){
- Log.e(TAG, "Cannot start video service if HMILevel is not FULL.");
+ if (!isHMIStateVideoStreamCapable(currentOnHMIStatus)) {
+ Log.e(TAG, "Cannot start video service in the current HMI status");
return;
}
//Start the video service
this.internalInterface.startVideoService(parameters, encrypted);
-
}
/**
@@ -394,7 +407,7 @@ public class VideoStreamManager extends BaseVideoStreamManager {
* @return boolean (true = yes, false = no)
*/
public boolean isStreaming(){
- return (stateMachine.getState() == StreamingStateMachine.STARTED) && (hmiLevel == HMILevel.HMI_FULL);
+ return (stateMachine.getState() == StreamingStateMachine.STARTED) && (isHMIStateVideoStreamCapable(currentOnHMIStatus));
}
/**
@@ -402,7 +415,7 @@ public class VideoStreamManager extends BaseVideoStreamManager {
* @return boolean (true = not paused, false = paused)
*/
public boolean isPaused(){
- return (hasStarted && stateMachine.getState() == StreamingStateMachine.STOPPED) || (hmiLevel != HMILevel.HMI_FULL);
+ return (hasStarted && stateMachine.getState() == StreamingStateMachine.STOPPED) || (!isHMIStateVideoStreamCapable(currentOnHMIStatus));
}
/**