Java tutorial
/* * Copyright 2016 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.physical_web.physicalweb; import org.physical_web.collection.PhysicalWebCollection; import org.physical_web.collection.PwPair; import org.physical_web.collection.PwsClient; import org.physical_web.collection.PwsResult; import org.physical_web.collection.UrlDevice; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; import android.view.Menu; import android.widget.Toast; import org.uribeacon.scan.util.RangingUtils; import org.uribeacon.scan.util.RegionResolver; import org.json.JSONException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; /** * This class is for various static utilities, largely for manipulation of data structures provided * by the collections library. */ class Utils { public static final String PROD_ENDPOINT = "https://url-caster.appspot.com"; public static final int PROD_ENDPOINT_VERSION = 1; public static final String DEV_ENDPOINT = "https://url-caster-dev.appspot.com"; public static final int DEV_ENDPOINT_VERSION = 1; public static final String GOOGLE_ENDPOINT = "https://physicalweb.googleapis.com"; public static final int GOOGLE_ENDPOINT_VERSION = 2; public static final String FAVORITES_KEY = "favorites"; public static final String BLE_DEVICE_TYPE = "ble"; public static final String FAT_BEACON_DEVICE_TYPE = "fat-beacon"; public static final String MDNS_LOCAL_DEVICE_TYPE = "mdns-local"; public static final String MDNS_PUBLIC_DEVICE_TYPE = "mdns-public"; public static final String WIFI_DIRECT_DEVICE_TYPE = "wifidirect"; public static final String SSDP_DEVICE_TYPE = "ssdp"; private static final String USER_OPTED_IN_KEY = "userOptedIn"; private static final String MAIN_PREFS_KEY = "physical_web_preferences"; private static final String DISCOVERY_SERVICE_PREFS_KEY = "org.physical_web.physicalweb.DISCOVERY_SERVICE_PREFS"; private static final String SCANTIME_KEY = "scantime"; private static final String TYPE_KEY = "type"; private static final String PUBLIC_KEY = "public"; private static final String TITLE_KEY = "title"; private static final String DESCRIPTION_KEY = "description"; private static final String RSSI_KEY = "rssi"; private static final String TXPOWER_KEY = "tx"; private static final String PWSTRIPTIME_KEY = "pwstriptime"; private static final String WIFIDIRECT_KEY = "wifidirect"; private static final String WIFIDIRECT_PORT_KEY = "wifiport"; private static final RegionResolver REGION_RESOLVER = new RegionResolver(); private static final String SEPARATOR = "\0"; private static Set<String> mFavoriteUrls = new HashSet<>(); private static Set<String> mBlockedUrls = new HashSet<>(); private static final int GZIP_SIGNATURE_LENGTH = 2; // Compares PwPairs by first considering if it has been favorited // and then considering distance public static class PwPairRelevanceComparator implements Comparator<PwPair> { private Set<String> mFavorites = mFavoriteUrls; public Map<String, Double> mCachedDistances; PwPairRelevanceComparator() { mCachedDistances = new HashMap<>(); } public double getDistance(UrlDevice urlDevice) { if (mCachedDistances.containsKey(urlDevice.getId())) { return mCachedDistances.get(urlDevice.getId()); } double distance = Utils.getDistance(urlDevice); mCachedDistances.put(urlDevice.getId(), distance); return distance; } @Override public int compare(PwPair lhs, PwPair rhs) { String lSite = lhs.getPwsResult().getSiteUrl(); String rSite = rhs.getPwsResult().getSiteUrl(); if (mFavorites.contains(lSite) == mFavorites.contains(rSite)) { return Double.compare(getDistance(lhs.getUrlDevice()), getDistance(rhs.getUrlDevice())); } else { if (mFavorites.contains(lSite)) { return -1; } return 1; } } } /** * Surface a notification to the user that the Physical Web is broadcasting. The notification * specifies the transport or URL that is being broadcast and cannot be swiped away. * @param context * @param stopServiceReceiver * @param broadcastNotificationId * @param title * @param text * @param filter */ public static void createBroadcastNotification(Context context, BroadcastReceiver stopServiceReceiver, int broadcastNotificationId, CharSequence title, CharSequence text, String filter) { Intent resultIntent = new Intent(); TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); stackBuilder.addParentStack(MainActivity.class); stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); context.registerReceiver(stopServiceReceiver, new IntentFilter(filter)); PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, new Intent(filter), PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.ic_leak_add_white_24dp).setContentTitle(title).setContentText(text) .setOngoing(true).addAction(android.R.drawable.ic_menu_close_clear_cancel, context.getString(R.string.stop), pIntent); builder.setContentIntent(resultPendingIntent); NotificationManager notificationManager = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(broadcastNotificationId, builder.build()); } /** * Reads the data from the inputStream. * @param inputStream The input to read from. * @return The entire input stream as a byte array * @throws IOException */ public static byte[] getBytes(InputStream inputStream) throws IOException { ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int len; while ((len = inputStream.read(buffer)) != -1) { byteBuffer.write(buffer, 0, len); } return byteBuffer.toByteArray(); } /** * Get set of Blocked hosts. */ public static Set<String> getBlockedHosts() { return mBlockedUrls; } /** * Hides all items in the given menu. * @param menu The menu to hide items for. */ public static void hideAllMenuItems(Menu menu) { menu.findItem(R.id.action_about).setVisible(false); menu.findItem(R.id.action_settings).setVisible(false); menu.findItem(R.id.block_settings).setVisible(false); menu.findItem(R.id.action_demos).setVisible(false); } /** * Check if URL has been favorited. * @param siteUrl */ public static boolean isFavorite(String siteUrl) { return mFavoriteUrls.contains(siteUrl); } /** * Toggles favorite status. * @param siteUrl */ public static void toggleFavorite(String siteUrl) { if (isFavorite(siteUrl)) { mFavoriteUrls.remove(siteUrl); return; } mFavoriteUrls.add(siteUrl); } /** * Save favorites to shared preferences. * @param context To get shared preferences. */ public static void saveFavorites(Context context) { // Write the PW Collection PreferenceManager.getDefaultSharedPreferences(context).edit().putStringSet(FAVORITES_KEY, mFavoriteUrls) .apply(); } /** * Get favorites from shared preferences. * @param context To get shared preferences. */ public static void restoreFavorites(Context context) { mFavoriteUrls = new HashSet<>(PreferenceManager.getDefaultSharedPreferences(context) .getStringSet(FAVORITES_KEY, new HashSet<String>())); } /** * Check if any PwPair in the list is favorited. * @param pairs List of pwPairs */ public static boolean containsFavorite(List<PwPair> pairs) { for (PwPair pair : pairs) { if (isFavorite(pair.getPwsResult().getSiteUrl())) { return true; } } return false; } /** * Check if domain of URL has been blocked. * @param siteUrl * @return is siteURL blocked */ public static boolean isBlocked(PwPair pwPair) { if (Utils.isWifiDirectDevice(pwPair.getUrlDevice())) { return mBlockedUrls.contains(Utils.getWifiAddress(pwPair.getUrlDevice())); } try { return mBlockedUrls.contains(new URI(pwPair.getPwsResult().getSiteUrl()).getHost()); } catch (URISyntaxException e) { return false; } } /** * Block the host of siteUrl. * @param siteUrl */ public static void addBlocked(PwPair pwPair) { if (Utils.isWifiDirectDevice(pwPair.getUrlDevice())) { mBlockedUrls.add(Utils.getWifiAddress(pwPair.getUrlDevice())); return; } try { mBlockedUrls.add(new URI(pwPair.getPwsResult().getSiteUrl()).getHost()); } catch (URISyntaxException e) { return; } } /** * Unblock the host. * @param host */ public static void removeBlocked(String host) { if (mBlockedUrls.contains(host)) { mBlockedUrls.remove(host); } } /** * Save blocked set to shared preferences. * @param context to access shared preferences */ public static void saveBlocked(Context context) { // Write the PW Collection PreferenceManager.getDefaultSharedPreferences(context).edit().putStringSet("blocked", mBlockedUrls).apply(); } /** * Restore blocked set from shared preferences. * @param context to access shared preferences */ public static void restoreBlocked(Context context) { mBlockedUrls = new HashSet<>(PreferenceManager.getDefaultSharedPreferences(context).getStringSet("blocked", new HashSet<String>())); } public static class WifiDirectInfo { public String title; public int port; public WifiDirectInfo(String title, int port) { this.title = title; this.port = port; } } /** * Checks to see if name matches defined wifi direct structure. * @param name WifiDirect device name */ public static WifiDirectInfo parseWifiDirectName(String name) { String split[] = name.split("-"); if (split.length < 3 || !split[0].equals("PW") || !split[split.length - 1].matches("\\d+")) { return null; } return new WifiDirectInfo(name.substring(3, name.lastIndexOf('-')), Integer.parseInt(split[split.length - 1])); } private static class PwsEndpoint { public String url; public int apiVersion; public String apiKey; public boolean neededApiKey; public PwsEndpoint(String url, int apiVersion, String apiKey) { this.url = url; this.apiVersion = apiVersion; this.apiKey = apiKey; this.neededApiKey = needApiKey(); if (this.neededApiKey) { this.url = PROD_ENDPOINT; this.apiVersion = PROD_ENDPOINT_VERSION; } } private boolean needApiKey() { return apiVersion >= 2 && apiKey.isEmpty(); } } private static void throwEncodeException(JSONException e) { throw new RuntimeException("Could not encode JSON", e); } private static void deletePreference(Context context, String preferenceName) { context.getSharedPreferences(preferenceName, Context.MODE_PRIVATE).edit().clear().apply(); } private static int getGoogleApiKeyResourceId(Context context) { return context.getResources().getIdentifier("google_api_key", "string", context.getPackageName()); } private static PwsEndpoint getCurrentPwsEndpoint(Context context) { return new PwsEndpoint(getCurrentPwsEndpointUrl(context), getCurrentPwsEndpointVersion(context), getCurrentPwsEndpointApiKey(context)); } private static String getCurrentPwsEndpointString(Context context) { String defaultEndpoint = getDefaultPwsEndpointPreferenceString(context); return PreferenceManager.getDefaultSharedPreferences(context) .getString(context.getString(R.string.pws_endpoint_setting_key), defaultEndpoint); } private static String getCurrentPwsEndpointUrl(Context context) { String endpoint = getCurrentPwsEndpointString(context); return endpoint.split(SEPARATOR)[0]; } private static int getCurrentPwsEndpointVersion(Context context) { String endpoint = getCurrentPwsEndpointString(context); return Integer.parseInt(endpoint.split(SEPARATOR)[1]); } private static String getCurrentPwsEndpointApiKey(Context context) { String endpoint = getCurrentPwsEndpointString(context); if (endpoint.endsWith(SEPARATOR) || endpoint.endsWith("null")) { return ""; } return endpoint.split(SEPARATOR)[2]; } private static String readCustomPwsEndpointUrl(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getString(context.getString(R.string.custom_pws_url_key), ""); } private static int readCustomPwsEndpointVersion(Context context) { return Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(context).getString( context.getString(R.string.custom_pws_version_key), context.getString(R.string.custom_pws_version_default))); } private static String readCustomPwsEndpointApiKey(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getString(context.getString(R.string.custom_pws_api_key_key), ""); } /** * Gets whether the user has optedIn from SharedPreferences. * @param context The context for the SharedPreferences. * @return True if the user has optedIn otherwise false. */ public static boolean checkIfUserHasOptedIn(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(USER_OPTED_IN_KEY, false); } public abstract static class UrlDeviceDiscoveryServiceConnection implements ServiceConnection { private Context mContext; @Override public void onServiceConnected(ComponentName className, IBinder service) { // Forward the service to the implementing class serviceHandler((UrlDeviceDiscoveryService.LocalBinder) service); mContext.unbindService(this); } @Override public void onServiceDisconnected(ComponentName className) { } public void connect(Context context) { mContext = context; Intent intent = new Intent(mContext, UrlDeviceDiscoveryService.class); mContext.startService(intent); mContext.bindService(intent, this, Context.BIND_AUTO_CREATE); } public abstract void serviceHandler(UrlDeviceDiscoveryService.LocalBinder localBinder); } /** * Delete the cached results from the UrlDeviceDisoveryService. * @param context The context for the service. */ public static void deleteCache(Context context) { new UrlDeviceDiscoveryServiceConnection() { @Override public void serviceHandler(UrlDeviceDiscoveryService.LocalBinder localBinder) { localBinder.getServiceInstance().clearCache(); } }.connect(context); } /** * Starts scanning with UrlDeviceDisoveryService. * @param context The context for the service. */ public static void startScan(Context context) { new UrlDeviceDiscoveryServiceConnection() { @Override public void serviceHandler(UrlDeviceDiscoveryService.LocalBinder localBinder) { localBinder.getServiceInstance().restartScan(); } }.connect(context); } /** * Format the endpoint URL, version, and API key. * @param pwsUrl The URL of the Physical Web Service. * @param pwsVersion The API version the PWS is running. * @param apiKey The API key for the PWS. * @return The PWS endpoint formatted for saving to SharedPreferences. */ public static String formatEndpointForSharedPrefernces(String pwsUrl, int pwsVersion, String apiKey) { pwsUrl = pwsUrl == null ? "" : pwsUrl; apiKey = apiKey == null ? "" : apiKey; return pwsUrl + SEPARATOR + pwsVersion + SEPARATOR + apiKey; } /** * Get the default PWS Endpoint formatted for SharedPreferences. * @param context The context for the SharedPreferences. * @return The default PWS endpoint formatted for saving to SharedPreferences. */ public static String getDefaultPwsEndpointPreferenceString(Context context) { if (isGoogleApiKeyAvailable(context)) { return formatEndpointForSharedPrefernces(GOOGLE_ENDPOINT, GOOGLE_ENDPOINT_VERSION, getGoogleApiKey(context)); } return formatEndpointForSharedPrefernces(PROD_ENDPOINT, PROD_ENDPOINT_VERSION, ""); } /** * Saves the optIn preference in the default shared preferences file. * @param context The context for the SharedPreferences. */ public static void setOptInPreference(Context context) { PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(USER_OPTED_IN_KEY, true).apply(); } /** * Saves the endpoint to SharedPreferences. * @param context The context for the SharedPreferences. * @param endpoint The endpoint formatted for SharedPreferences. */ public static void setPwsEndpointPreference(Context context, String endpoint) { PreferenceManager.getDefaultSharedPreferences(context).edit() .putString(context.getString(R.string.pws_endpoint_setting_key), endpoint).apply(); } /** * Saves the default settings to the SharedPreferences. * @param context The context for the SharedPreferences. */ public static void setSharedPreferencesDefaultValues(Context context) { PreferenceManager.setDefaultValues(context, R.xml.settings, false); setPwsEndpointPreference(context, getCurrentPwsEndpointString(context)); if (context.getSharedPreferences(MAIN_PREFS_KEY, Context.MODE_PRIVATE).getBoolean(USER_OPTED_IN_KEY, false)) { setOptInPreference(context); deletePreference(context, MAIN_PREFS_KEY); deletePreference(context, DISCOVERY_SERVICE_PREFS_KEY); } } /** * Sets the client's endpoint to the currently selected endpoint. * @param context The context for the SharedPreferences. * @param pwsClient The client used for requests to the Physical Web Service. * @return If the endpoint was successfully set to current endpoint or if it had to be reverted. * to the default endpoint. */ public static boolean setPwsEndpoint(Context context, PwsClient pwsClient) { PwsEndpoint endpoint = getCurrentPwsEndpoint(context); pwsClient.setEndpoint(endpoint.url, endpoint.apiVersion, endpoint.apiKey); return !endpoint.neededApiKey; } /** * Sets the client's endpoint to the currently selected endpoint. * @param context The context for the SharedPreferences. * @param physicalWebCollection The client used for requests to the Physical Web Service. * @return If the endpoint was successfully set to current endpoint or if it had to be reverted. * to the default endpoint. */ public static boolean setPwsEndpoint(Context context, PhysicalWebCollection physicalWebCollection) { PwsEndpoint endpoint = getCurrentPwsEndpoint(context); physicalWebCollection.setPwsEndpoint(endpoint.url, endpoint.apiVersion, endpoint.apiKey); return !endpoint.neededApiKey; } /** * Sets the client's endpoint to the Google endpoint. * @param context The context for the SharedPreferences. * @param pwsClient The client used for requests to the Physical Web Service. */ public static void setPwsEndPointToGoogle(Context context, PwsClient pwsClient) { pwsClient.setEndpoint(GOOGLE_ENDPOINT, GOOGLE_ENDPOINT_VERSION, getGoogleApiKey(context)); } /** * Checks if the currently selected PWS has a valid format, not that it exists. * @param context The context for the SharedPreferences. * @return If the current PWS configured properly. */ public static boolean isCurrentPwsSelectionValid(Context context) { String endpoint = getCurrentPwsEndpointUrl(context); int apiVersion = getCurrentPwsEndpointVersion(context); String apiKey = getCurrentPwsEndpointApiKey(context); return !endpoint.isEmpty() && !(apiVersion >= 2 && apiKey.isEmpty()); } /** * Checks if the Google API key resource exists. * @param context The context for the resources. * @return If the Google API key is available. */ public static boolean isGoogleApiKeyAvailable(Context context) { return getGoogleApiKeyResourceId(context) != 0; } /** * Get the Google API key if available. * @param context The context for the resources. * @return The API key for the Google PWS if available or an empty string. */ public static String getGoogleApiKey(Context context) { int resourceId = getGoogleApiKeyResourceId(context); return resourceId != 0 ? context.getString(resourceId) : ""; } /** * Gets the saved settings for the custom PWS. * @param context The context for the SharedPreferences. * @return The custom PWS endpoint formatted for SharedPrefences. */ public static String getCustomPwsEndpoint(Context context) { return formatEndpointForSharedPrefernces(readCustomPwsEndpointUrl(context), readCustomPwsEndpointVersion(context), readCustomPwsEndpointApiKey(context)); } /** * Get the saved setting for enabling Fatbeacon. * @param context The context for the SharedPreferences. * @return The enable Fatbeacon setting. */ public static boolean isFatBeaconEnabled(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.fatbeacon_key), false); } /** * Get the saved setting for enabling mDNS folder. * @param context The context for the SharedPreferences. * @return The enable mDNS folder setting. */ public static boolean isMdnsEnabled(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.mDNS_key), false); } /** * Get the saved setting for enabling Wifi direct. * @param context The context for the SharedPreferences. * @return The enable wifi direct setting. */ public static boolean isWifiDirectEnabled(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.wifi_direct_key), false); } /** * Get the saved setting for debug View. * @param context The context for the SharedPreferences. * @return The debug view setting. */ public static boolean isDebugViewEnabled(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.debug_key), false); } /** * Get the saved setting for enabling mDNS folder. * @param context The context for the SharedPreferences. * @return The enable mDNS folder setting. */ public static int getWifiDirectPort(Context context) { String port = PreferenceManager.getDefaultSharedPreferences(context) .getString(context.getString(R.string.wifi_port_key), "1234"); if (port.matches("\\d+")) { return Integer.parseInt(port); } return 1234; } /** * Toast the user to indicate the API key is missing. * @param context The context for the resources. */ public static void warnUserOnMissingApiKey(Context context) { Toast.makeText(context, R.string.error_api_key_no_longer_available, Toast.LENGTH_SHORT).show(); } /** * Create an intent for opening a URL. * @param pwsResult The result that has the URL the user clicked on. * @return The intent that opens the URL. */ public static Intent createNavigateToUrlIntent(PwsResult pwsResult) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(pwsResult.getSiteUrl())); return intent; } /** * Setup an intent to open the URL. * @param pwsResult The result that has the URL the user clicked on. * @param context The context for the activity. * @return The intent that opens the URL. */ public static PendingIntent createNavigateToUrlPendingIntent(PwsResult pwsResult, Context context) { Intent intent = createNavigateToUrlIntent(pwsResult); int requestID = (int) System.currentTimeMillis(); return PendingIntent.getActivity(context, requestID, intent, 0); } /** * Gets the top ranked PwPair with the given groupId. * @param pwCollection The collection of PwPairs. * @param groupId The group id of the requested PwPair. * @return The top ranked PwPair with a given group id if it exist. */ public static PwPair getTopRankedPwPairByGroupId(PhysicalWebCollection pwCollection, String groupId) { // This does the same thing as the PhysicalWebCollection method, only it uses our custom // getGroupId method. for (PwPair pwPair : pwCollection.getGroupedPwPairsSortedByRank(new PwPairRelevanceComparator())) { if (getGroupId(pwPair.getPwsResult()).equals(groupId)) { return pwPair; } } return null; } /** * Decode the downloaded icon to a Bitmap. * @param pwCollection The collection where the icon is stored. * @param pwsResult The result the icon is for. * @return The icon as a Bitmap. */ public static Bitmap getBitmapIcon(PhysicalWebCollection pwCollection, PwsResult pwsResult) { byte[] iconBytes = pwCollection.getIcon(pwsResult.getIconUrl()); if (iconBytes == null) { return null; } return BitmapFactory.decodeByteArray(iconBytes, 0, iconBytes.length); } /** * Get the scan time for a device if available. * @param urlDevice The device to get the scan time for. * @return The scan time in millisecond for the device. * @throws RuntimeException If the device doesn't have a scan time. */ public static long getScanTimeMillis(UrlDevice urlDevice) { try { return urlDevice.getExtraLong(SCANTIME_KEY); } catch (JSONException e) { throw new RuntimeException("Scan time not available in device " + urlDevice.getId(), e); } } /** * Checks if device is public. * @param urlDevice The device that is getting checked. * @return If the device is public or not. */ public static boolean isPublic(UrlDevice urlDevice) { return urlDevice.optExtraBoolean(PUBLIC_KEY, true); } /** * Checks if device is PWS resolvable. * @param urlDevice The device that is getting checked. * @return If the device is resolvable or not. */ public static boolean isResolvableDevice(UrlDevice urlDevice) { String type = urlDevice.optExtraString(TYPE_KEY, ""); return type.equals(BLE_DEVICE_TYPE) || type.equals(SSDP_DEVICE_TYPE) || type.equals(MDNS_PUBLIC_DEVICE_TYPE); } /** * Checks if device is Bluetooth Low Energy. * @param urlDevice The device that is getting checked. * @return If the device is BLE or not. */ public static boolean isBleUrlDevice(UrlDevice urlDevice) { return urlDevice.optExtraString(TYPE_KEY, "").equals(BLE_DEVICE_TYPE); } /** * Gets if the device is a FatBeacon. * @param urlDevice The device that is getting checked. * @return Is a FatBeacon device */ public static boolean isFatBeaconDevice(UrlDevice urlDevice) { return urlDevice.optExtraString(TYPE_KEY, "").equals(FAT_BEACON_DEVICE_TYPE); } /** * Checks if device is mdns device broadcasting public url. * @param urlDevice The device that is getting checked. * @return If the device is mdns public or not. */ public static boolean isMDNSPublicDevice(UrlDevice urlDevice) { return urlDevice.optExtraString(TYPE_KEY, "").equals(MDNS_PUBLIC_DEVICE_TYPE); } /** * Checks if device is Local. * @param urlDevice The device that is getting checked. * @return If the device is local or not. */ public static boolean isMDNSLocalDevice(UrlDevice urlDevice) { return urlDevice.optExtraString(TYPE_KEY, "").equals(MDNS_LOCAL_DEVICE_TYPE); } /** * Gets if the device is Wifi Direct. * @param urlDevice The device that is getting checked. * @return Is a WifiDirect device */ public static boolean isWifiDirectDevice(UrlDevice urlDevice) { return urlDevice.optExtraString(TYPE_KEY, "").equals(WIFI_DIRECT_DEVICE_TYPE); } /** * Gets if the device is SSDP. * @param urlDevice The device that is getting checked. * @return Is a SSDP device */ public static boolean isSSDPDevice(UrlDevice urlDevice) { return urlDevice.optExtraString(TYPE_KEY, "").equals(SSDP_DEVICE_TYPE); } /** * Gets the device RSSI if it is Bluetooth Low Energy. * @param urlDevice The device that is getting checked. * @return The RSSI for the device. * @throws RuntimeException If the device is not BLE. */ public static int getRssi(UrlDevice urlDevice) { try { return urlDevice.getExtraInt(RSSI_KEY); } catch (JSONException e) { throw new RuntimeException("Tried to get RSSI from non-ble device " + urlDevice.getId(), e); } } /** * Gets the device TX power if it is Bluetooth Low Energy. * @param urlDevice The device that is getting checked. * @return The TX power for the device. * @throws RuntimeException If the device is not BLE. */ public static int getTxPower(UrlDevice urlDevice) { try { return urlDevice.getExtraInt(TXPOWER_KEY); } catch (JSONException e) { throw new RuntimeException("Tried to get TX power from non-ble device " + urlDevice.getId(), e); } } /** * Gets the UrlDevice Title. * @param urlDevice The device that is getting checked. * @return The Title for the device. * @throws RuntimeException if no title present. */ public static String getTitle(UrlDevice urlDevice) { try { return urlDevice.getExtraString(TITLE_KEY); } catch (JSONException e) { throw new RuntimeException("Tried to get Title when no title set " + urlDevice.getId(), e); } } /** * Gets the UrlDevice Description. * @param urlDevice The device that is getting checked. * @return The Description for the device. * @throws RuntimeException if no description present. */ public static String getDescription(UrlDevice urlDevice) { try { return urlDevice.getExtraString(DESCRIPTION_KEY); } catch (JSONException e) { throw new RuntimeException("Tried to get Description when no description set " + urlDevice.getId(), e); } } /** * Gets the UrlDevice MAC address. * @param urlDevice The device that is getting checked. * @return The MAC address for the device. * @throws RuntimeException if no address present. */ public static String getWifiAddress(UrlDevice urlDevice) { try { return urlDevice.getExtraString(WIFIDIRECT_KEY); } catch (JSONException e) { throw new RuntimeException("Tried to get address when no description set " + urlDevice.getId(), e); } } /** * Gets the UrlDevice port. * @param urlDevice The device that is getting checked. * @return The port for the device. * @throws RuntimeException if no port present. */ public static int getWifiPort(UrlDevice urlDevice) { try { return urlDevice.getExtraInt(WIFIDIRECT_PORT_KEY); } catch (JSONException e) { throw new RuntimeException("Tried to get port when no port set " + urlDevice.getId(), e); } } /** * Gets the amount of time in milliseconds to get the result from the PWS if available. * @param pwsResult The result that is being queried. * @return The trip time for the result. * @throws RuntimeException If the trip time is not recorded. */ public static long getPwsTripTimeMillis(PwsResult pwsResult) { try { return pwsResult.getExtraLong(PWSTRIPTIME_KEY); } catch (JSONException e) { throw new RuntimeException("PWS trip time not recorded in PwsResult"); } } /** * Gets the groupId for the result. * @param pwsResult The result that is being queried. * @return The groupId for the result. */ public static String getGroupId(PwsResult pwsResult) { // The PWS does not always give us a group id yet. if (pwsResult.getGroupId() == null || pwsResult.getGroupId().equals("")) { try { return new URI(pwsResult.getSiteUrl()).getHost() + pwsResult.getTitle(); } catch (URISyntaxException e) { return pwsResult.getSiteUrl(); } } return pwsResult.getGroupId(); } /** * Updates the region resolver with the device. * @param urlDevice The device to update region with. */ public static void updateRegion(UrlDevice urlDevice) { REGION_RESOLVER.onUpdate(urlDevice.getId(), getRssi(urlDevice), getTxPower(urlDevice)); } /** * Gets the smoothed RSSI for device from the region resolver. * @param urlDevice The device being queried. * @return The smoothed RSSI for the device. */ public static double getSmoothedRssi(UrlDevice urlDevice) { return REGION_RESOLVER.getSmoothedRssi(urlDevice.getId()); } /** * Gets the distance for device from the region resolver. * @param urlDevice The device being queried. * @return The distance for the device. */ public static double getDistance(UrlDevice urlDevice) { return REGION_RESOLVER.getDistance(urlDevice.getId()); } /** * Gets the region string for device from the region resolver. * @param urlDevice The device being queried. * @return The region string for the device. */ public static String getRegionString(UrlDevice urlDevice) { return RangingUtils.toString(REGION_RESOLVER.getRegion(urlDevice.getId())); } static class UrlDeviceBuilder extends UrlDevice.Builder { /** * Constructor for the UrlDeviceBuilder. * @param id The id of the UrlDevice. * @param url The url of the UrlDevice. */ public UrlDeviceBuilder(String id, String url) { super(id, url); } /** * Set the device type. * @return The builder with type set. */ public UrlDeviceBuilder setDeviceType(String type) { addExtra(TYPE_KEY, type); return this; } /** * Setter for the ScanTimeMillis. * @param timeMillis The scan time of the UrlDevice. * @return The builder with ScanTimeMillis set. */ public UrlDeviceBuilder setScanTimeMillis(long timeMillis) { addExtra(SCANTIME_KEY, timeMillis); return this; } /** * Set the public key to false. * @return The builder with public set to false. */ public UrlDeviceBuilder setPrivate() { addExtra(PUBLIC_KEY, false); return this; } /** * Set the public key to true. * @return The builder with public set to true. */ public UrlDeviceBuilder setPublic() { addExtra(PUBLIC_KEY, true); return this; } /** * Set the title. * @param title corresonding to UrlDevice. * @return The builder with title */ public UrlDeviceBuilder setTitle(String title) { addExtra(TITLE_KEY, title); return this; } /** * Set the description. * @param description corresonding to UrlDevice. * @return The builder with description */ public UrlDeviceBuilder setDescription(String description) { addExtra(DESCRIPTION_KEY, description); return this; } /** * Set wifi-direct MAC address. * @param MAC address corresonding to UrlDevice. * @return The builder with address */ public UrlDeviceBuilder setWifiAddress(String address) { addExtra(WIFIDIRECT_KEY, address); return this; } /** * Set wifi-direct port. * @param port corresonding to UrlDevice. * @return The builder with port */ public UrlDeviceBuilder setWifiPort(int port) { addExtra(WIFIDIRECT_PORT_KEY, port); return this; } /** * Setter for the RSSI. * @param rssi The RSSI of the UrlDevice. * @return The builder with RSSI set. */ public UrlDeviceBuilder setRssi(int rssi) { addExtra(RSSI_KEY, rssi); return this; } /** * Setter for the TX power. * @param txPower The TX power of the UrlDevice. * @return The builder with TX power set. */ public UrlDeviceBuilder setTxPower(int txPower) { addExtra(TXPOWER_KEY, txPower); return this; } } static class PwsResultBuilder extends PwsResult.Builder { /** * Constructor for the PwsResultBuilder. * @param pwsResult The base result of the PwsResultBuilder. */ public PwsResultBuilder(PwsResult pwsResult) { super(pwsResult); } /** * Setter for the PWS Trip Time. * @param pwsResult The pwsResult. * @param timeMillis The PWS Trip Time for the result. * @return The builder PWS Trip Time set. */ public PwsResultBuilder setPwsTripTimeMillis(PwsResult pwsResult, long timeMillis) { addExtra(PWSTRIPTIME_KEY, timeMillis); return this; } } /** * Determines if a file is gzipped by examining the signature of * the file, which is the first two bytes. * @param file to be determined if is gzipped. * @return true If the contents of the file are gzipped otherwise false. */ public static boolean isGzippedFile(File file) { InputStream input; try { input = new FileInputStream(file); } catch (FileNotFoundException e) { return false; } byte[] signature = new byte[GZIP_SIGNATURE_LENGTH]; try { input.read(signature); } catch (IOException e) { return false; } return ((signature[0] == (byte) (GZIPInputStream.GZIP_MAGIC)) && (signature[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8))); } /** * Out-of-place Gunzips from src to dest. * @param src file containing gzipped information. * @param dest file to place decompressed information. * @return File that has decompressed information. */ public static File gunzip(File src, File dest) { byte[] buffer = new byte[1024]; try { GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(src)); FileOutputStream out = new FileOutputStream(dest); int len; while ((len = gzis.read(buffer)) > 0) { out.write(buffer, 0, len); } gzis.close(); out.close(); } catch (IOException ex) { ex.printStackTrace(); } return dest; } }