diff --git a/blur_location2city.r2py b/blur_location2city.r2py index 9e7d531..85c1a9e 100644 --- a/blur_location2city.r2py +++ b/blur_location2city.r2py @@ -164,4 +164,4 @@ CHILD_CONTEXT_DEF["get_lastknown_location"] = { # Dispatch. -secure_dispatch_module() +secure_dispatch_module() \ No newline at end of file diff --git a/blur_location2country.r2py b/blur_location2country.r2py index 1e8081f..8f4dbc5 100644 --- a/blur_location2country.r2py +++ b/blur_location2country.r2py @@ -1,185 +1,167 @@ -httpretrieve = dy_import_module("httpretrieve.r2py") -math = dy_import_module("math.r2py") -librepyfile = dy_import_module("librepyfile.r2py") - -statefilename = "states.txt" # Database of states -countryfilename = "countries.txt" # Database of countries - - -# Downloads the required file from the server -def get_file_from_server(filename): - - if filename not in listfiles(): # In case it already exists - if filename not in [statefilename, countryfilename]: - url = "http://sensibilityclearinghouse.poly.edu/data/quad/" + filename - else: - url = "http://sensibilityclearinghouse.poly.edu/data/" + filename - httpretrieve.httpretrieve_save_file(url, filename) - - -# Returns a dictionary containing information about the point closest to -# a given lat/lng pair, from the database. -# {"city": closest_city, "statecode": closest_state_code, "countrycode": -# closest_country_code, "coordinates": closest_point} -def find_closest_point(lat, lng): - - # Find the database file with coordinates closest to the given lat/lng pair - filename = get_filename(lat, lng) - # Get the list of coordinates from that file - listofpoints = load_lat_lng_from_file(filename) - - min_dist = 9999 - point1 = (lat, lng) - - for city in listofpoints.keys(): - data = listofpoints[city] - point2 = (data[0], data[1]) - dist = find_distance(point1, point2) - if dist < min_dist: - min_dist = dist - closest_point = point2 - closest_city = city - closest_state_code = data[3] - closest_country_code = data[2] - - closest = {"city": closest_city, "statecode": closest_state_code, "countrycode": closest_country_code, "coordinates": closest_point} - - return closest - - -# Returns the filename in the database with coordinates closest to the given -# lat/lng pair -def get_filename(lat, lng): - - # get ceiling as x/y index - x = int(math.math_ceil(lat)) - y = int(math.math_ceil(lng)) - filename = str(x) + '_' + str(y) + '.txt' - return filename - - -# Returns a dictionary containing all the cities in the given file, along with -# their corresponding data -# {city1: [lat, lng, country_code, state_code], city2: [lat, lng, country_code, -# state_code], ...} -def load_lat_lng_from_file(filename): - - get_file_from_server(filename) - listofpoints = {} - fileobj = librepyfile.open(filename, "r") - - while True: - try: - line = fileobj.next().strip() - except StopIteration: - break - else: - line = line.split("\t") - city_name = line[0] - lat = line[1] - lng = line[2] - country_code = line[3] - state_code = line[4] - listofpoints[city_name] = [lat, lng, country_code, state_code] - fileobj.close() - return listofpoints - - -# Returns the distance between two lat/lng points -def find_distance(p1, p2): - - (lat1, lng1) = p1 - (lat2, lng2) = p2 - lat2 = float(lat2) - lng2 = float(lng2) - lat_diff = (lat1-lat2) * (lat1-lat2) - lng_diff = (lng1-lng2) * (lng1-lng2) - # return squared distance - return lat_diff + lng_diff - - -# To replace get_location() -def get_country_location(): - - try: - location_data = get_location() - except Exception: # Not able to use LocationNotFoundException here - raise Exception +""" +A security layer for the functions get_location() and get_lastknown_location() +defined in getsensor.r2py. This program blurs the latitude/longitude +coordinates, received from the location sensors of an Android device, +to the geographic center of the country to which it belongs. + +The blurring is done using a database lookup method. First, we use the +get_geolocation() call to get the current address. The country code in +the address returned is then used to find a match in the database +"countries.txt", which is a list of all countries and their geodata. +This database file is located at: +http://sensibilityclearinghouse.poly.edu/data/countries.txt + +Usage: + start dylink.r2py encasementlib.r2py sensor_layer.r2py \ + blur_location2country.r2py user-program.r2py +""" + + + +location_blur_helper = dy_import_module("location_blur_helper.r2py") +country_filename = "countries.txt" + + + +def load_country_geodata(address): + """ + Loads the country (or countries) and corresponding geodata from the + given file into a dictionary. + + Below is an example of a line from the file "countries.txt" with + fields - country code, country name, latitude and longitude: + US United States 39.76 -98.5 + + The dictionary returned has the format: + { + country1: {"latitude": latitude, "longitude": longitude}, + country2: {"latitude": latitude, "longitude": longitude}, + ... + } + + """ + # Download the file from the country database. + location_blur_helper.get_country_file_from_server(country_filename) + # Obtain the list of countries and their geodata from the file. + countries_geodata = location_blur_helper.read_data_from_file(country_filename) + + country_dict = {} + + # Check if we can match the country code in the given address to that + # in the database. If there is a match, return a dict with that + # country and its geodata. + for line in countries_geodata: + # Ignore the empty line at the end of the file. + if line == "": + continue + country_geodata_record = line.split("\t") + if address["country_code"] == country_geodata_record[0]: + country_name = country_geodata_record[1] + country_dict[country_name] = { + "latitude": float(country_geodata_record[2]), + "longitude": float(country_geodata_record[3]) + } + return country_dict + + # If no match, return a dict of all countries and their geodata to + # find the closest country. + for line in countries_geodata: + # Ignore the empty line at the end of the file. + if line == "": + continue + country_geodata_record = line.split("\t") + country_name = country_geodata_record[1] + country_dict[country_name] = { + "latitude": float(country_geodata_record[2]), + "longitude": float(country_geodata_record[3]), + } + + return country_dict + + +def find_closest_country(lat, lon): + """ + Finds the country closest to the given latitude/longitude pair from the + dictionary of countries returned by the load_country_geodata() function, + and returns that country's geodata in the format: + { + "country_name": country name (string), + "latitude": latitude of the center of the country (float) + "longitude": longitude of the center of the country (float) + } + + Note: If the load_country_geodata() function returns only one country, + which happens when the country code from the get_geolocation() call + was successfully matched with one of the countries' code in the database, + then only that country's geodata is returned in the dictionary. + + """ + # Get the address for the given coordinates. Since get_geolocation() + # can possibly return more than one address, we take the first one. + address = get_geolocation(lat, lon, 1)[0] + + # Load the state(s) and corresponding geodata from the file. + countries_dict = load_country_geodata(address) + + return location_blur_helper.find_closest_location(lat, lon, countries_dict) - latitude = location_data["latitude"] - longitude = location_data["longitude"] - closest = find_closest_point(latitude, longitude) - country_code = closest["countrycode"] - # Download the Countries database - get_file_from_server(countryfilename) +def get_country_location(): + """ + Blurring layer for the get_location() function. It replaces the exact + coordinates of the Android device with the coordinates for the + geographic center of the country to which they belong. - countryfile = librepyfile.open(countryfilename, "r") + """ + location_data = get_location() - # Look for the country corresponding to the country code - while True: - try: - line = countryfile.next().strip() - except StopIteration: - break - else: - line = line.split("\t") - if country_code == line[0]: - clat = line[2] - clng = line[3] - break - countryfile.close() + closest_country = find_closest_country(location_data["latitude"], + location_data["longitude"]) - location_data["latitude"] = clat - location_data["longitude"] = clng + location_data["latitude"] = closest_country["latitude"] + location_data["longitude"] = closest_country["longitude"] return location_data + + def get_country_lastknown_location(): - # to replace get_lastknown_location() - try: - location_data = get_lastknown_location() - except Exception: # Not able to use LocationNotFoundException here - raise Exception - - # Get the location from the the provider - for i in range(len(location_data.keys())): - provider = location_data.keys()[i] - location = location_data[provider] - if location != None: - latitude = location["latitude"] - longitude = location["longitude"] - - closest = find_closest_point(latitude, longitude) - - country_code = closest["countrycode"] - - # Download the Countries database - get_file_from_server(countryfilename) - - countryfile = librepyfile.open(countryfilename, "r") - - # Look for the country corresponding to the country code - while True: - try: - line = countryfile.next().strip() - except StopIteration: - break - else: - line = line.split("\t") - if country_code == line[0]: - clat = line[2] - clng = line[3] - break - countryfile.close() - - location_data[provider]["latitude"] = clat - location_data[provider]["longitude"] = clng + """ + Blurring layer for the get_lastknown_location() function. It replaces + the last-known coordinates of the Android device with the coordinates + for the geographic center of the country to which they belong. + + """ + location_data = get_lastknown_location() + + # Blur the coordinates of the first non-empty location data. + for location_provider, provider_location_data in location_data.items(): + # Skip this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue + + closest_country = find_closest_country(provider_location_data["latitude"], + provider_location_data["longitude"]) + + break + + # Copy the blurred coordinates into all providers' location data. + for location_provider, provider_location_data in location_data.items(): + # Skip blurring this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue + + location_data[location_provider]["latitude"] = closest_country["latitude"] + location_data[location_provider]["longitude"] = closest_country["longitude"] return location_data + +# Mapping our blurring function get_country_location to get_location. CHILD_CONTEXT_DEF["get_location"] = { "type": "func", "args": None, @@ -189,6 +171,8 @@ CHILD_CONTEXT_DEF["get_location"] = { } +# Mapping our blurring function get_country_lastknown_location to +# get_lastknown_location. CHILD_CONTEXT_DEF["get_lastknown_location"] = { "type": "func", "args": None, @@ -197,4 +181,6 @@ CHILD_CONTEXT_DEF["get_lastknown_location"] = { "target": get_country_lastknown_location, } + +# Dispatch. secure_dispatch_module() \ No newline at end of file diff --git a/blur_location2state.r2py b/blur_location2state.r2py index 652db41..e853160 100644 --- a/blur_location2state.r2py +++ b/blur_location2state.r2py @@ -1,191 +1,179 @@ -httpretrieve = dy_import_module("httpretrieve.r2py") -math = dy_import_module("math.r2py") -librepyfile = dy_import_module("librepyfile.r2py") - -statefilename = "states.txt" # Database of states -countryfilename = "countries.txt" # Database of countries - - -# Downloads the required file from the server -def get_file_from_server(filename): - - if filename not in listfiles(): # In case it already exists - if filename not in [statefilename, countryfilename]: - url = "http://sensibilityclearinghouse.poly.edu/data/quad/" + filename - else: - url = "http://sensibilityclearinghouse.poly.edu/data/" + filename - httpretrieve.httpretrieve_save_file(url, filename) - - -# Returns a dictionary containing information about the point closest to -# a given lat/lng pair, from the database. -# {"city": closest_city, "statecode": closest_state_code, "countrycode": -# closest_country_code, "coordinates": closest_point} -def find_closest_point(lat, lng): - - # Find the database file with coordinates closest to the given lat/lng pair - filename = get_filename(lat, lng) - # Get the list of coordinates from that file - listofpoints = load_lat_lng_from_file(filename) - - min_dist = 9999 - point1 = (lat, lng) - - for city in listofpoints.keys(): - data = listofpoints[city] - point2 = (data[0], data[1]) - dist = find_distance(point1, point2) - if dist < min_dist: - min_dist = dist - closest_point = point2 - closest_city = city - closest_state_code = data[3] - closest_country_code = data[2] - - closest = {"city": closest_city, "statecode": closest_state_code, "countrycode": closest_country_code, "coordinates": closest_point} - - return closest - - -# Returns the filename in the database with coordinates closest to the given -# lat/lng pair -def get_filename(lat, lng): - - # get ceiling as x/y index - x = int(math.math_ceil(lat)) - y = int(math.math_ceil(lng)) - filename = str(x) + '_' + str(y) + '.txt' - return filename - - -# Returns a dictionary containing all the cities in the given file, along with -# their corresponding data -# {city1: [lat, lng, country_code, state_code], city2: [lat, lng, country_code, -# state_code], ...} -def load_lat_lng_from_file(filename): - - get_file_from_server(filename) - listofpoints = {} - fileobj = librepyfile.open(filename, "r") - - while True: - try: - line = fileobj.next().strip() - except StopIteration: - break - else: - line = line.split("\t") - city_name = line[0] - lat = line[1] - lng = line[2] - country_code = line[3] - state_code = line[4] - listofpoints[city_name] = [lat, lng, country_code, state_code] - fileobj.close() - return listofpoints - - -# Returns the distance between two lat/lng points -def find_distance(p1, p2): - - (lat1, lng1) = p1 - (lat2, lng2) = p2 - lat2 = float(lat2) - lng2 = float(lng2) - lat_diff = (lat1-lat2) * (lat1-lat2) - lng_diff = (lng1-lng2) * (lng1-lng2) - # return squared distance - return lat_diff + lng_diff - - -# To replace get_location() +""" +A security layer for the functions get_location() and get_lastknown_location() +defined in getsensor.r2py. This program blurs the latitude/longitude +coordinates, received from the location sensors of an Android device, +to the geographic center of approximately the nearest state (admin area). + +The blurring is done using a database lookup method. First, we use the +get_geolocation() call to get the current address. The country code in +the address returned is then used to look up the list of states for +that country from the database. This database, located at +http://sensibilityclearinghouse.poly.edu/data/states/, is a list of +all states and their corresponding geodata divided by country, where +each file is named with the 2-letter country code (e.g., "US.txt"). + +Next, we use the state name from the returned address to check for a +match with the list of states. If there is a match, the coordinates +associated with that state are returned. If there is no match, we look +for the state that has coordinates closest to the those received from +the location sensors and return its latitude and longitude. + +Usage: + start dylink.r2py encasementlib.r2py sensor_layer.r2py \ + blur_location2state.r2py user-program.r2py +""" + + + +location_blur_helper = dy_import_module("location_blur_helper.r2py") + + + +def load_state_geodata(address): + """ + Loads the state(s) and corresponding geodata from the given file + into a dictionary. + + Below is an example of a line from the file + http://sensibilityclearinghouse.poly.edu/data/states/US.txt, + with fields - state code, state name, latitude, longitude: + US.NY New York 43.00035 -75.4999 + + The dictionary that is returned has the format: + { + state1: {"latitude": latitude, "longitude": longitude}, + state2: {"latitude": latitude, "longitude": longitude}, + ... + } + + """ + # Use the country code to get the filename of the list of states + # for that country. + filename = address["country_code"] + ".txt" + # Download the file from the state database. + location_blur_helper.get_state_file_from_server(filename) + # Obtain the list of states and their geodata from the file. + states_geodata = location_blur_helper.read_data_from_file(filename) + + states_dict = {} + + # Check if we can match the state name in the given address to the + # name in the database. If there is a match, return a dict with that + # state and its geodata (state names are unique in each file). + if "admin_area" in address: + for line in states_geodata: + # Ignore the empty line at the end of the file. + if line == "": + continue + state_geodata_record = line.split("\t") + if address["admin_area"] == state_geodata_record[1]: + state_name = state_geodata_record[1] + states_dict[state_name] = { + "latitude": float(state_geodata_record[2]), + "longitude": float(state_geodata_record[3]), + } + return states_dict + + # If no match, return a dict of all states and their geodata to + # find the closest state. + for line in states_geodata: + # Ignore the empty line at the end of the file. + if line == "": + continue + state_geodata_record = line.split("\t") + state_name = state_geodata_record[1] + states_dict[state_name] = { + "latitude": float(state_geodata_record[2]), + "longitude": float(state_geodata_record[3]), + } + + return states_dict + + + +def find_closest_state(lat, lon): + """ + Finds the state closest to the given latitude/longitude pair from the + dictionary of states returned by the load_state_geodata() function, + and returns that state's geodata in the format: + { + "state_name": state name (string), + "latitude": latitude of the center of the state (float) + "longitude": longitude of the center of the state (float) + } + + Note: If the load_state_geodata() function returns only one state, + which happens when the state name from the get_geolocation() call + was successfully matched with one of the states in the database, + then only that state's geodata is returned in the dictionary. + + """ + # Get the address for the given coordinates. Since get_geolocation() + # can possibly return more than one address, we take the first one. + address = get_geolocation(lat, lon, 1)[0] + + # Load the state(s) and corresponding geodata from the file. + states_dict = load_state_geodata(address) + + return location_blur_helper.find_closest_location(lat, lon, states_dict) + + + def get_state_location(): + """ + Blurring layer for the get_location() function. It replaces the exact + coordinates of the Android device with the coordinates for the + geographic center of the nearest state. + + """ + location_data = get_location() - try: - location_data = get_location() - except Exception: # Not able to use LocationNotFoundException here - raise Exception - - latitude = location_data["latitude"] - longitude = location_data["longitude"] - - closest = find_closest_point(latitude, longitude) - country_code = closest["countrycode"] - state_code = closest["statecode"] - code = country_code + "." + str(state_code) - - # Download the States database - get_file_from_server(statefilename) - - statefile = librepyfile.open(statefilename, "r") - - # Look for the state corresponding to the code - while True: - try: - line = statefile.next().strip() - except StopIteration: - break - else: - line = line.split("\t") - if code == line[0]: - slat = line[2] - slng = line[3] - break - statefile.close() - - location_data["latitude"] = slat - location_data["longitude"] = slng + closest_state = find_closest_state(location_data["latitude"], + location_data["longitude"]) + + location_data["latitude"] = closest_state["latitude"] + location_data["longitude"] = closest_state["longitude"] return location_data -# To replace get_lastknown_location() + def get_state_lastknown_location(): + """ + Blurring layer for the get_lastknown_location() function. It replaces + the last-known coordinates of the Android device with the coordinates + for the geographic center of the nearest state. + + """ + location_data = get_lastknown_location() - try: - location_data = get_lastknown_location() - except Exception: # Not able to use LocationNotFoundException here - raise Exception - - # Get the location from the the provider - for i in range(len(location_data.keys())): - provider = location_data.keys()[i] - location = location_data[provider] - if location != None: - latitude = location["latitude"] - longitude = location["longitude"] - - closest = find_closest_point(latitude, longitude) - - country_code = closest["countrycode"] - state_code = closest["statecode"] - code = country_code + "." + str(state_code) - - # Download the States database - get_file_from_server(statefilename) - - statefile = librepyfile.open(statefilename, "r") - - # Look for the state corresponding to the code - while True: - try: - line = statefile.next().strip() - except StopIteration: - break - else: - line = line.split("\t") - if code == line[0]: - slat = line[2] - slng = line[3] - break - statefile.close() - - location_data[provider]["latitude"] = slat - location_data[provider]["longitude"] = slng + # Blur the coordinates of the first non-empty location data. + for location_provider, provider_location_data in location_data.items(): + # Skip this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue + + closest_state = find_closest_state(provider_location_data["latitude"], + provider_location_data["longitude"]) + + break + + # Copy the blurred coordinates into all providers' location data. + for location_provider, provider_location_data in location_data.items(): + # Skip blurring this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue + + location_data[location_provider]["latitude"] = closest_state["latitude"] + location_data[location_provider]["longitude"] = closest_state["longitude"] return location_data + +# Mapping our blurring function get_state_location to get_location. CHILD_CONTEXT_DEF["get_location"] = { "type": "func", "args": None, @@ -195,6 +183,8 @@ CHILD_CONTEXT_DEF["get_location"] = { } +# Mapping our blurring function get_state_lastknown_location to +# get_lastknown_location. CHILD_CONTEXT_DEF["get_lastknown_location"] = { "type": "func", "args": None, @@ -203,4 +193,6 @@ CHILD_CONTEXT_DEF["get_lastknown_location"] = { "target": get_state_lastknown_location, } + +# Dispatch secure_dispatch_module() \ No newline at end of file diff --git a/blur_location2zipcode.r2py b/blur_location2zipcode.r2py new file mode 100644 index 0000000..62c3b13 --- /dev/null +++ b/blur_location2zipcode.r2py @@ -0,0 +1,167 @@ +""" +A security layer for the functions get_location() and get_lastknown_location() +defined in getsensor.r2py. This program blurs the latitude/longitude +coordinates, received from the location sensors of an Android device, +to the geographic center of approximately the nearest ZIP code area. + +The blurring is done using a database lookup method. The database, +located at http://sensibilityclearinghouse.poly.edu/data/zip/, contains +a list of ZIP codes and their geodata, divided by their latitude/longitude +coordinates into cells. Each cell is a separate file in the database, +whose name is derived as "ceiling(latitude)_ceiling(longitude).txt". +For example, if a location has coordinates (40.78343, -73.96625), it +will be mapped to the file with name "41_-73.txt". + +Usage: + start dylink.r2py encasementlib.r2py sensor_layer.r2py \ + blur_location2zipcode.r2py user-program.r2py +""" + + + +location_blur_helper = dy_import_module("location_blur_helper.r2py") + + + +def load_zipcode_geodata(lat, lon): + """ + Loads all ZIP codes and corresponding geodata from the given file + into a dictionary. + + Below is an example of a line from the file + http://sensibilityclearinghouse.poly.edu/data/zip/41_-73.txt + with fields - country code, ZIP code, latitude, longitude: + US 10012 40.7255 -73.9983 + + The dictionary that is returned has the format: + { + zipcode1: {"latitude": latitude, "longitude": longitude}, + zipcode2: {"latitude": latitude, "longitude": longitude}, + ... + } + + """ + # Determine which file to download from the database. + filename = location_blur_helper.get_database_filename(lat, lon) + # Download the file from the ZIP code database. + location_blur_helper.get_zipcode_file_from_server(filename) + # Obtain the list of ZIP codes and their geodata from the file. + zipcodes_geodata = location_blur_helper.read_data_from_file(filename) + + zipcodes_dict = {} + + for line in zipcodes_geodata: + # Ignore the empty line at the end of the file. + if line == "": + continue + zipcode_geodata_record = line.split("\t") + zipcode = zipcode_geodata_record[1] + zipcodes_dict[zipcode] = { + "latitude": float(zipcode_geodata_record[2]), + "longitude": float(zipcode_geodata_record[3]), + } + + return zipcodes_dict + + + +def find_closest_zipcode(lat, lon): + """ + Finds the ZIP code closest to the given latitude/longitude pair from the + dictionary of ZIP codes returned by the load_zipcode_geodata() function, + and returns that ZIP code's geodata in the format: + { + "zipcode": ZIP code (string), + "latitude": latitude of the center of the ZIP code area (float) + "longitude": longitude of the center of the ZIP code area (float) + } + + Note: We're looking for the closest ZIP code within the same cell as + the given latitude/longitude pair. There might be a closer ZIP code + area in the surrounding cells. + + """ + # Load all ZIP codes and corresponding geodata from the file. + zipcodes_dict = load_zipcode_geodata(lat, lon) + + return location_blur_helper.find_closest_location(lat, lon, zipcodes_dict) + + + +def get_zipcode_location(): + """ + Blurring layer for the get_location() function. It replaces the exact + coordinates of the Android device with the coordinates for the + geographic center of the nearest ZIP code area. + + """ + location_data = get_location() + + closest_zipcode = find_closest_zipcode(location_data["latitude"], + location_data["longitude"]) + + location_data["latitude"] = closest_zipcode["latitude"] + location_data["longitude"] = closest_zipcode["longitude"] + + return location_data + + + +def get_zipcode_lastknown_location(): + """ + Blurring layer for the get_lastknown_location() function. It replaces + the last-known coordinates of the Android device with the coordinates + for the geographic center of the nearest ZIP code area. + + """ + location_data = get_lastknown_location() + + # Blur the coordinates of the first non-empty location data. + for location_provider, provider_location_data in location_data.items(): + # Skip this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue + + closest_zipcode = find_closest_zipcode(provider_location_data["latitude"], + provider_location_data["longitude"]) + + break + + # Copy the blurred coordinates into all providers' location data. + for location_provider, provider_location_data in location_data.items(): + # Skip blurring this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue + + location_data[location_provider]["latitude"] = closest_zipcode["latitude"] + location_data[location_provider]["longitude"] = closest_zipcode["longitude"] + + return location_data + + + +# Mapping our blurring function get_zipcode_location to get_location. +CHILD_CONTEXT_DEF["get_location"] = { + "type": "func", + "args": None, + "return": dict, + "exceptions": "any", + "target": get_zipcode_location, +} + + +# Mapping our blurring function get_zipcode_lastknown_location to +# get_lastknown_location. +CHILD_CONTEXT_DEF["get_lastknown_location"] = { + "type": "func", + "args": None, + "return": dict, + "exceptions": "any", + "target": get_zipcode_lastknown_location, +} + + +# Dispatch. +secure_dispatch_module() \ No newline at end of file diff --git a/blur_location_round.r2py b/blur_location_round.r2py index 3eb8c5a..53282c5 100644 --- a/blur_location_round.r2py +++ b/blur_location_round.r2py @@ -1,36 +1,57 @@ +""" +A security layer for the functions get_location() and get_lastknown_location() +defined in getsensor.r2py. This program blurs the latitude/longitude +coordinates, received from the location sensors of an Android device, +by rounding them off to one decimal place. + +Usage: + start dylink.r2py encasementlib.r2py sensor_layer.r2py \ + blur_location_round.r2py user-program.r2py +""" + + + def blur_location_round(): + """ + Blurring layer for the get_location() function. It replaces the exact + coordinates of the Android device with the coordinates rounded off to + a single decimal place. - try: - location = get_location() - except Exception: # Not able to use LocationNotFoundException here - raise Exception + """ + location_data = get_location() - # Blur the coordinates by rounding - location["latitude"] = round(float(location["latitude"]), 1) - location["longitude"] = round(float(location["longitude"]), 1) + location_data["latitude"] = round(float(location_data["latitude"]), 1) + location_data["longitude"] = round(float(location_data["longitude"]), 1) - return location + return location_data def blur_lastknown_location_round(): + """ + Blurring layer for the get_lastknown_location() function. It replaces + the last-known coordinates of the Android device with the coordinates + rounded off to a single decimal place. + + """ + location_data = get_lastknown_location() + + for location_provider, provider_location_data in location_data.items(): + # Skip blurring this provider's data if it doesn't contain a previous + # location. + if provider_location_data is None: + continue - try: - location = get_lastknown_location() - except Exception: # Not able to use LocationNotFoundException here - raise Exception + location_data[location_provider]["latitude"] = \ + round(float(provider_location_data["latitude"]), 1) + location_data[location_provider]["longitude"] = \ + round(float(provider_location_data["longitude"]), 1) - # Blur the coordinates by rounding - for i in range(len(location.keys())): - provider = location.keys()[i] - location_item = location[provider] - if location_item != None: - location[provider]["latitude"] = round(float(location_item["latitude"]), 1) - location[provider]["longitude"] = round(float(location_item["longitude"]), 1) + return location_data - return location +# Mapping our blurring function blur_location_round to get_location. CHILD_CONTEXT_DEF["get_location"] = { "type": "func", "args": None, @@ -40,6 +61,8 @@ CHILD_CONTEXT_DEF["get_location"] = { } +# Mapping our blurring function blur_lastknown_location_round to +# get_lastknown_location. CHILD_CONTEXT_DEF["get_lastknown_location"] = { "type": "func", "args": None, @@ -49,4 +72,5 @@ CHILD_CONTEXT_DEF["get_lastknown_location"] = { } +# Dispatch. secure_dispatch_module() \ No newline at end of file diff --git a/location_blur_helper.r2py b/location_blur_helper.r2py new file mode 100644 index 0000000..8206c72 --- /dev/null +++ b/location_blur_helper.r2py @@ -0,0 +1,164 @@ +""" +This is a helper program that contains some of the common functions +shared between the blurring layers blur_location2city, blur_location2zipcode, +blur_location2state and blur_location2country. + +""" + + + +httpretrieve = dy_import_module("httpretrieve.r2py") +math = dy_import_module("math.r2py") + + + +def get_zipcode_file_from_server(filename): + """ + Downloads the required file from the database server, if it has not + already been downloaded. + + The database is located at: + http://sensibilityclearinghouse.poly.edu/data/zip/ + + """ + if filename not in listfiles(): + url = "http://sensibilityclearinghouse.poly.edu/data/zip/" + filename + httpretrieve.httpretrieve_save_file(url, filename) + + + +def get_city_file_from_server(filename): + """ + Downloads the required file from the database server, if it has not + already been downloaded. + + The database is located at: + http://sensibilityclearinghouse.poly.edu/data/quad/ + + """ + if filename not in listfiles(): + url = "http://sensibilityclearinghouse.poly.edu/data/quad/" + filename + httpretrieve.httpretrieve_save_file(url, filename) + + + +def get_state_file_from_server(filename): + """ + Downloads the required file from the database server, if it has not + already been downloaded. + + The database is located at: + http://sensibilityclearinghouse.poly.edu/data/states/ + + """ + if filename not in listfiles(): + url = "http://sensibilityclearinghouse.poly.edu/data/states/" + filename + httpretrieve.httpretrieve_save_file(url, filename.lower()) + + + +def get_country_file_from_server(filename): + """ + Downloads the required file from the database server, if it has not + already been downloaded. + + The database is located at: + http://sensibilityclearinghouse.poly.edu/data/countries.txt + + """ + if filename not in listfiles(): + url = "http://sensibilityclearinghouse.poly.edu/data/" + filename + httpretrieve.httpretrieve_save_file(url, filename) + + + +def get_database_filename(lat, lon): + """ + Returns the filename of the cell in the database to which the given + latitude/longitude pair belongs. + + """ + # Get ceiling as x/y index. + x = int(math.math_ceil(lat)) + y = int(math.math_ceil(lon)) + filename = str(x) + '_' + str(y) + ".txt" + return filename + + + +def find_squared_difference(p1, p2): + """ + Returns the squared difference between the two given pairs of + coordinates (p1 and p2, where p1 and p2 are tuples of the form + (latitude, longitude)). + + """ + lat1, lon1 = p1 + lat2, lon2 = p2 + lat_diff = (lat1-lat2) ** 2 + lon_diff = (lon1-lon2) ** 2 + return lat_diff + lon_diff + + + +def read_data_from_file(filename): + """ + Reads all data from the given file and returns a list of the lines + in that file. + + """ + fileobj = openfile(filename.lower(), False) + file_data = fileobj.readat(None, 0).split("\n") + fileobj.close() + return file_data + + + +def find_closest_location(lat, lon, location_dict): + """ + Returns a dictionary with the name and coordinates of the center of + the closest location to the given latitude and longitude coordinates. + This location, depending on the level of blurring, could be the + closest city, state, ZIP code area or country. + + The argument "location_dict" contains a list of all nearby + locations (either cities, states, ZIP code areas or countries) and + their geodata (latitude and longitude). + + The dictionary returned has the format: + { + "name": name of the closest location (string), + "latitude": latitude of the center of the above location (float), + "longitude": longitude of the center of the above location (float) + } + """ + # Check if there is only one entry in the dictionary, (e.g., in a state + # file like this http://sensibilityclearinghouse.poly.edu/data/states/US.txt + # there's only one entry that matches the state name) + if len(location_dict) == 1: + closest_location = location_dict.keys()[0] + + # Else find closest location. + else: + # Set the minimum squared difference between two pairs of coordinates + # to a number larger than any possible minimum distance to a close + # location in the current latitude/longitude cell (in case of + # blurring to city/ZIP code area), in the current country (in + # case of blurring to state), or in the entire world (in case of + # blurring to country). + min_diff = 9999 + + for current_location, location_geodata in location_dict.items(): + diff = find_squared_difference((lat, lon), (location_geodata["latitude"], + location_geodata["longitude"])) + if diff < min_diff: + min_diff = diff + closest_location = current_location + + closest_location_geodata = { + "name": closest_location, + "latitude": location_dict[closest_location]["latitude"], + "longitude": location_dict[closest_location]["longitude"] + } + + return closest_location_geodata \ No newline at end of file