This document provides steps for developing an Android app to access files stored on a FlashAir wireless storage device. It describes how to set up an Android project, access the FlashAir over WiFi, display a list of files with thumbnails, and download images. Key steps include using the FlashAir API to get file metadata and thumbnails, displaying files in a ListView, adding the Volley library to load network images, and using DownloadManager to download files to the device.
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
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
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();
}
}
...
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;
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;
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);
}
35. 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/
36. 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
38. 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
39. 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!
45. 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;
}
}
...
48. 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
49. 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.
51. 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();
52. 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());
53. 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);
}
...