I am trying to build an android application where I am using google cloud vision API for detecting faces. I am following this tutorial. The problem is that, I am unable to produce the toast message that was supposed to be displayed on the screen after I click the button but the logcat shows:
Attempt to invoke virtual method 'com.google.api.services.vision.v1.Vision$Images com.google.api.services.vision.v1.Vision.images()' on a null object reference
Here is the code :
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button upload_button;
private ImageView image_capture;
final int CAMERA_PIC_REQUEST = 100;
private Vision vision;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
upload_button = (Button) findViewById(R.id.uploadb);
image_capture=(ImageView)findViewById(R.id.capturedImage);
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{android.Manifest.permission.CAMERA},
5);
}
}
Vision.Builder visionBuilder = new Vision.Builder(
new NetHttpTransport(),
new AndroidJsonFactory(),
null);
visionBuilder.setVisionRequestInitializer(
new VisionRequestInitializer("AIzaSyAueQjrrY_GiXh7kNGlbDLKWhYP-4q77vI"));
Vision vision = visionBuilder.build();
upload_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);*/
imageDectection();
}
});
}
private void imageDectection() {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try {
InputStream inputStream = getResources().openRawResource(R.raw.crewf);
byte[] photoData = IOUtils.toByteArray(inputStream);
Image inputImage = new Image();
inputImage.encodeContent(photoData);
Feature desiredFeature = new Feature();
desiredFeature.setType("FACE_DETECTION");
AnnotateImageRequest request = new AnnotateImageRequest();
request.setImage(inputImage);
request.setFeatures(Arrays.asList(desiredFeature));
BatchAnnotateImagesRequest batchRequest = new BatchAnnotateImagesRequest();
batchRequest.setRequests(Arrays.asList(request));
BatchAnnotateImagesResponse batchResponse =
vision.images().annotate(batchRequest).execute();
List<FaceAnnotation> faces = batchResponse.getResponses()
.get(0).getFaceAnnotations();
int numberOfFaces = faces.size();
String likelihoods = "";
for(int i=0; i<numberOfFaces; i++) {
likelihoods += "\n It is " +
faces.get(i).getJoyLikelihood() +
" that face " + i + " is happy";
}
final String message =
"This photo has " + numberOfFaces + " faces" + likelihoods;
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),
message, Toast.LENGTH_LONG).show();
}
});
} catch(Exception e) {
Log.d("ERROR", e.getMessage());
}
}
});
}
}
The picture is stored in /res/raw location as crewf.jpg. I have tried setting the types as LABEL_DETECTION,TEXT_DETECTION,LANDMARK_DETECTION but none of it works.
Can anyone help me in this?
You are not initializing the Vision object.
You should declare two class variables:
private Vision.Builder visionBuilder = new Vision.Builder(
new NetHttpTransport(),
new AndroidJsonFactory(),
null
).setVisionRequestInitializer(new VisionRequestInitializer(BuildConfig.GOOGLE_API_KEY));
private Vision vision;
Then on the onCreate build the object:
vision = visionBuilder.build();
After that, you're ready to go.
If you're still facing troubles email me, I could help you reviewing your code.
Related
I am having a bit of trouble trying to utilize the default Android dialog for popping up networks listed in the area. I have done some research and tried different avenues, but I haven't found anything that works correctly.
WifiManager mWifiManager;
List<ScanResult> mScanResults;
WifiListAdapter wifiListAdapter;
TextView hiddenVersionNumber;
String connectedSSID = "";
ProgressBar wifiNetworksLoading;
ArrayList<WifiItem> networkList = new ArrayList<>();
private static final int WEAK_WIFI_SIGNAL_STRENGTH = 1;
private final BroadcastReceiver mWifiScanReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
List<ScanResult>mScanResults = mWifiManager.getScanResults();
//*unregisterReceiver(mWifiScanReceiver);*//
Log.d(TAG, "bozo " + mScanResults.size());
//*networkList.clear();
if (wifiNetworksLoading != null) {
wifiNetworksLoading.setVisibility(View.GONE);
}*//
ArrayList<WifiItem> list = new ArrayList<>();
for (ScanResult scan : mScanResults) {
//*Log.d(TAG, "bozo3 " + scan.SSID);*//
int level = WifiManager.calculateSignalLevel(scan.level, 4);
boolean isConnected = false;
Log.d(TAG, "bozo2 " + connectedSSID);
if (!connectedSSID.isEmpty()) {
Log.d(TAG, "bozo2 " + connectedSSID + " = " + scan.SSID);
if (connectedSSID.equalsIgnoreCase(scan.SSID)) {
isConnected = true;
}
}
if (!scan.SSID.isEmpty()) {
networkList.add(new WifiItem(scan.SSID, scan.capabilities, level, isConnected));
}
}
The OnCreate code listed below...
mWifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
//*registerReceiver(mWifiScanReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));*//
mWifiManager.startScan();
if (mWifiManager != null) {
mWifiManager.setWifiEnabled(true); // turn on Wifi
}
I am new to Google AR core and Sceneform. I want to develop a basic fps game on Android Studio, when user touches anywhere on the screen AR object will be created and if button is pushed, a ray will be shot from the center of the screen and if the ray hits to any created AR object, the score will increase.
The code is below, but i cannot continue more. How can i do?
public class MainActivity extends AppCompatActivity{
private static final String TAG = MainActivity.class.getSimpleName();
private static final double MIN_OPENGL_VERSION = 3.0;
private ArFragment arFragment;
private ModelRenderable mRenderable;
private ImageButton imageButton;
private TextView scoreText;
private int score=0;
private Set<Vector3> position = new HashSet<Vector3>();
// Set<Vector3> obj_set = new HashSet<Vector3>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!checkIsSupportedDeviceOrFinish(this)) {
return;
}
setContentView(R.layout.activity_main);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
imageButton = (ImageButton) findViewById(R.id.imageButton);
scoreText = (TextView) findViewById(R.id.scoreText);
setUpModel();
setUpPlane();
imageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
Camera camera = arFragment.getArSceneView().getScene().getCamera();
Ray ray = new Ray(camera.getWorldPosition(),camera.getForward());
HitTestResult result = arFragment.getArSceneView().getScene().hitTest(ray);
if (result.getNode() != null && result.getDistance() < 0) {
// Hit something
//doSomething(result.getNode());
Log.e(TAG,"RAYCASTING ERROR");
}else{
Iterator value = position.iterator();
while(value.hasNext()){
if(position.equals(result.getPoint())){
Toast.makeText(getApplicationContext(),"HIT WAS DETECTED",Toast.LENGTH_SHORT).show();
score = score + 5;
scoreText.setText("SCORE: " + score + "");
Log.e(TAG,"HEY THERE");
}
else{
Log.e(TAG,"NOOOOOOO");
}
}
}
} catch (Exception e) {
Log.e(TAG, "ERROR ON BUTTON");
}
}
});
}
private void setUpModel() { //Load the model
WeakReference<MainActivity> weakActivity = new WeakReference<>(this);
ModelRenderable.builder()
.setSource(this, R.raw.model)
.setIsFilamentGltf(true)
.build()
.thenAccept(modelRenderable -> {
MainActivity activity = weakActivity.get();
if (activity != null) {
mRenderable = modelRenderable;
}
})
.exceptionally(throwable -> {
Toast.makeText(MainActivity.this, "Model can not be loaded!", Toast.LENGTH_SHORT).show();
return null;
});
}
private void setUpPlane() {//Attach the scene to the node
arFragment.setOnTapArPlaneListener(new BaseArFragment.OnTapArPlaneListener() {
#Override
public void onTapPlane(HitResult hitResult, Plane plane, MotionEvent motionEvent) {
// Creates the anchor
Anchor anchor = hitResult.createAnchor();
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
createModel(anchorNode);
}
});
}
private void createModel(AnchorNode anchorNode) {// Create the transformable model and add it to the anchor
TransformableNode node = new TransformableNode(arFragment.getTransformationSystem());
node.setParent(anchorNode);
node.setRenderable(mRenderable);
node.select();
position.add(anchorNode.getWorldPosition());
}
public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.e(TAG, "Sceneform requires Android N or later");
Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show();
activity.finish();
return false;
}
String openGlVersionString =
((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
.getDeviceConfigurationInfo()
.getGlEsVersion();
if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later");
Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG)
.show();
activity.finish();
return false;
}
return true;
}
}
I'm not sure if I fully understood what you want to achieve but if you want to increase score when user points towards the object and presses button then you could check just that the result != null and then do your action, why do you have the hit detection logic in the else part? So you could have:
...
HitTestResult result = arFragment.getArSceneView().getScene().hitTest(ray);
if (result.getNode() != null) {
// Hit something
Toast.makeText(getApplicationContext(),"HIT WAS DETECTED",Toast.LENGTH_SHORT).show();
score = score + 5;
scoreText.setText("SCORE: " + score + "");
}
...
This will of course keep the score increasing as long as the user points towards the object.
I am developing app using camera on fragment,so for camera I have used this library https://natario1.github.io/CameraView/home because I am using watermarks in camera, now I want to save pictures and videos to gallery, for pictures I have done with below code, for video I done research but not get a solution, for pictures this library is giving bitmap so pictures are saving perfectly but for video I can't figure out kindly help me.
Thank you
public class VideoPreviewActivity extends AppCompatActivity {
private VideoView videoView;
private static VideoResult videoResult;
private Button btnSaveVideo;
public static void setVideoResult(#Nullable VideoResult result) {
videoResult = result;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_preview);
final VideoResult result = videoResult;
if (result == null) {
finish();
return;
}
btnSaveVideo = findViewById(R.id.save_video);
videoView = findViewById(R.id.video);
videoView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
playVideo();
}
});
AspectRatio ratio = AspectRatio.of(result.getSize());
MediaController controller = new MediaController(this);
controller.setAnchorView(videoView);
controller.setMediaPlayer(videoView);
videoView.setMediaController(controller);
videoView.setVideoURI(Uri.fromFile(result.getFile()));
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
ViewGroup.LayoutParams lp = videoView.getLayoutParams();
float videoWidth = mp.getVideoWidth();
float videoHeight = mp.getVideoHeight();
float viewWidth = videoView.getWidth();
lp.height = (int) (viewWidth * (videoHeight / videoWidth));
videoView.setLayoutParams(lp);
playVideo();
if (result.isSnapshot()) {
// Log the real size for debugging reason.
Log.e("VideoPreview", "The video full size is " + videoWidth + "x" + videoHeight);
}
}
});
//Click this button to save video
btnSaveVideo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Calling 1st Method but not working
//SaveVideo(videoResult.getFile().toString());
//2nd method calling but still not working
saveVideoToInternalStorage(videoResult.getFile().toString());
}
});
}
void playVideo() {
if (!videoView.isPlaying()) {
videoView.start();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (!isChangingConfigurations()) {
setVideoResult(null);
}
}
//first method which I tried but not working
private void SaveVideo(Uri f) {
//I don't know what data type I have to pass in the methods parameters
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath();
File myDir = new File(root + "/Push Videos");
if (!myDir.exists()) {
myDir.mkdirs();
}
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Video-"+ n +".mp4";
File file = new File (myDir, fname);
if (file.exists ())
file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
Toast.makeText(VideoPreviewActivity.this, "PUSH Video Saved", Toast.LENGTH_LONG).show();
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//Tried this 2nd method but it is also not giving a desired result
//For saving Video...
private void saveVideoToInternalStorage (String filePath) {
File newfile;
try {
File currentFile = new File(filePath);
String fileName = currentFile.getName();
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir("videoDir", Context.MODE_PRIVATE);
newfile = new File(directory.getAbsolutePath(), fileName);
if(currentFile.exists()){
InputStream in = new FileInputStream(currentFile);
OutputStream out = new FileOutputStream(newfile);
// Copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
scanner(filePath);
in.close();
out.close();
Log.v("", "Video file saved successfully.");
Toast.makeText(this, "Push Video Saved TO Gallery", Toast.LENGTH_SHORT).show();
}else{
Log.v("", "Video saving failed. Source file missing.");
}
} catch (Exception e) {
Log.d("Err ", "EXS " + e.getMessage());
e.printStackTrace();
}
}
}
I am trying to make a translation application from English to Bangla using Yandex API.
It works fine in the emulator but in the real device it shows result for only one word in the text view but when writing a sentence it shows null / nothing.
I think the problem is buffer overflow but don't know how to fix it for the real device. Here are some reference pictures. In the emulator the result works fine:
In the real device it shows empty in text view:
But it works fine when a single word is used in real device.
Here is the code for my Asynctask:
public class
TranslatorBackgroundTask extends AsyncTask<String, Void, String> {
//Declare Context
Context ctx;
//Set Context
TranslatorBackgroundTask(Context ctx){
this.ctx = ctx;
}
String resultString;
#Override
protected String doInBackground(String... params) {
//String variables
String textToBeTranslated = params[0];
String languagePair = params[1];
String jsonString;
try {
//Set up the translation call URL
String yandexKey = "trnsl.1.1.20170823T130435Z.79a583874abfc8ff.61e23593359fdc92452e69a3d5ec05347fc4180b";
String yandexUrl = "https://translate.yandex.net/api/v1.5/tr.json/translate?key=" + yandexKey
+ "&text=" + textToBeTranslated + "&lang=" + languagePair;
URL yandexTranslateURL = new URL(yandexUrl);
//Set Http Conncection, Input Stream, and Buffered Reader
HttpURLConnection httpJsonConnection = (HttpURLConnection) yandexTranslateURL.openConnection();
InputStream inputStream = httpJsonConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//Set string builder and insert retrieved JSON result into it
StringBuilder jsonStringBuilder = new StringBuilder();
while ((jsonString = bufferedReader.readLine()) != null) {
jsonStringBuilder.append(jsonString + "\n");
}
//Close and disconnect
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
inputStream.close();
httpJsonConnection.disconnect();
//Making result human readable
resultString = jsonStringBuilder.toString().trim();
//Getting the characters between [ and ]
resultString = resultString.substring(resultString.indexOf('[')+1);
resultString = resultString.substring(0,resultString.indexOf("]"));
//Getting the characters between " and "
resultString = resultString.substring(resultString.indexOf("\"")+1);
resultString = resultString.substring(0,resultString.indexOf("\""));
Log.d("Translation Result:", resultString);
return jsonStringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//String text = String.valueOf(resultString);
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
MainActivity.tvTranslatedText.setText(resultString);
Toast.makeText(ctx, resultString, Toast.LENGTH_LONG).show();
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
And the code for the main activity:
public class MainActivity extends AppCompatActivity{
Context context=this;
private static final int REQUEST_CODE = 1234;
static TextView tvTranslatedText;
EditText etUserText;
Button buTranslate;
Button buSpeak;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_activity_main);
tvTranslatedText = (TextView)findViewById(R.id.tvTranslatedText);
etUserText = (EditText)findViewById(R.id.etUserText);
buTranslate = (Button)findViewById(R.id.buTranslate);
buSpeak = (Button)findViewById(R.id.buSpeak);
}
public void buTranslate(View view) {
//Default variables for translation
String textToBeTranslated = "";
textToBeTranslated= etUserText.getText().toString();
String languagePair = "en-bn"; //English to bengali ("<source_language>-<target_language>")
//Executing the translation function
Translate(textToBeTranslated,languagePair);
}
//Function for calling executing the Translator Background Task
void Translate(String textToBeTranslated, String languagePair){
TranslatorBackgroundTask translatorBackgroundTask= new TranslatorBackgroundTask(context);
String translationResult = "";
translationResult = String.valueOf(translatorBackgroundTask.execute(textToBeTranslated,languagePair)); // Returns the translated text as a String
Log.d("Translation Result",translationResult); // Logs the result in Android Monitor
}
//Speak button activities
public void buSpeak(View view) {
startVoiceRecognitionActivity();
}
private void startVoiceRecognitionActivity()
{
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak to translate");
startActivityForResult(intent, REQUEST_CODE);
}
/**
* Handle the results from the voice recognition activity.
*/
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
if (data != null) {
//pull all of the matches
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String topResult = matches.get(0);
EditText AutoText = (EditText) findViewById(R.id.etUserText);
AutoText.setText(topResult);
}
}
}
}
The error message:
Caused by: com.google.android.apps.gsa.shared.exception.GsaIOException: Error code: 393238 | Buffer overflow, no available space.
Why didn't you add a listener to your sample code?
Try adding these on onCreate in MainActivity:
buTranslate.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
buTranslate(view);
}
}
);
Update:
There was another issue. Emulators on android sdk 16 don't show Unicode properly. Thats why you don't see your results, as those are Unicodes. Try Log to print your resultString.
The following app upload video to Dropbox when it is start, I added finish() in the end of onCreate to exit the app when its completed the uploading, but I got "Unfortunately, DBRoulette has stopped.".
In the Eclipse LogCat:
Activity com.dropbox.android.sample.DBRoulette has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#42a7ee38 that was originally added here
android.view.WindowLeaked: Activity com.dropbox.android.sample.DBRoulette has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#42a7ee38 that was originally added here
I have Progress viewer which may cause the problem but I don't know how to solve it!
What I want to do is closing the app automatically when the uploading completed.
DBRoulette.java
#SuppressLint("SimpleDateFormat")
public class DBRoulette extends Activity {
private static final String TAG = "DBRoulette";
final static private String APP_KEY = "<My APP_KEY>";
final static private String APP_SECRET = "<My APP_SECRET>";
// You don't need to change these, leave them alone.
final static private String ACCOUNT_PREFS_NAME = "prefs";
final static private String ACCESS_KEY_NAME = "ACCESS_KEY";
final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET";
private static final boolean USE_OAUTH1 = false;
DropboxAPI<AndroidAuthSession> mApi;
private boolean mLoggedIn;
// Android widgets
private Button mSubmit;
private RelativeLayout mDisplay;
private Button mGallery;
private ImageView mImage;
private final String PHOTO_DIR = "/Motion/";
#SuppressWarnings("unused")
final static private int NEW_PICTURE = 50;
private String mCameraFileName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCameraFileName = savedInstanceState.getString("mCameraFileName");
}
// We create a new AuthSession so that we can use the Dropbox API.
AndroidAuthSession session = buildSession();
mApi = new DropboxAPI<AndroidAuthSession>(session);
// Basic Android widgets
setContentView(R.layout.main);
checkAppKeySetup();
mSubmit = (Button) findViewById(R.id.auth_button);
mSubmit.setOnClickListener(new OnClickListener() {
#SuppressWarnings("deprecation")
public void onClick(View v) {
// This logs you out if you're logged in, or vice versa
if (mLoggedIn) {
logOut();
} else {
// Start the remote authentication
if (USE_OAUTH1) {
mApi.getSession().startAuthentication(DBRoulette.this);
} else {
mApi.getSession().startOAuth2Authentication(
DBRoulette.this);
}
}
}
});
mDisplay = (RelativeLayout) findViewById(R.id.logged_in_display);
// This is where a photo is displayed
mImage = (ImageView) findViewById(R.id.image_view);
File outFile = new File("/mnt/sdcard/ipwebcam_videos/video.mov");
mCameraFileName = outFile.toString();
UploadPicture upload = new UploadPicture(DBRoulette.this, mApi, PHOTO_DIR,outFile);
upload.execute();
// Display the proper UI state if logged in or not
setLoggedIn(mApi.getSession().isLinked());
finish();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("mCameraFileName", mCameraFileName);
super.onSaveInstanceState(outState);
}
#Override
protected void onResume() {
super.onResume();
AndroidAuthSession session = mApi.getSession();
if (session.authenticationSuccessful()) {
try {
session.finishAuthentication();
storeAuth(session);
setLoggedIn(true);
} catch (IllegalStateException e) {
showToast("Couldn't authenticate with Dropbox:"
+ e.getLocalizedMessage());
Log.i(TAG, "Error authenticating", e);
}
}
}
private void logOut() {
// Remove credentials from the session
mApi.getSession().unlink();
clearKeys();
// Change UI state to display logged out version
setLoggedIn(false);
}
#SuppressWarnings("deprecation")
public String getRealPathFromURI(Uri contentUri)
{
String[] proj = { MediaStore.Audio.Media.DATA };
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
private void setLoggedIn(boolean loggedIn) {
mLoggedIn = loggedIn;
if (loggedIn) {
mSubmit.setText("Logout from Dropbox");
mDisplay.setVisibility(View.VISIBLE);
} else {
mSubmit.setText("Login with Dropbox");
mDisplay.setVisibility(View.GONE);
mImage.setImageDrawable(null);
}
}
private void checkAppKeySetup() {
// Check to make sure that we have a valid app key
if (APP_KEY.startsWith("CHANGE") || APP_SECRET.startsWith("CHANGE")) {
showToast("You must apply for an app key and secret from developers.dropbox.com, and add them to the DBRoulette ap before trying it.");
finish();
return;
}
// Check if the app has set up its manifest properly.
Intent testIntent = new Intent(Intent.ACTION_VIEW);
String scheme = "db-" + APP_KEY;
String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test";
testIntent.setData(Uri.parse(uri));
PackageManager pm = getPackageManager();
if (0 == pm.queryIntentActivities(testIntent, 0).size()) {
showToast("URL scheme in your app's "
+ "manifest is not set up correctly. You should have a "
+ "com.dropbox.client2.android.AuthActivity with the "
+ "scheme: " + scheme);
finish();
}
}
private void showToast(String msg) {
Toast error = Toast.makeText(this, msg, Toast.LENGTH_LONG);
error.show();
}
/**
* Shows keeping the access keys returned from Trusted Authenticator in a
* local store, rather than storing user name & password, and
* re-authenticating each time (which is not to be done, ever).
*/
private void loadAuth(AndroidAuthSession session) {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
String key = prefs.getString(ACCESS_KEY_NAME, null);
String secret = prefs.getString(ACCESS_SECRET_NAME, null);
if (key == null || secret == null || key.length() == 0
|| secret.length() == 0)
return;
if (key.equals("oauth2:")) {
// If the key is set to "oauth2:", then we can assume the token is
// for OAuth 2.
session.setOAuth2AccessToken(secret);
} else {
// Still support using old OAuth 1 tokens.
session.setAccessTokenPair(new AccessTokenPair(key, secret));
}
}
/**
* Shows keeping the access keys returned from Trusted Authenticator in a
* local store, rather than storing user name & password, and
* re-authenticating each time (which is not to be done, ever).
*/
private void storeAuth(AndroidAuthSession session) {
// Store the OAuth 2 access token, if there is one.
String oauth2AccessToken = session.getOAuth2AccessToken();
if (oauth2AccessToken != null) {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME,
0);
Editor edit = prefs.edit();
edit.putString(ACCESS_KEY_NAME, "oauth2:");
edit.putString(ACCESS_SECRET_NAME, oauth2AccessToken);
edit.commit();
return;
}
// Store the OAuth 1 access token, if there is one. This is only
// necessary if
// you're still using OAuth 1.
AccessTokenPair oauth1AccessToken = session.getAccessTokenPair();
if (oauth1AccessToken != null) {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME,
0);
Editor edit = prefs.edit();
edit.putString(ACCESS_KEY_NAME, oauth1AccessToken.key);
edit.putString(ACCESS_SECRET_NAME, oauth1AccessToken.secret);
edit.commit();
return;
}
}
private void clearKeys() {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
Editor edit = prefs.edit();
edit.clear();
edit.commit();
}
private AndroidAuthSession buildSession() {
AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, APP_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeyPair);
loadAuth(session);
return session;
}
}
UploadPicture.java
public class UploadPicture extends AsyncTask<Void, Long, Boolean> {
private DropboxAPI<?> mApi;
private String mPath;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private final ProgressDialog mDialog;
private String mErrorMsg;
private File outFiles;
public UploadPicture(Context context, DropboxAPI<?> api, String dropboxPath,
File file) {
// We set the context this way so we don't accidentally leak activities
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mPath = dropboxPath;
mFile = file;
Date dates = new Date();
DateFormat dfs = new SimpleDateFormat("yyyyMMdd-kkmmss");
String newPicFiles = dfs.format(dates) + ".mov";
String outPaths = new File(Environment
.getExternalStorageDirectory(), newPicFiles).getPath();
outFiles = new File(outPaths);
mDialog = new ProgressDialog(context);
mDialog.setMax(100);
mDialog.setMessage("Uploading " + outFiles.getName());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setProgress(0);
mDialog.setButton(ProgressDialog.BUTTON_POSITIVE, "Cancel", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// This will cancel the putFile operation
mRequest.abort();
}
});
mDialog.show();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
// By creating a request, we get a handle to the putFile operation,
// so we can cancel it later if we want to
FileInputStream fis = new FileInputStream(mFile);
String path = mPath + outFiles.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
#Override
public long progressInterval() {
// Update the progress bar every half-second or so
return 500;
}
#Override
public void onProgress(long bytes, long total) {
publishProgress(bytes);
}
});
if (mRequest != null) {
mRequest.upload();
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return false;
}
#Override
protected void onProgressUpdate(Long... progress) {
int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
mDialog.setProgress(percent);
}
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
if (result) {
showToast("Image successfully uploaded");
} else {
showToast(mErrorMsg);
}
}
private void showToast(String msg) {
Toast error = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
error.show();
}
}
Your problem is that you are trying to update an Activity's UI after the activity has finished.
First, you kick of an AsyncTask which posts progress updates to the UI thread. Then, before the task completes, you call finish(). Any updates to the Activity's UI after finish() is called are liable to throw exceptions, cause window leak issues, etc.
If you want to have any UI behavior as you perform your AsyncTask, you do not want to finish() the Activity until it the task is completed.
To achieve this, you could include a callback in the onPostExecute which tells the activity it is OK to finish once the AsyncTask completes.
This is how I would do it:
Change the signature of UploadPicture:
final Activity callingActivity;
public UploadPicture(final Activity callingActivity, DropboxAPI api, String dropboxPath, File file) {
Context mContext = callingActivity.getApplicationContext();
this.callingActivity = callingActivity;
Add the finish call to onPostExecute:
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
if (result) {
showToast("Image successfully uploaded");
} else {
showToast(mErrorMsg);
}
callingActivity.finish(); //Finish activity only once you are done
}