Reputation: 6060
I want to write an Espresso matcher that verifies that an `ImageView´ has a specific bitmap set. Since the app does its loading of images via Glide, I thought I have to do the same on the test side to account for cropping / centering before I can actually compare the expected and actual bitmaps.
Here is what I came up with so far:
BitmapRequestBuilder<Uri, Bitmap> bitmapRequest = Glide.with(imageView.getContext())
.load(Uri.parse("file:///android_asset/" + mPath))
.asBitmap();
switch (imageView.getScaleType()) {
case CENTER_CROP:
bitmapRequest.centerCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
bitmapRequest.fitCenter();
break;
default:
// no scaling applied to the ImageView under test
}
AtomicReference<Bitmap> bmRef = new AtomicReference<>();
bitmapRequest.into(new SimpleTarget<Bitmap>(
imageView.getMeasuredWidth(),
imageView.getMeasuredHeight()
) {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
bmRef.set(resource);
}
});
// ???
try {
Bitmap expected = bmRef.get();
return expected.sameAs(bitmap);
} catch (Exception e) {
throw new IllegalStateException("could not load asset " + mPath, e);
}
Now the issue here is of course that I have a deadlock. I'm on the main thread (the matcher is executed on the main thread IIRC) and Glide wants a backend thread to load the bitmap and then returns on the main thread (in 'onResourceReady') itself. So I need to wait from the outside for the result that is posted on the inside, while keeping the main thread running.
I (unsuccessfully) tried to advance the current looper via Looper.loop()
in // ???
and also tried the regular lock / wait approach, but nothing worked. I'm out of ideas...
Upvotes: 10
Views: 2289
Reputation: 391
One way to do this to keep your comparison logic inside onResourceReady, And then if you are using any eventbus then trigger event with the result and put UI logic inside the method which subscribes to this event. If not using any event bus then LocalBroadcastManager to broadcast result.
For example:
private BroadcastReceiver receiver;
private void doWhateverYouWantWithResult(boolean result) {
}
bitmapRequest.into(new SimpleTarget<Bitmap>(
imageView.getMeasuredWidth(),
imageView.getMeasuredHeight()
) {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
bmRef.set(resource);
Bitmap expected = resource;
boolean result = expected.sameAs(bitmap);
Intent localIntent =
new Intent(BROADCAST_ACTION)
// Puts the status into the Intent
.putExtra(MATCH_RESULT, result);
// Broadcasts the Intent to receivers in this app.
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
});
@Override
public void onResume(){
super.onResume();
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean result = intent.getBooleanExtra(MATCH_RESULT);
doWhateverYouWantWithResult(result);
}
};
LocalBroadcastManager.getInstance(getContext())
.registerReceiver(receiver, new IntentFilter(BROADCAST_ACTION));
}
@Override
public void onPause(){
super.onPause();
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(receiver);
}
Upvotes: -2
Reputation: 10205
For cases like that I use a simple sleep
, it is not the best option, but it works for me.
public static void waitForActivity(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Upvotes: -2