From 92c32b0b96938009af55ed28920472f22a4614ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 31 Jan 2013 22:12:21 +0100 Subject: Problems with downloaded file, the emulator cannot find the file downloaded. Seen http://code.google.com/p/android/issues/detail?id=18462 and decided to look for another solution. First solution thought (and going to be the next test): HTTP Get request :) --- src/se/leap/leapclient/Dashboard.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 15 ++ src/se/leap/leapclient/ProviderListActivity.java | 187 +++++++++++++++++++++++ src/se/leap/leapclient/ProviderListContent.java | 77 ++++++++++ src/se/leap/leapclient/ProviderListFragment.java | 150 ++++++++++++++++++ 5 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 src/se/leap/leapclient/ProviderAPI.java create mode 100644 src/se/leap/leapclient/ProviderListActivity.java create mode 100644 src/se/leap/leapclient/ProviderListContent.java create mode 100644 src/se/leap/leapclient/ProviderListFragment.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 7d0b5e0f..84ddab27 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -37,8 +37,8 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); // FIXME provider data!! get parmegv's work so we can stop (or lessen) faking it - if ( !preferences.contains("provider") ) - fixmePrefsFaker(preferences); + if (preferences.contains("provider") ) + startActivity(new Intent(this, ProviderListActivity.class)); // Get our provider provider = Provider.getInstance(preferences); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java new file mode 100644 index 00000000..6d52e44f --- /dev/null +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -0,0 +1,15 @@ +package se.leap.leapclient; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class ProviderAPI extends Service { + + @Override + public IBinder onBind(Intent arg0) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java new file mode 100644 index 00000000..4964a1fd --- /dev/null +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -0,0 +1,187 @@ +package se.leap.leapclient; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; + +import se.leap.leapclient.ProviderListContent; +import se.leap.leapclient.ProviderListContent.ProviderItem; +import android.app.DownloadManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.AssetManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.app.FragmentActivity; + + +/** + * An activity representing a list of Providers. This activity + * has different presentations for handset and tablet-size devices. On + * handsets, the activity presents a list of items, which when touched, + * lead to a {@link DashboardActivity} representing + * item details. On tablets, the activity presents the list of items and + * item details side-by-side using two vertical panes. + *

+ * The activity makes heavy use of fragments. The list of items is a + * {@link ProviderListFragment} and the item details + * (if present) is a {@link DashboardFragment}. + *

+ * This activity also implements the required + * {@link ProviderListFragment.Callbacks} interface + * to listen for item selections. + */ +public class ProviderListActivity extends FragmentActivity + implements ProviderListFragment.Callbacks { + + /** + * Whether or not the activity is in two-pane mode, i.e. running on a tablet + * device. + */ + private boolean mTwoPane; + + private static SharedPreferences preferences; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_provider_list); + + preferences = getPreferences(MODE_PRIVATE); + + loadPreseededProviders(); + + // TODO: If exposing deep links into your app, handle intents here. + } + + private void loadPreseededProviders() { + AssetManager asset_manager = getAssets(); + String[] urls_filepaths = null; + try { + String url_files_folder = "urls"; + //TODO Put that folder in a better place (also inside the "for") + urls_filepaths = asset_manager.list(url_files_folder); + String provider_name = ""; + for(String url_filepath : urls_filepaths) + { + provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString(); + if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list + ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath))); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Callback method from {@link ProviderListFragment.Callbacks} + * indicating that the item with the given ID was selected. + */ + @Override + public void onItemSelected(String id) { + if (mTwoPane) { + + } else { + // In single-pane mode, simply start the detail activity + // for the selected item ID. + + Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); + while(preseeded_providers_iterator.hasNext()) + { + ProviderItem current_provider_item = preseeded_providers_iterator.next(); + if(current_provider_item.id.equalsIgnoreCase(id)) + { + ArrayList downloaded_files = downloadFiles(current_provider_item); + try { + parseToSharedPrefs(downloaded_files); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + Intent dashboardIntent = new Intent(this, Dashboard.class); + startActivity(dashboardIntent); + } + } + + private void parseToSharedPrefs(ArrayList downloaded_files) throws IOException { + SharedPreferences.Editor sharedPreferencesEditor = preferences.edit(); + + for(int i = 0; i < downloaded_files.size(); i++) + { + String type_and_filename = downloaded_files.get(i); + String filename = type_and_filename.substring(type_and_filename.indexOf(":")+1, type_and_filename.length()); + + String file_contents = readFileAsString(filename, null); + + if(downloaded_files.get(i).startsWith("provider:")) + sharedPreferencesEditor.putString("provider", file_contents); + else if(downloaded_files.get(i).startsWith("provider:")) + sharedPreferencesEditor.putString("eip", file_contents); + + sharedPreferencesEditor.commit(); + } + } + + public static String readFileAsString(String fileName, String charsetName) + throws java.io.IOException { + java.io.InputStream is = new java.io.FileInputStream(fileName); + try { + final int bufsize = 4096; + int available = is.available(); + byte data[] = new byte[available < bufsize ? bufsize : available]; + int used = 0; + while (true) { + if (data.length - used < bufsize) { + byte newData[] = new byte[data.length << 1]; + System.arraycopy(data, 0, newData, 0, used); + data = newData; + } + int got = is.read(data, used, data.length - used); + if (got <= 0) + break; + used += got; + } + return charsetName != null ? new String(data, 0, used, charsetName) + : new String(data, 0, used); + } finally { + is.close(); + } + } + + private ArrayList downloadFiles(ProviderItem current_provider_item) { + ArrayList paths_to_downloaded_files = new ArrayList(); + + paths_to_downloaded_files.add(downloadProviderJSON("provider_json", current_provider_item.provider_json_url, Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_provider.json")); + paths_to_downloaded_files.add(downloadProviderJSON("eip_service_json", current_provider_item.eip_service_json_url, Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_eip-service.json")); + + return paths_to_downloaded_files; + } + + private String downloadProviderJSON(String type, String json_url, String target_directory, String filename) { + + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(json_url)); + request.setDescription("Downloading JSON file"); + request.setTitle("JSON file"); + // in order for this if to run, you must use the android 3.2 to compile your app + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + request.allowScanningByMediaScanner(); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + } + //request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_provider.json"); + request.setDestinationInExternalPublicDir(target_directory, filename); + + // get download service and enqueue file + DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); + manager.enqueue(request); + return type + ":" + target_directory + "/" + filename; + + } +} diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java new file mode 100644 index 00000000..1fe60159 --- /dev/null +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -0,0 +1,77 @@ +package se.leap.leapclient; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.JSONException; +import org.json.JSONObject; + + +public class ProviderListContent { + + /** + * An array of sample (dummy) items. + */ + public static List ITEMS = new ArrayList(); + + /** + * A map of sample (dummy) items, by ID. + */ + public static Map ITEM_MAP = new HashMap(); + + static { + //addItem(new ProviderItem("1", "bitmask", "https://bitmask.net/provider.json", "https://api.bitmask.net:4430/1/config/eip-service.json")); + } + + public static void addItem(ProviderItem item) { + ITEMS.add(item); + ITEM_MAP.put(String.valueOf(ITEMS.size()), item); + } + + /** + * A dummy item representing a piece of content. + */ + public static class ProviderItem { + public String id; + public String name; + public String provider_json_url; + public String eip_service_json_url; + + + public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url) { + this.id = id; + this.name = name; + this.provider_json_url = provider_json_url; + this.eip_service_json_url = eip_service_json_url; + } + + public ProviderItem(String name, InputStream urls_file_input_stream) { + + try { + byte[] urls_file_bytes = new byte[urls_file_input_stream.available()]; + urls_file_input_stream.read(urls_file_bytes); + String urls_file_content = new String(urls_file_bytes); + JSONObject file_contents = new JSONObject(urls_file_content); + id = name; + this.name = name; + provider_json_url = (String) file_contents.get("json_provider"); + eip_service_json_url = (String) file_contents.get("json_eip_service"); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java new file mode 100644 index 00000000..717a65c1 --- /dev/null +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -0,0 +1,150 @@ +package se.leap.leapclient; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import se.leap.leapclient.ProviderListContent; + +/** + * A list fragment representing a list of Providers. This fragment + * also supports tablet devices by allowing list items to be given an + * 'activated' state upon selection. This helps indicate which item is + * currently being viewed in a {@link DashboardFragment}. + *

