diff options
Diffstat (limited to 'android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java')
-rw-r--r-- | android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java | 169 |
1 files changed, 167 insertions, 2 deletions
diff --git a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java index 9109dc3ad..1f4ba2de0 100644 --- a/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java +++ b/android/sdl_android/src/main/java/com/smartdevicelink/util/AndroidTools.java @@ -36,18 +36,28 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.BatteryManager; +import android.os.Bundle; +import androidx.annotation.Nullable; +import com.smartdevicelink.marshal.JsonRPCMarshaller; +import com.smartdevicelink.proxy.rpc.VehicleType; import com.smartdevicelink.transport.TransportConstants; +import org.json.JSONException; +import org.json.JSONObject; + import java.io.BufferedInputStream; import java.io.IOException; import java.net.URL; @@ -56,9 +66,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.Hashtable; import java.util.List; + public class AndroidTools { + + private static final String TAG = "AndroidTools"; + private static final String SDL_DEVICE_VEHICLES_PREFS = "sdl.device.vehicles"; + private static final Object VEHICLE_PREF_LOCK = new Object(); + /** * Check to see if a component is exported * @@ -97,7 +114,6 @@ public class AndroidTools { return sdlMultiList; } - /** * Finds all SDL apps via their SdlRouterService manifest entry. It will return the metadata associated with that router service. * @@ -105,6 +121,7 @@ public class AndroidTools { * @param comparator the Comparator to sort the resulting list. If null is supplied, they will be returned as they are from the system * @return the sorted list of SdlAppInfo objects that represent SDL apps */ + @Deprecated public static List<SdlAppInfo> querySdlAppInfo(Context context, Comparator<SdlAppInfo> comparator) { List<SdlAppInfo> sdlAppInfoList = new ArrayList<>(); Intent intent = new Intent(TransportConstants.ROUTER_SERVICE_ACTION); @@ -118,7 +135,7 @@ public class AndroidTools { PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfo(info.serviceInfo.packageName, 0); - sdlAppInfoList.add(new SdlAppInfo(info, packageInfo)); + sdlAppInfoList.add(new SdlAppInfo(info, packageInfo, context)); } catch (NameNotFoundException e) { //Package was not found, likely a sign the resolve info can't be trusted. } @@ -134,6 +151,54 @@ public class AndroidTools { return sdlAppInfoList; } + /** + * Finds all SDL apps via their SdlRouterService manifest entry. It will return the metadata associated with that router service. + * + * @param context a context instance to obtain the package manager + * @param comparator the Comparator to sort the resulting list. If null is supplied, they will be returned as they are from the system + * @return the sorted list of SdlAppInfo objects that represent SDL apps + */ + public static List<SdlAppInfo> querySdlAppInfo(Context context, Comparator<SdlAppInfo> comparator, VehicleType type) { + List<SdlAppInfo> sdlAppInfoList = new ArrayList<>(); + Intent intent = new Intent(TransportConstants.ROUTER_SERVICE_ACTION); + List<ResolveInfo> resolveInfoList = context.getPackageManager().queryIntentServices(intent, PackageManager.GET_META_DATA); + + if (resolveInfoList != null && resolveInfoList.size() > 0) { + PackageManager packageManager = context.getPackageManager(); + if (packageManager != null) { + + for (ResolveInfo info : resolveInfoList) { + PackageInfo packageInfo; + try { + packageInfo = packageManager.getPackageInfo(info.serviceInfo.packageName, 0); + SdlAppInfo appInformation = new SdlAppInfo(info, packageInfo, context); + sdlAppInfoList.add(appInformation); + + } catch (NameNotFoundException e) { + //Package was not found, likely a sign the resolve info can't be trusted. + } + + } + } + + List<SdlAppInfo> sdlAppInfoListVehicleType = new ArrayList<>(); + + for (SdlAppInfo appInformation : sdlAppInfoList) { + if (appInformation.routerServiceVersion < 15) { + sdlAppInfoListVehicleType.add(appInformation); + } else if (SdlAppInfo.checkIfVehicleSupported(appInformation.supportedVehicles, type)) { + sdlAppInfoListVehicleType.add(appInformation); + } + } + sdlAppInfoList = sdlAppInfoListVehicleType; + + if (comparator != null) { + Collections.sort(sdlAppInfoList, comparator); + } + } + return sdlAppInfoList; + } + /** * Sends the provided intent to the specified destinations making it an explicit intent, rather @@ -204,4 +269,104 @@ public class AndroidTools { } return false; } + + /** + * Saves the mac address along with vehicle details into user's shared prefs. + * + * @param context a context instance to obtain the shared preferences. + * @param vehicleType a RPCStruct that describes the type of vehicle the mobile phone is connected with. + * @param address a string containing the Bluetooth Mac address of the connected vehicle. + */ + public static void saveVehicleType(Context context, VehicleType vehicleType, String address) { + synchronized (VEHICLE_PREF_LOCK) { + if (vehicleType == null || address == null || context == null) { + DebugTool.logWarning(TAG, String.format("Unable to save vehicle type. Context is %1$s, Address is %2$s and VehicleType is %3$s", context, address, vehicleType)); + return; + } + try { + SharedPreferences preferences = context.getSharedPreferences(SDL_DEVICE_VEHICLES_PREFS, Context.MODE_PRIVATE); + + String jsonString = vehicleType.serializeJSON().toString(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(address, jsonString); + editor.commit(); + } catch (JSONException e) { + DebugTool.logError(TAG, "Unable to serialize vehicle type to JSON.", e); + } + } + } + + /** + * Retrieves the vehicle details by the mac address of the connected vehicle. + * + * @param context a context instance to obtain the shared preferences. + * @param address a string containing the Bluetooth Mac address of the connected vehicle. + * @return The Hashtable to be used to construct VehicleTyp + */ + public static @Nullable Hashtable<String, Object> getVehicleTypeFromPrefs(Context context, String address) { + synchronized (VEHICLE_PREF_LOCK) { + if (context == null || address == null) { + DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from prefs. Context is %1$s and Address is %2$s", context, address)); + return null; + } + try { + SharedPreferences preferences = context.getSharedPreferences(SDL_DEVICE_VEHICLES_PREFS, Context.MODE_PRIVATE); + String storedVehicleTypeSerialized = preferences.getString(address, null); + + if (storedVehicleTypeSerialized == null) { + return null; + } else { + JSONObject object = new JSONObject(storedVehicleTypeSerialized); + return JsonRPCMarshaller.deserializeJSONObject(object); + } + } catch (JSONException e) { + DebugTool.logError(TAG, "Unable to deserialize stored vehicle type.", e); + return null; + } + } + } + + /** + * Retrieves the list of vehicle types that are set in the manifest. + * + * @param context a context to access Android system services through. + * @param component a component name of a LocalRouterService. + * @param manifestFieldId a string resources id that indicates an unique name for the vehicle data in the manifest. + * @return The list of vehicle types, or null if an error occurred or field was not found. + */ + public static @Nullable List<VehicleType> getVehicleTypesFromManifest(Context context, ComponentName component, int manifestFieldId) { + if (context == null || component == null) { + DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from manifest. Context is %1$s and Component is %2$s", context, component)); + return null; + } + try { + PackageManager pm = context.getPackageManager(); + Resources resources = context.getResources(); + if (pm == null || resources == null) { + DebugTool.logWarning(TAG, String.format("Unable to get vehicle type from manifest. PackageManager is %1$s and Resources is %2$s", pm, resources)); + return null; + } + + Bundle metaData = pm.getServiceInfo(component, PackageManager.GET_META_DATA).metaData; + if (metaData == null) { + DebugTool.logError(TAG, "metaData isn't available."); + return null; + } + + int xmlFieldId = metaData.getInt(resources.getString(manifestFieldId)); + if (xmlFieldId == 0) { + DebugTool.logError(TAG, "Field with id " + manifestFieldId + " was not found in manifest"); + return null; + } + + XmlResourceParser parser = resources.getXml(xmlFieldId); + return SdlAppInfo.deserializeSupportedVehicles(parser); + } catch (PackageManager.NameNotFoundException e) { + DebugTool.logError(TAG, "Failed to get OEM vehicle data filter: " + e.getMessage()+ " - assume vehicle data is supported"); + return null; + } catch (Resources.NotFoundException ex) { + DebugTool.logError(TAG, "Failed to find resource: " + ex.getMessage()+ " - assume vehicle data is supported"); + return null; + } + } } |