• Like
FlashAir Android App Development
Upcoming SlideShare
Loading in...5
×

FlashAir Android App Development

  • 9,168 views
Uploaded on

This slides were used for the FlashAir x Android App Development Workshop held in Tokyo. The APIs, development tutorials, and Q&A forum for FlashAir Android App Development are now available for free …

This slides were used for the FlashAir x Android App Development Workshop held in Tokyo. The APIs, development tutorials, and Q&A forum for FlashAir Android App Development are now available for free on "FlashAir Developers" > https://flashair-developers.com

More in: Technology , Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
9,168
On Slideshare
0
From Embeds
0
Number of Embeds
9

Actions

Shares
Downloads
22
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • {}

Transcript

  • 1. FlashAir Android App Development Sep. 18 2013 Yuki Anzai uPhyca Inc.
  • 2. Steps • Access the FlashAir • Display a list of files stored on the FlashAir • Display thumbnail images • Download images
  • 3. Set up a Project
  • 4. • [File] - [New] - [Android Application Project] • Application Name: FlashAirSample • Project Name: FlashAirSample • Package Name: com.example.flashairsample • Mininum Required SDK: API 9 • Use default settings for everything else
  • 5. Access the FlashAir
  • 6. Access the FlashAir #1 • Connect your Android device to the FlashAir's wireless network. • Create a shortcut to open the WiFi configuration window.
  • 7. res/menu/main.xml <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_wifi_settings" android:showAsAction="never" android:title="@string/action_wifi_settings"/> </menu> res/values/strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> ... <string name="action_wifi_settings">WiFi Settings</string> </resources>
  • 8. MainActivity.java public class MainActivity extends Activity { ... @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } } @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId) { case R.id.action_wifi_settings: Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); startActivity(intent); return true; } return super.onOptionsItemSelected(item); }
  • 9. Access the FlashAir #2 • Since the FlashAir uses HTTP, your app will require android.permission.INTERNET. • • Default SSID: flashair_xxxxx Default Password: 12345678
  • 10. AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.flashairsample" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.INTERNET"/> ... </manifest>
  • 11. Access the FlashAir #3 • • Use a library project FlashAirDev • • • • https://github.com/yanzm/FlashAirDev git clone https://github.com/yanzm/FlashAirDev.git [File] - [Import] - [Android] - [Existing Android Code Into Workspace] Select root directory: • Set FlashAirDev folder
  • 12. Access FlashAir #4 • • Add the FlashAirDev library project [Android] - [Library] - [Add] • Select FlashAirDev
  • 13. Access FlashAir #5 • • • • To get the number of files in a folder: Use http://flashair/command.cgi?op=101&DIR=[path] The number of files will be returned See: https://www.flashairdevelopers.com/ja/documents/api/commandcgi/#101
  • 14. res/layout/activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" ... tools:context=".MainActivity" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
  • 15. res/menu/main.xml <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_reload" android:showAsAction="ifRoom" android:title="@string/action_reload"/> ... </menu> res/values/strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> ... <string name="action_reload">Reload</string> <string name="image_count_format">%1$d images</string> </resources>
  • 16. MainActivity.java public class MainActivity extends Activity { ... @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId) { ... case R.id.action_reload: String dir = "/DCIM"; getFileCount(dir); return true; } return super.onOptionsItemSelected(item); } ... }
  • 17. MainActivity.java public class MainActivity extends Activity { ... private void getFileCount(final String dir) { new AsyncTask<Void, Void, Integer>() { @Override protected Integer doInBackground(Void... params) { return FlashAirUtils.getFileCount(dir); } } } @Override protected void onPostExecute(Integer result) { TextView tv = (TextView) findViewById(R.id.textView1); tv.setText(getString(R.string.image_count_format, result)); } }.execute();
  • 18. FlashAirUtils.java Get the number of files public class FlashAirUtils { public static final String BASE = "http://flashair/"; public static final String COMMAND = BASE + "command.cgi?"; public static final String FILE_COUNT = COMMAND + "op=101&DIR="; public static int getFileCount(String dir) { try { String result = Utils.accessToFlashAir(FILE_COUNT + dir); return Integer.parseInt(result); } catch (NumberFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } return -1; ...
  • 19. Utils.java For HTTP Access public class Utils { public static String accessToFlashAir(String uri) throws IOException { URL url = new URL(uri); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); String result = null; try { InputStream in = new BufferedInputStream(urlConnection.getInputStream()); result = inputStreamToString(in); in.close(); } finally { urlConnection.disconnect(); } } } return result; ...
  • 20. Utils.java For HTTP Access public class Utils { ... private static String inputStreamToString(InputStream stream) throws IOException { Reader reader = new InputStreamReader(stream, "UTF-8"); StringBuilder sb = new StringBuilder(); char[] buffer = new char[1024]; int num; while (0 < (num = reader.read(buffer))) { sb.append(buffer, 0, num); } return sb.toString(); } } ...
  • 21. Display a list of files stored on the FlashAir
  • 22. Display a list of files #1 • • • Get a list of the DCIM folder • <directory>,<file name>,<file size>,<attribute>,<date>,and <time> are returned. • • e.g. /DCIM,100__TSB,0,16,9944,129 Use: http://flashair/command.cgi?op=100&DIR=[path] See: https://www.flashairdevelopers.com/ja/documents/api/commandcgi/#100 NOTE: A comma could be returned as part of a filename.
  • 23. Display a list of files #2 • • • • • • • • The file's size is in bytes Attribute is a 16-bit integer Bit 5 : Archive Bit 4 : Directly Bit 3 : Volume Bit 2 : System file Bit 1 : Hidden file Bit 0 : Read only
  • 24. Display a list of files #3 • Date is also a 16-bit integer • • • • Bit 15-9 : A value based on 0 as a 1980 Bit 8-5 : Month from 1 to 12 Bit 4-0 : Day from 1 to 31 So is the Timestamp • • • Bit 15-11 : Hour Bit 10-5 : Minute Bit 4-0 : Second/2
  • 25. FlashAirFileInfo.java Class for a file information public class FlashAirFileInfo { public FlashAirFileInfo(String info, String dir) { int start; int end; start = info.lastIndexOf(","); int time = Integer.parseInt(info.substring(start + 1).trim()); end = start; start = info.lastIndexOf(",", end - 1); int date = Integer.parseInt(info.substring(start + 1, end).trim()); end = start; start = info.lastIndexOf(",", end - 1); mAttribute = Integer.parseInt(info.substring(start + 1, end).trim()); end = start; start = info.lastIndexOf(",", end - 1); mSize = info.substring(start + 1, end); ... end = start; start = info.indexOf(",", dir.length()); mFileName = info.substring(start + 1, end);
  • 26. FlashAirFileInfo.java ... Class for a file information mDir = dir; int year = ((date >> 9) & 0x0000007f) + 1980; int month = (date >> 5) & 0x0000000f - 1; int day = (date) & 0x0000001f; int hourOfDay = (time >> 11) & 0x0000001f; int minute = (time >> 5) & 0x0000003f; int second = ((time) & 0x0000001f) * 2; } mCalendar = Calendar.getInstance(); mCalendar.set(year, month, day, hourOfDay, minute, second); public public public public public ... String mDir; String mFileName; String mSize; int mAttribute; Calendar mCalendar;
  • 27. FlashAirFileInfo.java ... public public public public public public static static static static static static final final final final final final int int int int int int Class for a file information ATTR_MASK_ARCHIVE = 0x00000020; ATTR_MASK_DIRECTORY = 0x00000010; ATTR_MASK_VOLUME = 0x00000008; ATTR_MASK_SYSTEM_FILE = 0x00000004; ATTR_MASK_HIDDEN_FILE = 0x00000002; ATTR_MASK_READ_ONLY = 0x00000001; public boolean isDirectory() { return (mAttribute & ATTR_MASK_DIRECTORY) > 0; } } @Override public String toString() { return "DIR=" + mDir + " FILENAME=" + mFileName + " SIZE=" + mSize + " ATTRIBUTE=" + mAttribute + " DATE=" + DateFormat.format("yyyy-MM-dd kk:mm:ss", mCalendar); }
  • 28. FlashAirUtils.java Get a file information public class FlashAirUtils { ... public static List<FlashAirFileInfo> getFileList(String dir) { try { String result = Utils.accessToFlashAir(FILE_LIST + dir); if (TextUtils.isEmpty(result)) { return null; } ... ArrayList<FlashAirFileInfo> list = new ArrayList<FlashAirFileInfo>(); for (String line : result.split("¥n")) { if (TextUtils.isEmpty(line)) { continue; } if (line.split(",").length < 6) { continue; } FlashAirFileInfo info = new FlashAirFileInfo(line, dir); list.add(info); } return list;
  • 29. FlashAirUtils.java ... } catch (IOException e) { e.printStackTrace(); } } return null; Get a file information
  • 30. res/layout/activity_main.xml Add ListView <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" ... tools:context=".MainActivity" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/textView1" /> </RelativeLayout>
  • 31. MainActivity.java public class MainActivity extends Activity { ... @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId) { ... case R.id.action_reload: String dir = "/DCIM"; getFileCount(dir); getFileList(dir); return true; } return super.onOptionsItemSelected(item); } ... } Get a file list
  • 32. MainActivity.java Set a file list to ListView public class MainActivity extends Activity { ... private void getFileList(final String dir) { new AsyncTask<Void, Void, List<FlashAirFileInfo>>() { @Override protected List<FlashAirFileInfo> doInBackground(Void... params) { return FlashAirUtils.getFileList(dir); } } @Override protected void onPostExecute(List<FlashAirFileInfo> result) { ListView lv = (ListView) findViewById(R.id.listView1); lv.setAdapter(new FileListAdapter(MainActivity.this, result)); } }.execute(); public class FileListAdapter extends ArrayAdapter<FlashAirFileInfo> { } } public FileListAdapter(Context context, List<FlashAirFileInfo> data) { super(context, android.R.layout.simple_list_item_1, data); }
  • 33. Display thumbnail of images
  • 34. Display thumbnails #1 • • • • To get thumbnails from image files: • Thumbnail images are defined by EXIF standard, and are only available in JPEG format • If a file is not JPEG or no thumbnails are defined, a 404 error is returned Use http://flashair/thumbnail.cgi?[path] e.g. http://flashair/thumbnail.cgi?/DCIM/IMG_xxx.jpg See: https://www.flashairdevelopers.com/ja/documents/api/thumbnailcgi/
  • 35. Display thumbnails #2 • • Display the thumbnails in a ListView Use Volley! • • A network processing library for Android • http://y-anz-m.blogspot.jp/2013/05/google-io-2013android-volley-easy-fast.html • NetworkImageView is available https://android.googlesource.com/platform/frameworks/v olley/ • NetworkImageView is an ImageView with communication processing
  • 36. Display thumbnails #3 • NetworkImagView of Vollay • • <com.android.volley.toolbox.NetworkImageView> setImageUrl(String url, ImageLoader loader)
  • 37. Display thumbnails #4 • Volley is a library project, so we need to add it. • git clone https://android.googlesource.com/platform/frameworks/vo lley • [File] - [Import] - [Android] - [Existing Android Code Into Workspace] • Select root directory: • Set volley folder
  • 38. Display thumbnails #5 • • Open Properties for FlashAirSample [Android] - [Library] - [Add] • Select volley If Volley is not appear on the list, make sure Is Library od Volley project is checked!
  • 39. res/layout/list_row.xml Layout for list <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <com.android.volley.toolbox.NetworkImageView android:id="@+id/imageView1" android:layout_width="100dp" android:layout_height="80dp" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text" android:textAppearance="?android:attr/textAppearanceMedium" /> </LinearLayout>
  • 40. MainActivity.java Prepare Volley public class MainActivity extends Activity { private RequestQueue mQueue; private ImageLoader mImageLoader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mQueue = Volley.newRequestQueue(getApplicationContext()); mImageLoader = new ImageLoader(mQueue, new BitmapCache()); } ...
  • 41. MainActivity.java Prepare Volley ... public class BitmapCache implements ImageCache { private LruCache<String, Bitmap> mCache; public BitmapCache() { int maxSize = 5 * 1024 * 1024; // 5MB mCache = new LruCache<String, Bitmap>(maxSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; } @Override public Bitmap getBitmap(String url) { return mCache.get(url); } } @Override public void putBitmap(String url, Bitmap bitmap) { mCache.put(url, bitmap); }
  • 42. MainActivity.java Expand Adapter for list public class MainActivity extends Activity { ... public class FileListAdapter extends ArrayAdapter<FlashAirFileInfo> { LayoutInflater mInflater; public FileListAdapter(Context context, List<FlashAirFileInfo> data) { super(context, 0, data); mInflater = LayoutInflater.from(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.list_row, parent, false); } FlashAirFileInfo item = getItem(position); TextView tv = (TextView) convertView.findViewById(R.id.textView1); tv.setText(item.mFileName); ...
  • 43. MainActivity.java Set URL at NetworkImageView ... NetworkImageView niv = (NetworkImageView) convertView .findViewById(R.id.imageView1); } } } if (item.mFileName.endsWith(".jpg") || item.mFileName.endsWith(".jpeg")) { niv.setImageUrl( FlashAirUtils.getThumbnailUrl(item.mDir, item.mFileName), mImageLoader); } else { niv.setImageUrl(null, mImageLoader); } return convertView;
  • 44. FlashAirUtils.java public class FlashAirUtils { public static final String BASE = "http://flashair/"; public static final String THUMBNAIL = BASE + "thumbnail.cgi?"; public static String getThumbnailUrl(String dir, String fileName) { return THUMBNAIL + dir + "/" + fileName; } } ...
  • 45. Download images
  • 46. Download images #1 • • • • To get an image file Use http://flashair/[path] e.g. http://flashair/DCIM/IMG_xxx.jpg Use DownloadManager • http://developer.android.com/reference/android/app/Dow nloadManager.html
  • 47. Download images #2 • Using DownloadManager • • Create a download request with Request request = new DownloadManager.Request(uri) • • Get an instance with getSystemService(Context.DOWNLOAD_SERVICE) Add the request with downloadManager.enqueue(request) To save image to your device, you will need android.permission.WRITE_EXTERNAL_STORAGE.
  • 48. AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.flashairsample" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
  • 49. MainActivity.java Set Listener in list public class MainActivity extends Activity implements OnItemClickListener { ... private void getFileList(final String dir) { new AsyncTask<Void, Void, List<FlashAirFileInfo>>() { @Override protected List<FlashAirFileInfo> doInBackground(Void... params) { return FlashAirUtils.getFileList(dir); } } ... @Override protected void onPostExecute(List<FlashAirFileInfo> result) { ListView lv = (ListView) findViewById(R.id.listView1); lv.setAdapter(new FileListAdapter(MainActivity.this, result)); lv.setOnItemClickListener(MainActivity.this); } }.execute();
  • 50. MainActivity.java Set Listener in list public class MainActivity extends Activity implements OnItemClickListener { ... @Override public void onItemClick(AdapterView<?> adapter, View v, int position, long l) { FlashAirFileInfo info = (FlashAirFileInfo) adapter .getItemAtPosition(position); File path = Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); File file = new File(path, info.mFileName); if (!file.exists()) { startDownload(info); return; } } ... openDownloadedFile(file.toString());
  • 51. MainActivity.java ... private void openDownloadedFile(String filePath) { MediaScannerConnection.scanFile(this, new String[] { filePath }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); startActivity(intent); } }); } private void startDownload(FlashAirFileInfo info) { Uri uri = FlashAirUtils.getFileUri(info.mDir, info.mFileName); DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request(uri); request.allowScanningByMediaScanner(); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DCIM, info.mFileName); manager.enqueue(request); } ...
  • 52. MainActivity.java ... @Override protected void onResume() { super.onResume(); IntentFilter filter = new IntentFilter( DownloadManager.ACTION_DOWNLOAD_COMPLETE); registerReceiver(receiver, filter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(receiver); } ...
  • 53. MainActivity.java ... BroadcastReceiver receiver = new BroadcastReceiver() { } @Override public void onReceive(Context context, Intent intent) { long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); if (id > 0) { DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); Uri fileUri = manager.getUriForDownloadedFile(id); openDownloadedFile(fileUri.getPath()); } } };