diff options
Diffstat (limited to 'android/sdl_android/src/main/java/com')
22 files changed, 906 insertions, 196 deletions
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java b/android/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java index 457bd9a46..cbd45c49a 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/SdlConnection/SdlSession2.java @@ -45,6 +45,7 @@ import com.smartdevicelink.protocol.heartbeat.IHeartbeatMonitor; import com.smartdevicelink.proxy.interfaces.ISdlServiceListener; import com.smartdevicelink.transport.BaseTransportConfig; import com.smartdevicelink.transport.MultiplexTransportConfig; +import com.smartdevicelink.transport.TCPTransportConfig; import com.smartdevicelink.transport.enums.TransportType; import com.smartdevicelink.util.MediaStreamingStatus; import com.smartdevicelink.util.Version; @@ -82,8 +83,14 @@ public class SdlSession2 extends SdlSession implements ISdlProtocol{ } + public SdlSession2(ISdlConnectionListener listener, TCPTransportConfig config){ //TODO is it better to have two constructors or make it take BaseTransportConfig? + this.transportConfig = config; + this.sessionListener = listener; + this.sdlProtocol = new SdlProtocol(this,config); + } + boolean isAudioRequirementMet(){ - if(mediaStreamingStatus == null){ + if(mediaStreamingStatus == null && contextWeakReference!= null && contextWeakReference.get() != null){ mediaStreamingStatus = new MediaStreamingStatus(contextWeakReference.get(), new MediaStreamingStatus.Callback() { @Override public void onAudioNoLongerAvailable() { @@ -304,7 +311,15 @@ public class SdlSession2 extends SdlSession implements ISdlProtocol{ }else if(SessionType.PCM.equals(serviceType)){ stopAudioStream(); } - + // Notify any listeners of the service being ended + if(serviceListeners != null && serviceListeners.containsKey(serviceType)){ + CopyOnWriteArrayList<ISdlServiceListener> listeners = serviceListeners.get(serviceType); + if (listeners != null && listeners.size() > 0) { + for (ISdlServiceListener listener : listeners) { + listener.onServiceEnded(this, serviceType); + } + } + } } @Override diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/haptic/HapticInterfaceManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/haptic/HapticInterfaceManager.java index 9a6e44897..716fc16fc 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/haptic/HapticInterfaceManager.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/haptic/HapticInterfaceManager.java @@ -28,6 +28,8 @@ import com.smartdevicelink.proxy.interfaces.ISdl; import com.smartdevicelink.proxy.rpc.HapticRect; import com.smartdevicelink.proxy.rpc.Rectangle; import com.smartdevicelink.proxy.rpc.SendHapticData; +import com.smartdevicelink.proxy.rpc.VideoStreamingCapability; +import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -59,8 +61,8 @@ public class HapticInterfaceManager { */ public void setHapticData(List<HapticRect> hapticData) { userHapticData = hapticData; - ISdl proxy = proxyHolder.get(); - if (proxy != null) { + if(proxyHolder.get() != null) { + ISdl proxy = proxyHolder.get(); SendHapticData msg = new SendHapticData(); msg.setHapticRectData(userHapticData); proxy.sendRPCRequest(msg); @@ -75,15 +77,17 @@ public class HapticInterfaceManager { * the root or parent View */ public void refreshHapticData(View root) { - ISdl proxy = proxyHolder.get(); - if ((userHapticData == null) && (proxy != null)) { - List<HapticRect> hapticRects = new ArrayList<>(); - findHapticRects(root, hapticRects); + if(proxyHolder.get() != null) { + ISdl proxy = proxyHolder.get(); + if (userHapticData == null) { + List<HapticRect> hapticRects = new ArrayList<>(); + findHapticRects(root, hapticRects); - SendHapticData msg = new SendHapticData(); - msg.setHapticRectData(hapticRects); + SendHapticData msg = new SendHapticData(); + msg.setHapticRectData(hapticRects); - proxy.sendRPCRequest(msg); + proxy.sendRPC(msg); + } } } @@ -91,6 +95,17 @@ public class HapticInterfaceManager { List<View> focusables = new ArrayList<>(); getFocusableViews(root, focusables); + double scale = 1.0; + + if (proxyHolder.get() != null) { + ISdl proxy = proxyHolder.get(); + VideoStreamingCapability videoStreamingCapability = (VideoStreamingCapability) + proxy.getCapability(SystemCapabilityType.VIDEO_STREAMING); + if (videoStreamingCapability != null && videoStreamingCapability.getScale() != null) { + scale = videoStreamingCapability.getScale(); + } + } + int [] loc = new int[2]; int id = 0; for (View view : focusables) { @@ -99,10 +114,10 @@ public class HapticInterfaceManager { view.getLocationOnScreen(loc); Rectangle rect = new Rectangle(); - rect.setWidth((float) w); - rect.setHeight((float) h); - rect.setX((float) loc[0]); - rect.setY((float) loc[1]); + rect.setWidth((float) (w * scale)); + rect.setHeight((float) (h * scale)); + rect.setX((float) (loc[0] * scale)); + rect.setY((float) (loc[1] * scale)); HapticRect hapticRect = new HapticRect(); hapticRect.setId(id++); diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java index fc204df49..23c37bea5 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/ProxyBridge.java @@ -44,13 +44,16 @@ import com.smartdevicelink.proxy.rpc.AddSubMenuResponse; import com.smartdevicelink.proxy.rpc.AlertManeuverResponse; import com.smartdevicelink.proxy.rpc.AlertResponse; import com.smartdevicelink.proxy.rpc.ButtonPressResponse; +import com.smartdevicelink.proxy.rpc.CancelInteractionResponse; import com.smartdevicelink.proxy.rpc.ChangeRegistrationResponse; import com.smartdevicelink.proxy.rpc.CloseApplicationResponse; import com.smartdevicelink.proxy.rpc.CreateInteractionChoiceSetResponse; +import com.smartdevicelink.proxy.rpc.CreateWindowResponse; import com.smartdevicelink.proxy.rpc.DeleteCommandResponse; import com.smartdevicelink.proxy.rpc.DeleteFileResponse; import com.smartdevicelink.proxy.rpc.DeleteInteractionChoiceSetResponse; import com.smartdevicelink.proxy.rpc.DeleteSubMenuResponse; +import com.smartdevicelink.proxy.rpc.DeleteWindowResponse; import com.smartdevicelink.proxy.rpc.DiagnosticMessageResponse; import com.smartdevicelink.proxy.rpc.DialNumberResponse; import com.smartdevicelink.proxy.rpc.EndAudioPassThruResponse; @@ -59,6 +62,7 @@ import com.smartdevicelink.proxy.rpc.GetAppServiceDataResponse; import com.smartdevicelink.proxy.rpc.GetCloudAppPropertiesResponse; import com.smartdevicelink.proxy.rpc.GetDTCsResponse; import com.smartdevicelink.proxy.rpc.GetFileResponse; +import com.smartdevicelink.proxy.rpc.GetInteriorVehicleDataConsentResponse; import com.smartdevicelink.proxy.rpc.GetInteriorVehicleDataResponse; import com.smartdevicelink.proxy.rpc.GetSystemCapabilityResponse; import com.smartdevicelink.proxy.rpc.GetVehicleDataResponse; @@ -93,6 +97,7 @@ import com.smartdevicelink.proxy.rpc.PublishAppServiceResponse; import com.smartdevicelink.proxy.rpc.PutFileResponse; import com.smartdevicelink.proxy.rpc.ReadDIDResponse; import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse; +import com.smartdevicelink.proxy.rpc.ReleaseInteriorVehicleDataModuleResponse; import com.smartdevicelink.proxy.rpc.ResetGlobalPropertiesResponse; import com.smartdevicelink.proxy.rpc.ScrollableMessageResponse; import com.smartdevicelink.proxy.rpc.SendHapticDataResponse; @@ -103,6 +108,7 @@ import com.smartdevicelink.proxy.rpc.SetDisplayLayoutResponse; import com.smartdevicelink.proxy.rpc.SetGlobalPropertiesResponse; import com.smartdevicelink.proxy.rpc.SetInteriorVehicleDataResponse; import com.smartdevicelink.proxy.rpc.SetMediaClockTimerResponse; +import com.smartdevicelink.proxy.rpc.ShowAppMenuResponse; import com.smartdevicelink.proxy.rpc.ShowConstantTbtResponse; import com.smartdevicelink.proxy.rpc.ShowResponse; import com.smartdevicelink.proxy.rpc.SliderResponse; @@ -574,6 +580,16 @@ public class ProxyBridge implements IProxyListener{ } @Override + public void onCreateWindowResponse(CreateWindowResponse response) { + onRPCReceived(response); + } + + @Override + public void onDeleteWindowResponse(DeleteWindowResponse response) { + onRPCReceived(response); + } + + @Override public void onButtonPressResponse(ButtonPressResponse response) { onRPCReceived(response); @@ -609,7 +625,8 @@ public class ProxyBridge implements IProxyListener{ public void onGetCloudAppProperties(GetCloudAppPropertiesResponse response) { onRPCReceived(response); } -@Override + + @Override public void onPublishAppServiceResponse(PublishAppServiceResponse response){ onRPCReceived(response); } @@ -635,6 +652,16 @@ public class ProxyBridge implements IProxyListener{ } @Override + public void onGetInteriorVehicleDataConsentResponse(GetInteriorVehicleDataConsentResponse response) { + onRPCReceived(response); + } + + @Override + public void onReleaseInteriorVehicleDataModuleResponse(ReleaseInteriorVehicleDataModuleResponse response) { + onRPCReceived(response); + } + + @Override public void onOnSystemCapabilityUpdated(OnSystemCapabilityUpdated notification){ onRPCReceived(notification); } @@ -645,6 +672,16 @@ public class ProxyBridge implements IProxyListener{ } @Override + public void onCancelInteractionResponse(CancelInteractionResponse response) { + onRPCReceived(response); + } + + @Override + public void onShowAppMenuResponse(ShowAppMenuResponse response) { + onRPCReceived(response); + } + + @Override public void onUnpublishAppServiceResponse(UnpublishAppServiceResponse response) { onRPCReceived(response); } 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 d4eda9630..b4b66bfc5 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 @@ -35,6 +35,8 @@ package com.smartdevicelink.managers; import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; @@ -43,6 +45,7 @@ import com.smartdevicelink.exception.SdlException; import com.smartdevicelink.managers.audio.AudioStreamManager; import com.smartdevicelink.managers.file.FileManager; import com.smartdevicelink.managers.file.filetypes.SdlArtwork; +import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate; import com.smartdevicelink.managers.lockscreen.LockScreenConfig; import com.smartdevicelink.managers.lockscreen.LockScreenManager; import com.smartdevicelink.managers.permission.PermissionManager; @@ -52,6 +55,7 @@ import com.smartdevicelink.protocol.enums.FunctionID; import com.smartdevicelink.protocol.enums.SessionType; import com.smartdevicelink.proxy.RPCMessage; import com.smartdevicelink.proxy.RPCRequest; +import com.smartdevicelink.proxy.RPCResponse; import com.smartdevicelink.proxy.SdlProxyBase; import com.smartdevicelink.proxy.SystemCapabilityManager; import com.smartdevicelink.proxy.callbacks.OnServiceEnded; @@ -61,6 +65,7 @@ import com.smartdevicelink.proxy.interfaces.ISdl; import com.smartdevicelink.proxy.interfaces.ISdlServiceListener; import com.smartdevicelink.proxy.interfaces.IVideoStreamListener; import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener; +import com.smartdevicelink.proxy.rpc.ChangeRegistration; import com.smartdevicelink.proxy.rpc.OnHMIStatus; import com.smartdevicelink.proxy.rpc.RegisterAppInterfaceResponse; import com.smartdevicelink.proxy.rpc.SdlMsgVersion; @@ -69,12 +74,14 @@ import com.smartdevicelink.proxy.rpc.TTSChunk; import com.smartdevicelink.proxy.rpc.TemplateColorScheme; import com.smartdevicelink.proxy.rpc.enums.AppHMIType; import com.smartdevicelink.proxy.rpc.enums.Language; +import com.smartdevicelink.proxy.rpc.enums.Result; import com.smartdevicelink.proxy.rpc.enums.SdlDisconnectedReason; import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType; import com.smartdevicelink.proxy.rpc.listeners.OnMultipleRequestListener; import com.smartdevicelink.proxy.rpc.listeners.OnRPCListener; import com.smartdevicelink.proxy.rpc.listeners.OnRPCNotificationListener; import com.smartdevicelink.proxy.rpc.listeners.OnRPCRequestListener; +import com.smartdevicelink.proxy.rpc.listeners.OnRPCResponseListener; import com.smartdevicelink.security.SdlSecurityBase; import com.smartdevicelink.streaming.audio.AudioStreamingCodec; import com.smartdevicelink.streaming.audio.AudioStreamingParams; @@ -86,6 +93,8 @@ import com.smartdevicelink.transport.utl.TransportRecord; import com.smartdevicelink.util.DebugTool; import com.smartdevicelink.util.Version; +import org.json.JSONException; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -126,12 +135,16 @@ public class SdlManager extends BaseSdlManager{ @Override public void onProxyConnected() { DebugTool.logInfo("Proxy is connected. Now initializing."); + changeRegistrationRetry = 0; + checkLifecycleConfiguration(); initialize(); } @Override public void onProxyClosed(String info, Exception e, SdlDisconnectedReason reason){ - dispose(); + if (!reason.equals(SdlDisconnectedReason.LANGUAGE_CHANGE)){ + dispose(); + } } @Override @@ -226,6 +239,71 @@ public class SdlManager extends BaseSdlManager{ } @Override + protected void checkLifecycleConfiguration(){ + final Language actualLanguage = this.getRegisterAppInterfaceResponse().getLanguage(); + + if (!actualLanguage.equals(hmiLanguage)) { + + final LifecycleConfigurationUpdate lcu = managerListener.managerShouldUpdateLifecycle(actualLanguage); + + if (lcu != null) { + ChangeRegistration changeRegistration = new ChangeRegistration(actualLanguage, actualLanguage); + changeRegistration.setAppName(lcu.getAppName()); + changeRegistration.setNgnMediaScreenAppName(lcu.getShortAppName()); + changeRegistration.setTtsName(lcu.getTtsName()); + changeRegistration.setVrSynonyms(lcu.getVoiceRecognitionCommandNames()); + changeRegistration.setOnRPCResponseListener(new OnRPCResponseListener() { + @Override + public void onResponse(int correlationId, RPCResponse response) { + if (response.getSuccess()){ + // go through and change sdlManager properties that were changed via the LCU update + hmiLanguage = actualLanguage; + + if (lcu.getAppName() != null) { + appName = lcu.getAppName(); + } + + if (lcu.getShortAppName() != null) { + shortAppName = lcu.getShortAppName(); + } + + if (lcu.getTtsName() != null) { + ttsChunks = lcu.getTtsName(); + } + + if (lcu.getVoiceRecognitionCommandNames() != null) { + vrSynonyms = lcu.getVoiceRecognitionCommandNames(); + } + } + try { + DebugTool.logInfo(response.serializeJSON().toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + @Override + public void onError(int correlationId, Result resultCode, String info) { + DebugTool.logError("Change Registration onError: " + resultCode + " | Info: " + info); + changeRegistrationRetry++; + if (changeRegistrationRetry < MAX_RETRY) { + final Handler handler = new Handler(Looper.getMainLooper()); + handler.postDelayed(new Runnable() { + @Override + public void run() { + checkLifecycleConfiguration(); + DebugTool.logInfo("Retry Change Registration Count: " + changeRegistrationRetry); + } + }, 3000); + } + } + }); + this.sendRPC(changeRegistration); + } + } + } + + @Override protected void initialize(){ // Instantiate sub managers this.permissionManager = new PermissionManager(_internalInterface); diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java index 5a59604cc..d27ac27b5 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/SdlManagerListener.java @@ -32,6 +32,9 @@ package com.smartdevicelink.managers; +import com.smartdevicelink.managers.lifecycle.LifecycleConfigurationUpdate; +import com.smartdevicelink.proxy.rpc.enums.Language; + public interface SdlManagerListener extends BaseSdlManagerListener{ /** @@ -50,4 +53,17 @@ public interface SdlManagerListener extends BaseSdlManagerListener{ * @param e the exception */ void onError(String info, Exception e); + + /** + * Called when the SDL manager detected a language mismatch. In case of a language mismatch the + * manager should change the apps registration by updating the lifecycle configuration to the + * specified language. If the app can support the specified language it should return an Object + * of LifecycleConfigurationUpdate, otherwise it should return null to indicate that the language + * is not supported. + * + * @param language The language of the connected head unit the manager is trying to update the configuration. + * @return An object of LifecycleConfigurationUpdate if the head unit language is supported, + * otherwise null to indicate that the language is not supported. + */ + LifecycleConfigurationUpdate managerShouldUpdateLifecycle(Language language); } diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java index 857b26b92..55bff7bba 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/audio/AudioStreamManager.java @@ -56,6 +56,7 @@ import com.smartdevicelink.proxy.interfaces.OnSystemCapabilityListener; import com.smartdevicelink.proxy.rpc.AudioPassThruCapabilities;
import com.smartdevicelink.proxy.rpc.OnHMIStatus;
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.listeners.OnRPCNotificationListener;
import com.smartdevicelink.transport.utl.TransportRecord;
@@ -160,7 +161,11 @@ public class AudioStreamManager extends BaseAudioStreamManager { @Override
public void onNotified(RPCNotification notification) {
if(notification != null){
- hmiLevel = ((OnHMIStatus)notification).getHmiLevel();
+ OnHMIStatus onHMIStatus = (OnHMIStatus)notification;
+ if (onHMIStatus.getWindowID() != null && onHMIStatus.getWindowID() != PredefinedWindows.DEFAULT_WINDOW.getValue()) {
+ return;
+ }
+ hmiLevel = onHMIStatus.getHmiLevel();
if(hmiLevel.equals(HMILevel.HMI_FULL) || hmiLevel.equals(HMILevel.HMI_LIMITED)){
checkState();
}
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java index c5c0027ad..6769db0fc 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenConfig.java @@ -32,6 +32,11 @@ package com.smartdevicelink.managers.lockscreen; +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * <strong>LockScreenConfig</strong> <br> * @@ -47,16 +52,39 @@ package com.smartdevicelink.managers.lockscreen; * <li> customView - If you would like to provide your own view, you can pass it in here.</li> * * <li> deviceLogo - On by default. If available, will show the device or OEMs logo on the lockscreen</li> + * + * <li> displayMode - Describes when the lock screen will be displayed. Defaults to `DISPLAY_MODE_REQUIRED_ONLY`.</li> + * + * <li> enableDismissGesture - If true, then the lock screen can be dismissed with a downward swipe on compatible head units. + * Requires a connection of SDL 6.0+ and the head unit to enable the feature. Defaults to true.</li> */ public class LockScreenConfig { - private boolean enable, deviceLogo; + private boolean enable, deviceLogo, enableDismissGesture; private int backgroundColor, appIconInt, customViewInt; + private @DisplayMode int displayMode; + + /** + * DISPLAY_MODE_NEVER - The lock screen should never be shown. This should almost always mean that you will build your own lock screen. + * DISPLAY_MODE_REQUIRED_ONLY - The lock screen should only be shown when it is required by the head unit. + * DISPLAY_MODE_OPTIONAL_OR_REQUIRED - The lock screen should be shown when required by the head unit or when the head unit says that + * its optional, but *not* in other cases, such as before the user has interacted with your app on the head unit. + * DISPLAY_MODE_ALWAYS - The lock screen should always be shown after connection. + */ + @IntDef({DISPLAY_MODE_NEVER, DISPLAY_MODE_REQUIRED_ONLY, DISPLAY_MODE_OPTIONAL_OR_REQUIRED, DISPLAY_MODE_ALWAYS}) + @Retention(RetentionPolicy.SOURCE) + public @interface DisplayMode {} + public static final int DISPLAY_MODE_NEVER = 0; + public static final int DISPLAY_MODE_REQUIRED_ONLY = 1; + public static final int DISPLAY_MODE_OPTIONAL_OR_REQUIRED = 2; + public static final int DISPLAY_MODE_ALWAYS = 3; public LockScreenConfig(){ // set default values this.enable = true; this.deviceLogo = true; + this.displayMode = DISPLAY_MODE_REQUIRED_ONLY; + this.enableDismissGesture = true; } /** @@ -64,7 +92,10 @@ public class LockScreenConfig { * * If false, you must manage the lock screen * @param enable boolean + * + * @deprecated to disable the lockscreen, use setDisplayMode with DISPLAY_MODE_NEVER instead */ + @Deprecated public void setEnabled(boolean enable){ this.enable = enable; } @@ -72,7 +103,10 @@ public class LockScreenConfig { /** * Gets whether the lock screen is being managed for you * @return boolean + * + * @deprecated to disable the lockscreen, use setDisplayMode with DISPLAY_MODE_NEVER instead */ + @Deprecated public boolean isEnabled() { return enable; } @@ -145,4 +179,39 @@ public class LockScreenConfig { return deviceLogo; } + + /** + * Set the displayMode to be used + * @param displayMode - Describes when the lock screen will be displayed. Defaults to `DISPLAY_MODE_REQUIRED_ONLY`. + */ + public void setDisplayMode(@DisplayMode int displayMode){ + this.displayMode = displayMode; + } + + /** + * Get the displayMode to be used + * @return displayMode - Describes when the lock screen will be displayed. Defaults to `DISPLAY_MODE_REQUIRED_ONLY`. + */ + public @DisplayMode int getDisplayMode(){ + return this.displayMode; + } + + /** + * If true, then the lock screen can be dismissed with a downward swipe on compatible head units. + * Requires a connection of SDL 6.0+ and the head unit to enable the feature. Defaults to true. + * @param enableDismissGesture - enable or disable this feature + */ + public void enableDismissGesture(boolean enableDismissGesture) { + this.enableDismissGesture = enableDismissGesture; + } + + /** + * If true, then the lock screen can be dismissed with a downward swipe on compatible head units. + * Requires a connection of SDL 6.0+ and the head unit to enable the feature. Defaults to true. + * @return - whether or not this is enabled or disabled + */ + public boolean enableDismissGesture() { + return enableDismissGesture; + } + } 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 43e40be6c..30ed1b575 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 @@ -32,8 +32,10 @@ package com.smartdevicelink.managers.lockscreen; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.graphics.Bitmap; import android.os.Build; import android.util.Log; @@ -49,6 +51,7 @@ import com.smartdevicelink.proxy.rpc.OnSystemRequest; import com.smartdevicelink.proxy.rpc.enums.DriverDistractionState; import com.smartdevicelink.proxy.rpc.enums.HMILevel; 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; @@ -68,15 +71,17 @@ public class LockScreenManager extends BaseSubManager { private static final String TAG = "LockScreenManager"; private WeakReference<Context> context; - private HMILevel hmiLevel; + HMILevel hmiLevel; private OnRPCNotificationListener systemRequestListener, ddListener, hmiListener; private String deviceIconUrl; - private boolean driverDistStatus; + boolean driverDistStatus, mIsLockscreenDismissible, enableDismissGesture, lockScreenEnabled, deviceLogoEnabled; private volatile boolean isApplicationForegrounded; private android.arch.lifecycle.LifecycleObserver lifecycleObserver; - protected boolean lockScreenEnabled, deviceLogoEnabled; - protected int lockScreenIcon, lockScreenColor, customView; - protected Bitmap deviceLogo; + int lockScreenIcon, lockScreenColor, customView, displayMode; + Bitmap deviceLogo; + private boolean mLockScreenHasBeenDismissed, lockscreenDismissReceiverRegistered, receivedFirstDDNotification; + private String mLockscreenWarningMsg; + private BroadcastReceiver mLockscreenDismissedReceiver; public LockScreenManager(LockScreenConfig lockScreenConfig, Context context, ISdl internalInterface){ @@ -93,6 +98,14 @@ public class LockScreenManager extends BaseSubManager { customView = lockScreenConfig.getCustomView(); lockScreenEnabled = lockScreenConfig.isEnabled(); deviceLogoEnabled = lockScreenConfig.isDeviceLogoEnabled(); + displayMode = lockScreenConfig.getDisplayMode(); + enableDismissGesture = lockScreenConfig.enableDismissGesture(); + + // for older projects that may not use DisplayMode. This can + // be removed in a major release + if (!lockScreenEnabled){ + displayMode = LockScreenConfig.DISPLAY_MODE_NEVER; + } setupListeners(); } @@ -108,6 +121,12 @@ public class LockScreenManager extends BaseSubManager { // send broadcast to close lock screen if open if (context.get() != null) { context.get().sendBroadcast(new Intent(SDLLockScreenActivity.CLOSE_LOCK_SCREEN_ACTION)); + try { + context.get().unregisterReceiver(mLockscreenDismissedReceiver); + lockscreenDismissReceiverRegistered = false; + } catch (IllegalArgumentException e) { + //do nothing + } } // remove listeners internalInterface.removeOnRPCNotificationListener(FunctionID.ON_HMI_STATUS, hmiListener); @@ -153,7 +172,11 @@ public class LockScreenManager extends BaseSubManager { hmiListener = new OnRPCNotificationListener() { @Override public void onNotified(RPCNotification notification) { - hmiLevel = ((OnHMIStatus)notification).getHmiLevel(); + OnHMIStatus onHMIStatus = (OnHMIStatus)notification; + if (onHMIStatus.getWindowID() != null && onHMIStatus.getWindowID() != PredefinedWindows.DEFAULT_WINDOW.getValue()) { + return; + } + hmiLevel = onHMIStatus.getHmiLevel(); launchLockScreenActivity(); } }; @@ -166,6 +189,22 @@ public class LockScreenManager extends BaseSubManager { // do something with the status if (notification != null) { OnDriverDistraction ddState = (OnDriverDistraction) notification; + Boolean isDismissible = ddState.getLockscreenDismissibility(); + Log.i(TAG, "Lock screen dismissible: "+ isDismissible); + if (isDismissible != null) { + // both of these conditions must be met to be able to dismiss lockscreen + if (isDismissible && enableDismissGesture){ + mIsLockscreenDismissible = true; + + // if DisplayMode is set to ALWAYS, it will be shown before the first DD notification. + // If this is our first DD notification and we are in ALWAYS mode, send another intent to + // enable the dismissal + if (!receivedFirstDDNotification && displayMode == LockScreenConfig.DISPLAY_MODE_ALWAYS ){ + launchLockScreenActivity(); + } + } + } + mLockscreenWarningMsg = ddState.getLockscreenWarningMessage(); if (ddState.getState() == DriverDistractionState.DD_ON){ // launch lock screen @@ -174,10 +213,9 @@ public class LockScreenManager extends BaseSubManager { }else{ // close lock screen driverDistStatus = false; - if (context.get() != null) { - context.get().sendBroadcast(new Intent(SDLLockScreenActivity.CLOSE_LOCK_SCREEN_ACTION)); - } + closeLockScreenActivity(); } + receivedFirstDDNotification = true; } } }; @@ -226,6 +264,15 @@ public class LockScreenManager extends BaseSubManager { } else{ isApplicationForegrounded = true; } + + mLockscreenDismissedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (SDLLockScreenActivity.KEY_LOCKSCREEN_DISMISSED.equals(intent.getAction())) { + mLockScreenHasBeenDismissed = true; + } + } + }; } //// @@ -240,11 +287,20 @@ public class LockScreenManager extends BaseSubManager { * X. If the status is set to OFF, Send broadcast to close lock screen if it is open */ private void launchLockScreenActivity(){ + // If the user has dismissed the lockscreen for this run or has disabled it, do not show it + if (mLockScreenHasBeenDismissed || displayMode == LockScreenConfig.DISPLAY_MODE_NEVER) { + return; + } // intent to open SDLLockScreenActivity // pass in icon, background color, and custom view if (lockScreenEnabled && isApplicationForegrounded && context.get() != null) { + if (mIsLockscreenDismissible && !lockscreenDismissReceiverRegistered) { + context.get().registerReceiver(mLockscreenDismissedReceiver, new IntentFilter(SDLLockScreenActivity.KEY_LOCKSCREEN_DISMISSED)); + lockscreenDismissReceiverRegistered = true; + + } LockScreenStatus status = getLockScreenStatus(); - if (status == LockScreenStatus.REQUIRED) { + if (status == LockScreenStatus.REQUIRED || displayMode == LockScreenConfig.DISPLAY_MODE_ALWAYS || (status == LockScreenStatus.OPTIONAL && displayMode == LockScreenConfig.DISPLAY_MODE_OPTIONAL_OR_REQUIRED)) { Intent showLockScreenIntent = new Intent(context.get(), SDLLockScreenActivity.class); showLockScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -254,8 +310,24 @@ public class LockScreenManager extends BaseSubManager { showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_CUSTOM_VIEW_EXTRA, customView); showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_EXTRA, deviceLogoEnabled); showLockScreenIntent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_BITMAP, deviceLogo); + showLockScreenIntent.putExtra(SDLLockScreenActivity.KEY_LOCKSCREEN_DISMISSIBLE, mIsLockscreenDismissible); + showLockScreenIntent.putExtra(SDLLockScreenActivity.KEY_LOCKSCREEN_WARNING_MSG, mLockscreenWarningMsg); context.get().startActivity(showLockScreenIntent); } else if (status == LockScreenStatus.OFF) { + closeLockScreenActivity(); + } + } + } + + private void closeLockScreenActivity(){ + + if (displayMode == LockScreenConfig.DISPLAY_MODE_ALWAYS){ + return; + } + + if (context.get() != null) { + LockScreenStatus status = getLockScreenStatus(); + if (status == LockScreenStatus.OFF || (status == LockScreenStatus.OPTIONAL && displayMode != LockScreenConfig.DISPLAY_MODE_OPTIONAL_OR_REQUIRED)) { context.get().sendBroadcast(new Intent(SDLLockScreenActivity.CLOSE_LOCK_SCREEN_ACTION)); } } @@ -271,9 +343,9 @@ public class LockScreenManager extends BaseSubManager { * * @return Whether or not the Lock Screen is required */ - protected synchronized LockScreenStatus getLockScreenStatus() { + synchronized LockScreenStatus getLockScreenStatus() { - if ( (hmiLevel == null) || (hmiLevel.equals(HMILevel.HMI_NONE))) { + if ((hmiLevel == null) || (hmiLevel.equals(HMILevel.HMI_NONE))) { return LockScreenStatus.OFF; } else if ( hmiLevel.equals(HMILevel.HMI_BACKGROUND)) { @@ -284,7 +356,7 @@ public class LockScreenManager extends BaseSubManager { return LockScreenStatus.REQUIRED; } } - else if ( (hmiLevel.equals(HMILevel.HMI_FULL)) || (hmiLevel.equals(HMILevel.HMI_LIMITED))) { + else if ((hmiLevel.equals(HMILevel.HMI_FULL)) || (hmiLevel.equals(HMILevel.HMI_LIMITED))) { if (!driverDistStatus) { return LockScreenStatus.OPTIONAL; } else { diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java index 6ae10ec73..d87d27ca2 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/SDLLockScreenActivity.java @@ -39,9 +39,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.os.Bundle; +import android.view.GestureDetector; +import android.view.MotionEvent; import android.view.Window; import android.widget.ImageView; import android.widget.RelativeLayout; +import android.widget.TextView; import com.smartdevicelink.R; @@ -55,6 +58,12 @@ public class SDLLockScreenActivity extends Activity { public static final String LOCKSCREEN_CUSTOM_VIEW_EXTRA = "LOCKSCREEN_CUSTOM_VIEW_EXTRA"; public static final String LOCKSCREEN_DEVICE_LOGO_DOWNLOADED = "LOCKSCREEN_DEVICE_LOGO_DOWNLOADED"; public static final String CLOSE_LOCK_SCREEN_ACTION = "CLOSE_LOCK_SCREEN"; + public static final String KEY_LOCKSCREEN_DISMISSED = "KEY_LOCKSCREEN_DISMISSED"; + public static final String KEY_LOCKSCREEN_DISMISSIBLE = "KEY_LOCKSCREEN_DISMISSIBLE"; + public static final String KEY_LOCKSCREEN_WARNING_MSG = "KEY_LOCKSCREEN_WARNING_MSG"; + private static final int MIN_SWIPE_DISTANCE = 200; + private boolean mIsDismissible; + private GestureDetector mGestureDetector; private final BroadcastReceiver lockScreenBroadcastReceiver = new BroadcastReceiver() { @Override @@ -81,6 +90,7 @@ public class SDLLockScreenActivity extends Activity { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); + mGestureDetector = new GestureDetector(this, new SwipeUpGestureListener()); // set any parameters that came from the lock screen manager initializeActivity(getIntent()); @@ -94,6 +104,14 @@ public class SDLLockScreenActivity extends Activity { } @Override + public boolean onTouchEvent(MotionEvent event) { + if (mIsDismissible) { + return mGestureDetector.onTouchEvent(event); + } + return super.onTouchEvent(event); + } + + @Override protected void onDestroy() { unregisterReceiver(lockScreenBroadcastReceiver); super.onDestroy(); @@ -107,6 +125,9 @@ public class SDLLockScreenActivity extends Activity { protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); + if (intent != null && intent.getBooleanExtra(KEY_LOCKSCREEN_DISMISSIBLE, false)){ + initializeActivity(intent); + } } public void initializeActivity(Intent intent){ @@ -133,6 +154,11 @@ public class SDLLockScreenActivity extends Activity { if (deviceLogoEnabled && deviceIcon != null){ setDeviceLogo(deviceIcon); } + mIsDismissible = intent.getBooleanExtra(KEY_LOCKSCREEN_DISMISSIBLE, false); + String warningMsg = intent.getStringExtra(KEY_LOCKSCREEN_WARNING_MSG); + if (mIsDismissible) { + setLockscreenWarningMessage(warningMsg); + } } } } @@ -154,8 +180,26 @@ public class SDLLockScreenActivity extends Activity { } } + private void setLockscreenWarningMessage(String msg) { + TextView tv = findViewById(R.id.lockscreen_text); + if (tv != null) { + tv.setText(msg != null ? msg : getString(R.string.default_lockscreen_warning_message)); + } + } + private void setCustomView(int customView) { setContentView(customView); } + private class SwipeUpGestureListener extends GestureDetector.SimpleOnGestureListener { + @Override + public boolean onFling(MotionEvent event1, MotionEvent event2, + float velocityX, float velocityY) { + if ((event2.getY() - event1.getY()) > MIN_SWIPE_DISTANCE) { + sendBroadcast(new Intent(KEY_LOCKSCREEN_DISMISSED)); + finish(); + } + return true; + } + } } 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 49798078c..73065b865 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 @@ -62,6 +62,7 @@ import com.smartdevicelink.proxy.rpc.TouchCoord; import com.smartdevicelink.proxy.rpc.TouchEvent; import com.smartdevicelink.proxy.rpc.VideoStreamingCapability; 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.listeners.OnRPCNotificationListener; @@ -92,6 +93,7 @@ public class VideoStreamManager extends BaseVideoStreamManager { private VideoStreamingParameters parameters; private IVideoStreamListener streamListener; private boolean isTransportAvailable = false; + private boolean hasStarted; // INTERNAL INTERFACES @@ -114,8 +116,7 @@ public class VideoStreamManager extends BaseVideoStreamManager { } startEncoder(); stateMachine.transitionToState(StreamingStateMachine.STARTED); - - + hasStarted = true; } } @@ -140,7 +141,11 @@ public class VideoStreamManager extends BaseVideoStreamManager { @Override public void onNotified(RPCNotification notification) { if(notification != null){ - hmiLevel = ((OnHMIStatus)notification).getHmiLevel(); + 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(); } @@ -194,6 +199,7 @@ public class VideoStreamManager extends BaseVideoStreamManager { && hmiLevel != null && hmiLevel.equals(HMILevel.HMI_FULL) && parameters != null){ + stateMachine.transitionToState(StreamingStateMachine.READY); transitionToState(READY); } } @@ -310,6 +316,7 @@ public class VideoStreamManager extends BaseVideoStreamManager { //Encoder should be up and running createRemoteDisplay(virtualDisplayEncoder.getVirtualDisplay()); stateMachine.transitionToState(StreamingStateMachine.STARTED); + hasStarted = true; } catch (Exception e) { stateMachine.transitionToState(StreamingStateMachine.ERROR); e.printStackTrace(); @@ -384,8 +391,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) && (hmiLevel == HMILevel.HMI_FULL); } /** @@ -393,8 +399,7 @@ public class VideoStreamManager extends BaseVideoStreamManager { * @return boolean (true = not paused, false = paused) */ public boolean isPaused(){ - return (stateMachine.getState() == StreamingStateMachine.STARTED) || - (hmiLevel != HMILevel.HMI_FULL); + return (hasStarted && stateMachine.getState() == StreamingStateMachine.STOPPED) || (hmiLevel != HMILevel.HMI_FULL); } /** @@ -451,9 +456,8 @@ public class VideoStreamManager extends BaseVideoStreamManager { if(resolution != null){ DisplayMetrics displayMetrics = new DisplayMetrics(); disp.getMetrics(displayMetrics); - touchScalar[0] = ((float)displayMetrics.widthPixels) / resolution.getResolutionWidth(); - touchScalar[1] = ((float)displayMetrics.heightPixels) / resolution.getResolutionHeight(); - } + createTouchScalar(resolution, displayMetrics); + } } @@ -499,6 +503,11 @@ public class VideoStreamManager extends BaseVideoStreamManager { } } + void createTouchScalar(ImageResolution resolution, DisplayMetrics displayMetrics) { + touchScalar[0] = ((float)displayMetrics.widthPixels) / resolution.getResolutionWidth(); + touchScalar[1] = ((float)displayMetrics.heightPixels) / resolution.getResolutionHeight(); + } + List<MotionEvent> convertTouchEvent(OnTouchEvent onTouchEvent){ List<MotionEvent> motionEventList = new ArrayList<MotionEvent>(); @@ -677,4 +686,4 @@ public class VideoStreamManager extends BaseVideoStreamManager { } } -}
\ No newline at end of file +} diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java b/android/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java index c06709b52..c443abfc6 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/protocol/SdlProtocol.java @@ -36,7 +36,12 @@ import android.support.annotation.NonNull; import com.smartdevicelink.protocol.enums.SessionType; import com.smartdevicelink.transport.MultiplexTransportConfig; +import com.smartdevicelink.transport.TCPTransportConfig; +import com.smartdevicelink.transport.TCPTransportManager; import com.smartdevicelink.transport.TransportManager; +import com.smartdevicelink.transport.enums.TransportType; + +import java.util.Collections; @SuppressWarnings("WeakerAccess") @@ -54,17 +59,26 @@ public class SdlProtocol extends SdlProtocolBase { } + public SdlProtocol(@NonNull ISdlProtocol iSdlProtocol, @NonNull TCPTransportConfig config) { + super(iSdlProtocol,config); + this.requestedPrimaryTransports = Collections.singletonList(TransportType.TCP); + this.requestedSecondaryTransports = null; + this.requiresHighBandwidth =false; + this.setTransportManager(new TCPTransportManager(config,transportEventListener)); + } + /** * If there was a TransportListener attached to the supplied multiplex config, this method will * call the onTransportEvent method. */ @Override void notifyDevTransportListener (){ - MultiplexTransportConfig transportConfig = (MultiplexTransportConfig)this.transportConfig; - if(transportConfig.getTransportListener() != null && transportManager != null) { - transportConfig.getTransportListener().onTransportEvent(transportManager.getConnectedTransports(), isTransportForServiceAvailable(SessionType.PCM),isTransportForServiceAvailable(SessionType.NAV)); + if(TransportType.MULTIPLEX.equals(transportConfig.getTransportType() )) { + MultiplexTransportConfig transportConfig = (MultiplexTransportConfig) this.transportConfig; + if (transportConfig.getTransportListener() != null && transportManager != null) { + transportConfig.getTransportListener().onTransportEvent(transportManager.getConnectedTransports(), isTransportForServiceAvailable(SessionType.PCM), isTransportForServiceAvailable(SessionType.NAV)); + } } } - } diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/LockScreenManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/LockScreenManager.java index 76f92487f..d94372740 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/LockScreenManager.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/LockScreenManager.java @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following - * disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ +/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
package com.smartdevicelink.proxy;
import android.graphics.Bitmap;
@@ -40,6 +40,7 @@ import com.smartdevicelink.util.AndroidTools; import java.io.IOException;
+@Deprecated
public class LockScreenManager {
public interface OnLockScreenIconDownloadedListener{
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java index a48376751..763c139e9 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyALM.java @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following - * disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ +/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
package com.smartdevicelink.proxy;
import android.app.Service;
@@ -67,7 +67,13 @@ import java.util.Vector; import static com.smartdevicelink.proxy.SystemCapabilityManager.convertToList;
-
+/**
+ * @deprecated use {@link com.smartdevicelink.managers.SdlManager} instead.
+ *
+ * The guide created for the initial transition of SdlProxyBase/ALM to SdlManager can be found at
+ * <a href="https://smartdevicelink.com/en/guides/android/migrating-to-newer-sdl-versions/updating-to-v47/">Migrating to SDL Manager</a>
+ */
+@Deprecated
public class SdlProxyALM extends SdlProxyBase<IProxyListenerALM> {
private static final String SDL_LIB_TRACE_KEY = "42baba60-eb57-11df-98cf-0800200c9a66";
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java index b7d81716b..ec6c751b8 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java @@ -123,6 +123,7 @@ import com.smartdevicelink.trace.enums.InterfaceActivityDirection; import com.smartdevicelink.transport.BaseTransportConfig;
import com.smartdevicelink.transport.MultiplexTransportConfig;
import com.smartdevicelink.transport.SiphonServer;
+import com.smartdevicelink.transport.TCPTransportConfig;
import com.smartdevicelink.transport.USBTransportConfig;
import com.smartdevicelink.transport.enums.TransportType;
import com.smartdevicelink.util.CorrelationIdGenerator;
@@ -158,8 +159,14 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.ScheduledExecutorService;
-
+/**
+ * @deprecated use {@link com.smartdevicelink.managers.SdlManager} instead.
+ *
+ * The guide created for the initial transition of SdlProxyBase to SdlManager can be found at
+ * <a href="https://smartdevicelink.com/en/guides/android/migrating-to-newer-sdl-versions/updating-to-v47/">Migrating to SDL Manager</a>
+ */
@SuppressWarnings({"WeakerAccess", "Convert2Diamond"})
+@Deprecated
public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> {
// Used for calls to Android Log class.
public static final String TAG = "SdlProxy";
@@ -246,6 +253,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> private OnSystemRequest lockScreenIconRequest = null;
private TelephonyManager telephonyManager = null;
private DeviceInfo deviceInfo = null;
+ private ISdlServiceListener navServiceListener;
/**
* Contains current configuration for the transport that was selected during
@@ -342,6 +350,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> if(isConnected()){
sdlSession.setDesiredVideoParams(parameters);
sdlSession.startService(SessionType.NAV,sdlSession.getSessionId(),encrypted);
+ addNavListener();
}
}
@@ -540,13 +549,13 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> @Override
public void onTransportDisconnected(String info, boolean altTransportAvailable, BaseTransportConfig transportConfig) {
+
notifyPutFileStreamError(null, info);
- if( altTransportAvailable){
+ if (altTransportAvailable){
SdlProxyBase.this._transportConfig = transportConfig;
Log.d(TAG, "notifying RPC session ended, but potential primary transport available");
cycleProxy(SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST);
-
}else{
notifyProxyClosed(info, new SdlException("Transport disconnected.", SdlExceptionCause.SDL_UNAVAILABLE), SdlDisconnectedReason.TRANSPORT_DISCONNECT);
}
@@ -1563,14 +1572,14 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> synchronized(CONNECTION_REFERENCE_LOCK) {
//Handle legacy USB connections
- if(_transportConfig != null
- && TransportType.USB.equals(_transportConfig.getTransportType())){
+ if (_transportConfig != null
+ && TransportType.USB.equals(_transportConfig.getTransportType())) {
//A USB transport config was provided
- USBTransportConfig usbTransportConfig = (USBTransportConfig)_transportConfig;
- if(usbTransportConfig.getUsbAccessory() == null){
+ USBTransportConfig usbTransportConfig = (USBTransportConfig) _transportConfig;
+ if (usbTransportConfig.getUsbAccessory() == null) {
DebugTool.logInfo("Legacy USB transport config was used, but received null for accessory. Attempting to connect with router service");
//The accessory was null which means it came from a router service
- MultiplexTransportConfig multiplexTransportConfig = new MultiplexTransportConfig(usbTransportConfig.getUSBContext(),_appID);
+ MultiplexTransportConfig multiplexTransportConfig = new MultiplexTransportConfig(usbTransportConfig.getUSBContext(), _appID);
multiplexTransportConfig.setRequiresHighBandwidth(true);
multiplexTransportConfig.setSecurityLevel(MultiplexTransportConfig.FLAG_MULTI_SECURITY_OFF);
multiplexTransportConfig.setPrimaryTransports(Collections.singletonList(TransportType.USB));
@@ -1579,9 +1588,11 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> }
}
- if(_transportConfig.getTransportType().equals(TransportType.MULTIPLEX)){
- this.sdlSession = new SdlSession2(_interfaceBroker,(MultiplexTransportConfig)_transportConfig);
- }else{
+ if (_transportConfig != null && _transportConfig.getTransportType().equals(TransportType.MULTIPLEX)) {
+ this.sdlSession = new SdlSession2(_interfaceBroker, (MultiplexTransportConfig) _transportConfig);
+ }else if(_transportConfig != null &&_transportConfig.getTransportType().equals(TransportType.TCP)){
+ this.sdlSession = new SdlSession2(_interfaceBroker, (TCPTransportConfig) _transportConfig);
+ }else {
this.sdlSession = SdlSession.createSession((byte)getProtocolVersion().getMajor(),_interfaceBroker, _transportConfig);
}
}
@@ -1834,6 +1845,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> try{
_cycling = true;
cleanProxy(disconnectedReason);
+
initializeProxy();
if(!SdlDisconnectedReason.LEGACY_BLUETOOTH_MODE_ENABLED.equals(disconnectedReason)
&& !SdlDisconnectedReason.PRIMARY_TRANSPORT_CYCLE_REQUEST.equals(disconnectedReason)){//We don't want to alert higher if we are just cycling for legacy bluetooth
@@ -3551,6 +3563,36 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> _proxyListener.onGetInteriorVehicleDataResponse(msg);
onRPCResponseReceived(msg);
}
+ } else if (functionName.equals(FunctionID.CREATE_WINDOW.toString())) {
+ final CreateWindowResponse msg = new CreateWindowResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onCreateWindowResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onCreateWindowResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ } else if (functionName.equals(FunctionID.DELETE_WINDOW.toString())) {
+ final DeleteWindowResponse msg = new DeleteWindowResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onDeleteWindowResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onDeleteWindowResponse(msg);
+ onRPCResponseReceived(msg);
+ }
} else if (functionName.equals(FunctionID.GET_SYSTEM_CAPABILITY.toString())) {
// GetSystemCapabilityResponse
final GetSystemCapabilityResponse msg = new GetSystemCapabilityResponse(hash);
@@ -3702,12 +3744,28 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> _mainUIHandler.post(new Runnable() {
@Override
public void run() {
- _proxyListener.onCloseApplicationResponse( msg);
+ _proxyListener.onCloseApplicationResponse(msg);
onRPCResponseReceived(msg);
}
});
} else {
- _proxyListener.onCloseApplicationResponse( msg);
+ _proxyListener.onCloseApplicationResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ } else if (functionName.equals(FunctionID.CANCEL_INTERACTION.toString())) {
+ final CancelInteractionResponse msg = new CancelInteractionResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ // Run in UI thread
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onCancelInteractionResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onCancelInteractionResponse(msg);
onRPCResponseReceived(msg);
}
} else if (functionName.equals(FunctionID.UNPUBLISH_APP_SERVICE.toString())) {
@@ -3726,6 +3784,52 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> _proxyListener.onUnpublishAppServiceResponse( msg);
onRPCResponseReceived(msg);
}
+ } else if (functionName.equals(FunctionID.SHOW_APP_MENU.toString())) {
+ final ShowAppMenuResponse msg = new ShowAppMenuResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ // Run in UI thread
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onShowAppMenuResponse( msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onShowAppMenuResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ } else if (functionName.equals(FunctionID.GET_INTERIOR_VEHICLE_DATA_CONSENT.toString())) {
+ final GetInteriorVehicleDataConsentResponse msg = new GetInteriorVehicleDataConsentResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onGetInteriorVehicleDataConsentResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onGetInteriorVehicleDataConsentResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ } else if (functionName.equals(FunctionID.RELEASE_INTERIOR_VEHICLE_MODULE.toString())) {
+ final ReleaseInteriorVehicleDataModuleResponse msg = new ReleaseInteriorVehicleDataModuleResponse(hash);
+ msg.format(rpcSpecVersion, true);
+ if (_callbackToUIThread) {
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ _proxyListener.onReleaseInteriorVehicleDataModuleResponse(msg);
+ onRPCResponseReceived(msg);
+ }
+ });
+ } else {
+ _proxyListener.onReleaseInteriorVehicleDataModuleResponse(msg);
+ onRPCResponseReceived(msg);
+ }
} else {
if (_sdlMsgVersion != null) {
DebugTool.logError("Unrecognized response Message: " + functionName +
@@ -3735,6 +3839,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> }
} // end-if
+
} else if (messageType.equals(RPCMessage.KEY_NOTIFICATION)) {
if (functionName.equals(FunctionID.ON_HMI_STATUS.toString())) {
// OnHMIStatus
@@ -4108,7 +4213,19 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> if (_advancedLifecycleManagementEnabled) {
// This requires the proxy to be cycled
- cycleProxy(SdlDisconnectedReason.convertAppInterfaceUnregisteredReason(msg.getReason()));
+
+ if(_mainUIHandler == null){
+ _mainUIHandler = new Handler(Looper.getMainLooper());
+ }
+
+ //This needs to be ran on the main thread
+
+ _mainUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ cycleProxy(SdlDisconnectedReason.convertAppInterfaceUnregisteredReason(msg.getReason()));
+ }
+ });
} else {
if (_callbackToUIThread) {
// Run in UI thread
@@ -4813,7 +4930,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> sdlSession.setDesiredVideoParams(emptyParam);
sdlSession.startService(SessionType.NAV, sdlSession.getSessionId(), isEncrypted);
-
+ addNavListener();
FutureTask<Void> fTask = createFutureTask(new CallableMethod(RESPONSE_WAIT_TIME));
ScheduledExecutorService scheduler = createScheduler();
scheduler.execute(fTask);
@@ -4861,7 +4978,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> sdlSession.setDesiredVideoParams(emptyParam);
sdlSession.startService(SessionType.NAV, sdlSession.getSessionId(), isEncrypted);
-
+ addNavListener();
FutureTask<Void> fTask = createFutureTask(new CallableMethod(RESPONSE_WAIT_TIME));
ScheduledExecutorService scheduler = createScheduler();
scheduler.execute(fTask);
@@ -5235,7 +5352,7 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> navServiceStartRejectedParams = null;
sdlSession.startService(SessionType.NAV, sdlSession.getSessionId(), isEncrypted);
-
+ addNavListener();
FutureTask<Void> fTask = createFutureTask(new CallableMethod(RESPONSE_WAIT_TIME));
ScheduledExecutorService scheduler = createScheduler();
scheduler.execute(fTask);
@@ -5300,6 +5417,35 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> sdlSession.drainEncoder(endOfStream);
}
+ private void addNavListener(){
+
+ // videos may be started and stopped. Only add this once
+ if (navServiceListener == null){
+
+ navServiceListener = new ISdlServiceListener() {
+ @Override
+ public void onServiceStarted(SdlSession session, SessionType type, boolean isEncrypted) { }
+
+ @Override
+ public void onServiceEnded(SdlSession session, SessionType type) {
+ // reset nav flags so nav can start upon the next transport connection
+ resetNavStartFlags();
+ // propagate notification up to proxy listener so the developer will know that the service is ended
+ if (_proxyListener != null) {
+ _proxyListener.onServiceEnded(new OnServiceEnded(type));
+ }
+ }
+
+ @Override
+ public void onServiceError(SdlSession session, SessionType type, String reason) {
+ // if there is an error reset the flags so that there is a chance to restart streaming
+ resetNavStartFlags();
+ }
+ };
+ this.sdlSession.addServiceListener(SessionType.NAV, navServiceListener);
+ }
+ }
+
/**
* Opens a audio service (service type 10) and subsequently provides an IAudioStreamListener
* to the app to send audio data.
@@ -5452,7 +5598,13 @@ public abstract class SdlProxyBase<proxyListenerType extends IProxyListenerBase> private void AudioServiceEndedNACK() {
pcmServiceEndResponseReceived = true;
pcmServiceEndResponse = false;
- }
+ }
+
+ private void resetNavStartFlags() {
+ navServiceStartResponseReceived = false;
+ navServiceStartResponse = false;
+ navServiceStartRejectedParams = null;
+ }
public void setAppService(Service mService)
{
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java index 897add3f5..5240c4813 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBuilder.java @@ -49,6 +49,7 @@ import com.smartdevicelink.transport.MultiplexTransportConfig; import java.util.List; import java.util.Vector; +@Deprecated public class SdlProxyBuilder { // Required parameters private IProxyListenerALM listener; diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyConfigurationResources.java b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyConfigurationResources.java index c96df0f78..6e76db82a 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyConfigurationResources.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyConfigurationResources.java @@ -1,38 +1,39 @@ -/* - * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following - * disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ +/*
+ * Copyright (c) 2017 - 2019, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
package com.smartdevicelink.proxy;
import android.telephony.TelephonyManager;
+@Deprecated
public class SdlProxyConfigurationResources {
private String _sdlConfigurationFilePath;
private TelephonyManager _telephonyManager;
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java b/android/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java index 8af6b1c59..a35b4790a 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java @@ -173,7 +173,7 @@ public abstract class SdlRemoteDisplay extends Presentation { public void run() { // Want to create presentation on UI thread so it finds the right Looper // when setting up the Dialog. - if ((remoteDisplay == null) && (mDisplay != null)) + if((mDisplay!=null) && (remoteDisplay == null || remoteDisplay.getDisplay() != mDisplay)) { try { Constructor constructor = remoteDisplayClass.getConstructor(Context.class, Display.class); diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java index d5843f4c2..63766f0b1 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java @@ -47,6 +47,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import static com.smartdevicelink.util.DebugTool.logError; import static com.smartdevicelink.util.NativeLogTool.logInfo; @@ -354,8 +356,46 @@ public class MultiplexTcpTransport extends MultiplexBaseTransport { } private class WriterThread extends Thread { - private boolean mCancelled = false; + private boolean isHalted = false; private boolean mVerbose = false; + final BlockingQueue<OutPacket> packetQueue = new LinkedBlockingQueue<>(); + + @Override + public void run() { + while(!isHalted){ + try{ + OutPacket packet = packetQueue.take(); + if(packet == null){ + continue; + } + + OutputStream out; + synchronized (MultiplexTcpTransport.this) { + out = mOutputStream; + } + + if ((out != null) && (!isHalted)) { + try { + out.write(packet.bytes, packet.offset, packet.count); + if (mVerbose) { + logInfo("TCPTransport.sendBytesOverTransport: successfully sent data"); + } + } catch (IOException e) { + logError("TCPTransport.sendBytesOverTransport: error during sending data: " + e.getMessage()); + } + } else { + if (isHalted) { + logError("TCPTransport: sendBytesOverTransport request accepted, thread is cancelled"); + } else { + logError("TCPTransport: sendBytesOverTransport request accepted, but output stream is null"); + } + } + + }catch(InterruptedException e){ + break; + } + } + } public void write(byte[] msgBytes, int offset, int count) { if ((msgBytes == null) || (msgBytes.length == 0)) { @@ -366,32 +406,12 @@ public class MultiplexTcpTransport extends MultiplexBaseTransport { if (offset + count > msgBytes.length) { count = msgBytes.length - offset; } + packetQueue.add(new OutPacket(msgBytes, offset, count)); - OutputStream out; - synchronized (MultiplexTcpTransport.this) { - out = mOutputStream; - } - - if ((out != null) && (!mCancelled)) { - try { - out.write(msgBytes, offset, count); - if (mVerbose) { - logInfo("TCPTransport.sendBytesOverTransport: successfully sent data"); - } - } catch (IOException e) { - logError("TCPTransport.sendBytesOverTransport: error during sending data: " + e.getMessage()); - } - } else { - if (mCancelled) { - logError("TCPTransport: sendBytesOverTransport request accepted, thread is cancelled"); - } else { - logError("TCPTransport: sendBytesOverTransport request accepted, but output stream is null"); - } - } } public synchronized void cancel() { - mCancelled = true; + isHalted = true; if (mOutputStream != null) { synchronized (MultiplexTcpTransport.this) { try { @@ -410,4 +430,18 @@ public class MultiplexTcpTransport extends MultiplexBaseTransport { } } } + + private final class OutPacket{ + byte[] bytes; + int count; + int offset; + + OutPacket(byte[] bytes, int offset, int count){ + this.bytes = bytes; + this.offset = offset; + this.count = count; + } + } + + } diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java index dcfee9745..60ff45206 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java @@ -3173,10 +3173,10 @@ public class SdlRouterService extends Service{ * @return */ private TransportType getCompatPrimaryTransport(){ - if(this.registeredTransports != null){ + if(this.registeredTransports != null && this.registeredTransports.size() > 0) { List<TransportType> transportTypes = this.registeredTransports.valueAt(0); - if(transportTypes != null){ - if(transportTypes.get(0) != null){ + if (transportTypes != null) { + if (transportTypes.get(0) != null) { return transportTypes.get(0); } } @@ -3199,7 +3199,9 @@ public class SdlRouterService extends Service{ int flags = receivedBundle.getInt(TransportConstants.BYTES_TO_SEND_FLAGS, TransportConstants.BYTES_TO_SEND_FLAG_NONE); TransportType transportType = TransportType.valueForString(receivedBundle.getString(TransportConstants.TRANSPORT_TYPE)); if(transportType == null){ - transportType = getCompatPrimaryTransport(); + synchronized (TRANSPORT_LOCK){ + transportType = getCompatPrimaryTransport(); + } receivedBundle.putString(TransportConstants.TRANSPORT_TYPE, transportType.name()); } diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TCPTransportManager.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TCPTransportManager.java new file mode 100644 index 000000000..29e0c3aa1 --- /dev/null +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TCPTransportManager.java @@ -0,0 +1,135 @@ +package com.smartdevicelink.transport; + +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.smartdevicelink.protocol.SdlPacket; +import com.smartdevicelink.transport.enums.TransportType; +import com.smartdevicelink.transport.utl.TransportRecord; +import com.smartdevicelink.util.DebugTool; + +import java.lang.ref.WeakReference; + +public class TCPTransportManager extends TransportManagerBase{ + + private static final String TAG = "TCPTransportManager"; + + private TCPHandler tcpHandler; + private MultiplexTcpTransport transport; + private TCPTransportConfig config; + + public TCPTransportManager(TCPTransportConfig config, TransportEventListener transportEventListener){ + super(config,transportEventListener); + Log.d(TAG, "USING THE TCP TRANSPORT MANAGER"); + this.config = config; + tcpHandler = new TCPHandler(this); + transport = new MultiplexTcpTransport(config.getPort(), config.getIPAddress(),config.getAutoReconnect(),tcpHandler, null); + } + + @Override + public void start() { + transport.start(); + + } + + @Override + public void close(long sessionId) { + transport.stop(); + } + + @Override + public void resetSession() { + if(transport != null){ + transport.stop(); + } + //TODO make sure this makes sense + transport = new MultiplexTcpTransport(config.getPort(), config.getIPAddress(),config.getAutoReconnect(), tcpHandler, null); + + } + + @Override + public boolean isConnected(TransportType transportType, String address) { + return (transportType == null || TransportType.TCP.equals(transportType)) && transport.isConnected(); + } + + @Override + public TransportRecord getTransportRecord(TransportType transportType, String address) { + if(transport != null){ + return transport.getTransportRecord(); + }else{ + return null; + } + } + + @Override + public void sendPacket(SdlPacket packet) { + if(packet != null){ + byte[] rawBytes = packet.constructPacket(); + if(rawBytes != null && rawBytes.length >0){ + transport.write(rawBytes, 0, rawBytes.length); + } + } + + } + + + protected static class TCPHandler extends Handler { + + final WeakReference<TCPTransportManager> provider; + + public TCPHandler(TCPTransportManager provider){ + this.provider = new WeakReference<>(provider); + } + @Override + public void handleMessage(Message msg) { + if(this.provider.get() == null){ + return; + } + TCPTransportManager service = this.provider.get(); + if(service.transportListener == null){ + return; + } + switch (msg.what) { + case SdlRouterService.MESSAGE_STATE_CHANGE: + switch (msg.arg1) { + case MultiplexBaseTransport.STATE_CONNECTED: + synchronized (service.TRANSPORT_STATUS_LOCK){ + service.transportStatus.clear(); + service.transportStatus.add(service.transport.getTransportRecord()); + } + DebugTool.logInfo("TCP transport has connected"); + service.transportListener.onTransportConnected(service.transportStatus); + break; + case MultiplexBaseTransport.STATE_CONNECTING: + // Currently attempting to connect - update UI? + break; + case MultiplexBaseTransport.STATE_LISTEN: + if(service.transport != null){ + service.transport.stop(); + service.transport = null; + } + break; + case MultiplexBaseTransport.STATE_NONE: + // We've just lost the connection + if(service.transport != null){ + service.transportListener.onTransportDisconnected("TCP transport disconnected", service.transport.transportRecord, null); + }else{ + service.transportListener.onTransportDisconnected("TCP transport disconnected", null, null); + + } + break; + case MultiplexBaseTransport.STATE_ERROR: + Log.d(TAG, "TCP transport encountered an error"); + service.transportListener.onError("TCP transport encountered an error" ); + break; + } + break; + + case SdlRouterService.MESSAGE_READ: + service.transportListener.onPacketReceived((SdlPacket) msg.obj); + break; + } + } + } +} diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java index 0ab335bf9..10cb518d4 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/TransportBroker.java @@ -55,6 +55,7 @@ import com.smartdevicelink.transport.enums.TransportType; import com.smartdevicelink.transport.utl.ByteAraryMessageAssembler; import com.smartdevicelink.transport.utl.ByteArrayMessageSpliter; import com.smartdevicelink.transport.utl.TransportRecord; +import com.smartdevicelink.util.DebugTool; import java.lang.ref.WeakReference; import java.text.SimpleDateFormat; @@ -119,7 +120,6 @@ public class TransportBroker { Log.d(TAG, "Unbound from service " + className.getClassName()); routerServiceMessenger = null; registeredWithRouterService = false; - unBindFromRouterService(); isBound = false; onHardwareDisconnected(null, null); } @@ -158,6 +158,7 @@ public class TransportBroker { Log.d(TAG, "Dead object while attempting to send packet"); routerServiceMessenger = null; registeredWithRouterService = false; + unBindFromRouterService(); isBound = false; onHardwareDisconnected(null, null); return false; @@ -166,6 +167,7 @@ public class TransportBroker { Log.d(TAG, "Null messenger while attempting to send packet"); // NPE, routerServiceMessenger is null routerServiceMessenger = null; registeredWithRouterService = false; + unBindFromRouterService(); isBound = false; onHardwareDisconnected(null, null); return false; @@ -448,7 +450,7 @@ public class TransportBroker { * This method will end our communication with the router service. */ public void stop() { - //Log.d(TAG, "STOPPING transport broker for " + whereToReply); + DebugTool.logInfo("Stopping transport broker for " + whereToReply); synchronized (INIT_LOCK) { unregisterWithRouterService(); unBindFromRouterService(); @@ -461,15 +463,13 @@ public class TransportBroker { private synchronized void unBindFromRouterService() { try { - if (isBound && getContext() != null && routerConnection != null) { - getContext().unbindService(routerConnection); - isBound = false; - } else { - Log.w(TAG, "Unable to unbind from router service. bound? " + isBound + " context? " + (getContext()!=null) + " router connection?" + (routerConnection != null)); - } + getContext().unbindService(routerConnection); - } catch (IllegalArgumentException e) { + } catch (Exception e) { //This is ok + Log.w(TAG, "Unable to unbind from router service. bound? " + isBound + " context? " + (getContext()!=null) + " router connection?" + (routerConnection != null)); + }finally { + isBound = false; } } diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java b/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java index 6e7fd7c75..d33f4c374 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java @@ -72,6 +72,10 @@ public class WiFiSocketFactory { @TargetApi(Build.VERSION_CODES.LOLLIPOP) private static Socket createWiFiSocket(Context context) { + if(context == null){ + logInfo("Context supplied was null"); + return null; + } PackageManager pm = context.getPackageManager(); if (pm == null) { logInfo("PackageManager isn't available."); |