1

This is my first Android app, so please do go easy on me. The idea is to detect whenever user puts a photo in /mnt/sdcard and upload that to Imgur and then copy the link to system clipboard.

Classes in use

I have three classes working in my app. ObserveNewImages uses FileObserver to detect new photos in the previously stated path.

ObserveImages.java

public class ObserveNewImages extends Service {

final String pathToObserve = android.os.Environment.getExternalStorageDirectory().toString(); // stores "/mnt/sdcard"
final String upload_to = "https://api.imgur.com/3/upload.json";
final String API_key = "API_KEY_GOES_HERE";
public static final String TAG = "Awais";


String link; //full path to where the image is stored
Intent upload;


@Override
public void onCreate(){
    upload = new Intent(this, Imgur.class); //just initializing an intent for use later. Nothing special.
    super.onCreate();
}



@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "In onStartCommand");
    FileObserver observer = new FileObserver(pathToObserve){
        //As soon as we detect a new file in pathToObserve
            //, I fire up the service for uploading image to Imgur.

        @Override
        public void onEvent(int event, String file){
            if (event == FileObserver.CREATE){
                Log.d(TAG, "file address: " + pathToObserve + "/" + file);
                link = pathToObserve + "/" + file;
                upload.putExtra("path",link);
                startService(upload);
            }

        }
    };

    observer.startWatching();

    return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}
}

Moving on to Imgur.java which includes two classes Imgur.class and a ImgurTask which extends AsyncTask so that networking tasks take place on separate thread.

Imgur.java

public class Imgur extends Service{

String path;

@Override
public void onCreate() {
    // TODO Auto-generated method stub
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    path = intent.getStringExtra("path");
    new ImgurTask().execute(path); 

    return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}

class ImgurTask extends AsyncTask<String, Void, String>{


    final String upload_to = "https://api.imgur.com/3/upload.json";
    final String API_key = "API_KEY_GOES_HERE";
    public static final String TAG = "Awais";
    String link;


    @Override
    protected String doInBackground(String... params) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpContext localContext = new BasicHttpContext();
        HttpPost httpPost = new HttpPost(upload_to);
        httpPost.setHeader("Authorization", "Client-ID " + API_key);        


        try {
            MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

            entity.addPart("image", new FileBody(new File(params[0])));
            entity.addPart("key", new StringBody(API_key));

            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost, localContext);

            String response_string = EntityUtils.toString(response.getEntity());
            Log.d(TAG, "Response from Imgur: " + response_string);
            JSONObject json = new JSONObject(response_string);

            //Parsing JSON manually since I couldn't get it work using JSONObject's built-in class functions
            String json_str = json.toString();
            Integer indexlink = json_str.indexOf("link");

            Integer colonlink = json_str.indexOf(":", indexlink);
            Integer secondbracket = json_str.indexOf("}", colonlink);
            link = json_str.substring(colonlink+2, secondbracket-1);

            link = link.replace("\\","");

            return link;

        }catch (Exception e){
            e.printStackTrace();
        }
        return "error";
    }

    @Override
    protected void onPostExecute(String result) {
        if (result != "error"){
                            //copying link to clipboard
            ClipboardManager clipboard = (ClipboardManager)getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE); 
            ClipData clip = ClipData.newPlainText("Imgur link", result);
            clipboard.setPrimaryClip(clip);
            Toast.makeText(getApplicationContext(), "Link is ready to paste: " + result, Toast.LENGTH_SHORT).show();

        }
        else{
            Toast.makeText(getApplicationContext(), "Error: Are you connected to the Internet?", Toast.LENGTH_SHORT).show();
        }
        super.onPostExecute(result);
    }
}
}

MainActivity.java

This is only used to fire up the ObserveImages service.

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //start service
    Intent start_observing = new Intent(this, ObserveImages.class);
    startService(start_observing);
    Toast.makeText(getApplicationContext(), "Automatic Image Uploader is now running!", Toast.LENGTH_SHORT).show();
    finish();
}

}

The Problems

There are three problems:

  • The services just stop working after a while. Nothing shows up the logs (which I have removed from the code here) to indicate that the app is running. To get things running again, I have to launch from app icon again.

  • After a few uploads (sometimes 4-5, sometimes up to 10), Imgur's servers send a 405 Not Allowed response. Leave the app for a minute and come back again, and the servers will send back correct response.

  • The app crashes after a while. FileObserver class throws a Null Pointer Exception.

Awais Imran
  • 85
  • 2
  • 4
  • For point 1: the services may be dying automatically after a while. Don't know why that happens. I've even tried startForeground() but that didn't help. Point 2: This *might* be due to the fact that we are testing it by pushing one image after the other in quick succession. Imgur may have some API limitations in place, but I couldn't find it in their documentation. Point 3: No idea why it happens at all. – Awais Imran May 27 '13 at 21:56

1 Answers1

0

per the timeout problem, it's built into the API.

  • access_token: is your secret key used to access the user's data. It can be thought of the user's password and username combined into one, and is used to access the user's account. It expires after 1 hour.

I don't know what's going on with the other two though. Could you share the error stack for the FileObserver issue? It would probably help.

Having auto upload to Imgur is a really neat idea. Don't forget the rate limits however ( 1,250 uploads per day or approximately 12,500 requests per day). Perhaps even include some handling that may notify the user when they start to near one or the other limit (though I don't really see how anyone ever could as they're exceptionally generous).

adamellsworth
  • 361
  • 1
  • 3
  • 15