+ * Activities containing this fragment MUST implement the {@link Callbacks} + * interface. + */ +public class ProviderListFragment extends ListFragment { + + /** + * The serialization (saved instance state) Bundle key representing the + * activated item position. Only used on tablets. + */ + private static final String STATE_ACTIVATED_POSITION = "activated_position"; + + /** + * The fragment's current callback object, which is notified of list item + * clicks. + */ + private Callbacks mCallbacks = sDummyCallbacks; + + /** + * The current activated item position. Only used on tablets. + */ + private int mActivatedPosition = ListView.INVALID_POSITION; + + /** + * A callback interface that all activities containing this fragment must + * implement. This mechanism allows activities to be notified of item + * selections. + */ + public interface Callbacks { + /** + * Callback for when an item has been selected. + */ + public void onItemSelected(String id); + } + + /** + * A dummy implementation of the {@link Callbacks} interface that does + * nothing. Used only when this fragment is not attached to an activity. + */ + private static Callbacks sDummyCallbacks = new Callbacks() { + @Override + public void onItemSelected(String id) { + } + }; + + /** + * Mandatory empty constructor for the fragment manager to instantiate the + * fragment (e.g. upon screen orientation changes). + */ + public ProviderListFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setListAdapter(new ArrayAdapter( + getActivity(), + android.R.layout.simple_list_item_activated_1, + android.R.id.text1, + ProviderListContent.ITEMS)); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + // Restore the previously serialized activated item position. + if (savedInstanceState != null + && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { + setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION)); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + // Activities containing this fragment must implement its callbacks. + if (!(activity instanceof Callbacks)) { + throw new IllegalStateException("Activity must implement fragment's callbacks."); + } + + mCallbacks = (Callbacks) activity; + } + + @Override + public void onDetach() { + super.onDetach(); + + // Reset the active callbacks interface to the dummy implementation. + mCallbacks = sDummyCallbacks; + } + + @Override + public void onListItemClick(ListView listView, View view, int position, long id) { + super.onListItemClick(listView, view, position, id); + + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mCallbacks.onItemSelected(ProviderListContent.ITEMS.get(position).id); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mActivatedPosition != ListView.INVALID_POSITION) { + // Serialize and persist the activated item position. + outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); + } + } + + /** + * Turns on activate-on-click mode. When this mode is on, list items will be + * given the 'activated' state when touched. + */ + public void setActivateOnItemClick(boolean activateOnItemClick) { + // When setting CHOICE_MODE_SINGLE, ListView will automatically + // give items the 'activated' state when touched. + getListView().setChoiceMode(activateOnItemClick + ? ListView.CHOICE_MODE_SINGLE + : ListView.CHOICE_MODE_NONE); + } + + private void setActivatedPosition(int position) { + if (position == ListView.INVALID_POSITION) { + getListView().setItemChecked(mActivatedPosition, false); + } else { + getListView().setItemChecked(position, true); + } + + mActivatedPosition = position; + } +} -- cgit v1.2.3