/* * Copyright 2014 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 com.google.samples.apps.iosched.nearby; import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; import android.util.Log; import android.util.Patterns; import java.util.HashMap; import java.util.List; import java.util.Map; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageRequest; import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.Volley; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import static com.google.samples.apps.iosched.Config.METADATA_URL; import static com.google.samples.apps.iosched.util.LogUtils.makeLogTag; /** * Class for resolving BLE device metadata via proxy. */ public class MetadataResolver { static String TAG = makeLogTag("MetadataResolver"); static Map<String, String> mDeviceUrlMap; static RequestQueue mRequestQueue; static boolean mIsInitialized = false; public static void initialize(Context context) { mDeviceUrlMap = new HashMap<String, String>(); if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(context); } mIsInitialized = true; } public static String getURLForDevice(NearbyDevice device) { if (!mIsInitialized) { Log.e(TAG, "Not initialized."); return null; } // If the device name is already a URL, use it. String deviceName = device.getName(); String url = deviceName; if (Patterns.WEB_URL.matcher(deviceName).matches()) { // TODO: Improve this. // For now, if there's no scheme present, add a default http:// scheme. if (!url.startsWith("http://") && !url.startsWith("https://")) { url = "http://" + url; } } else { // Otherwise, try doing the lookup. url = mDeviceUrlMap.get(deviceName); } return url; } public static void getBatchMetadata(List<NearbyDevice> batchList) { if (!mIsInitialized) { Log.e(TAG, "Not initialized."); return; } JSONObject jsonObj = createRequestObject(batchList); Map<String, NearbyDevice> deviceMap = new HashMap<String, NearbyDevice>(); for (int i = 0; i < batchList.size(); i++) { NearbyDevice nearbyDevice = batchList.get(i); deviceMap.put(nearbyDevice.getUrl(), nearbyDevice); } JsonObjectRequest jsObjRequest = createMetadataRequest(jsonObj, deviceMap); // Queue the request mRequestQueue.add(jsObjRequest); } private static JsonObjectRequest createMetadataRequest(JSONObject jsonObj, final Map<String, NearbyDevice> deviceMap) { return new JsonObjectRequest( METADATA_URL, jsonObj, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject jsonResponse) { try { JSONArray foundMetaData = jsonResponse.getJSONArray("metadata"); int deviceCount = foundMetaData.length(); for (int i = 0; i < deviceCount; i++) { JSONObject deviceData = foundMetaData.getJSONObject(i); String title = "Unknown name"; String url = "Unknown url"; String description = "Unknown description"; String iconUrl = "/favicon.ico"; String id = deviceData.getString("id"); if (deviceData.has("title")) { title = deviceData.getString("title"); } if (deviceData.has("url")) { url = deviceData.getString("url"); } if (deviceData.has("description")) { description = deviceData.getString("description"); } if (deviceData.has("icon")) { // We might need to do some magic here. iconUrl = deviceData.getString("icon"); } // Provisions for a favicon specified as a relative URL. if (!iconUrl.startsWith("http")) { // Lets just assume we are dealing with a relative path. Uri fullUri = Uri.parse(url); Uri.Builder builder = fullUri.buildUpon(); // Append the default favicon path to the URL. builder.path(iconUrl); iconUrl = builder.toString(); } DeviceMetadata deviceMetadata = new DeviceMetadata(); deviceMetadata.title = title; deviceMetadata.description = description; deviceMetadata.siteUrl = url; deviceMetadata.iconUrl = iconUrl; downloadIcon(deviceMetadata, deviceMap.get(id)); // Look up the device from the input and update the data deviceMap.get(id).onDeviceInfo(deviceMetadata); } } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.i(TAG, "VolleyError: " + volleyError.toString()); } } ); } private static JSONObject createRequestObject(List<NearbyDevice> devices) { JSONObject jsonObj = new JSONObject(); try { JSONArray urlArray = new JSONArray(); for(int dIdx = 0; dIdx < devices.size(); dIdx++) { NearbyDevice device = devices.get(dIdx); JSONObject urlObject = new JSONObject(); urlObject.put("url", device.getUrl()); urlObject.put("rssi", device.getLastRSSI()); urlArray.put(urlObject); } JSONObject location = new JSONObject(); location.put("lat", 49.129837); location.put("lon", 120.38142); jsonObj.put("location", location); jsonObj.put("objects", urlArray); } catch(JSONException ex) { } return jsonObj; } /** * Asynchronously download the image for the nearby device. * @param metadata * @param listener */ private static void downloadIcon(final DeviceMetadata metadata, final OnMetadataListener listener) { ImageRequest imageRequest = new ImageRequest(metadata.iconUrl, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { Log.i(TAG, "Got an image: " + response.toString()); metadata.icon = response; listener.onDeviceInfo(metadata); } }, 0, 0, null, null); mRequestQueue.add(imageRequest); } public interface OnMetadataListener { public void onDeviceInfo(DeviceMetadata deviceMetadata); } }