Handling Advertisements in Native app using Selenium Java - java

I am automating Android Native Gaming App, our app renders ads from different ad networks. After submitting each game you may see static ad and video ad or you may not see an ad at all. If video ad is found it may vary from 30 secs to 1 min.
Important thing, when i use Appium inspector to spy various video ad screens shall be identified only by Class(android.webkit.WebView, android.widget.VideoView, android.widget.Button, android.view.View, android.widget.Image & android.widget.ImageView.). After Ad complete playing we need to click on device back button and play next game.
Can you suggest any good approach to automate this kind of app? Any sample code is much appreciated.

Option I: you have is to ask your developers to create a version of the application without ads.
Advantages - No ads.
Disadvantages - You will not be testing the exact same code as you plan to release.
You can disable only fullscreen ad.
I think there is no best way to do this. Stable automate checks or checking the exact same code as you plan to release.
Option II: is to catch if the ad is visible, and press back button.
For example (example fo Android):
protected boolean checkAdvert(AppiumDriver<WebElement> driver, int timeout) {
By adTree = By.xpath("//hierarchy/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]");
Map<String, Object> adParams = new HashMap<>();
//trying to wait for the ad to come up and then click the Expense button
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
driver.context("NATIVE_APP");
FluentWait<WebDriver> await = new FluentWait<WebDriver> (driver)
.withTimeout(timeout, TimeUnit.SECONDS)
.pollingEvery(500, TimeUnit.MILLISECONDS)
.ignoring(NoSuchElementException.class);
try {
await.until (ExpectedConditions.visibilityOf(driver.findElement(adTree)));
// go BACK to eliminate the popup
adParams.clear();
adParams.put("keySequence", "BACK");
driver.executeScript("mobile:presskey", adParams);
System.out.println("Press the back button to get out of ad");
return true;
} catch (Exception t) {
System.out.println("no ad showed up");
return false;
}
}
and use this in page object class:
public void addExp(String desc, String amount) {
do {
try {
driver.context("WEBVIEW");
driver.findElement(expDesc).sendKeys(desc);
driver.findElement(expAmnt).sendKeys(amount);
adClick = false;
} catch (NoSuchElementException ne) {
adClick = checkAdvert(driver, 1);
if (!adClick) throw ne;
}
} while (adClick);
}
But you must remember that ads may be different, you can try to find a universal selector. But I think it will hard to cover all cases.
adTree = By.xpath("//hierarchy/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]");

Related

Google Play Install Referrer Library - Referrer Generation

I'm developing an android application in Java where I need to pass the referer information to an URL. I'm getting the referrer information using Play Install Referrer Library.
Here is my code:
InstallReferrerClient referrerClient = InstallReferrerClient.newBuilder(this).build();
referrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
try {
Log.v("TAG", "InstallReferrer conneceted");
ReferrerDetails response = referrerClient.getInstallReferrer();
System.out.println("referrerUrl ID: " + response);
referrerClient.endConnection();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
Log.w("TAG", "InstallReferrer not supported");
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
Log.w("TAG", "Unable to connect to the service");
break;
default:
Log.w("TAG", "responseCode not found.");
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
Code is working fine and currently, the above snippet is inside my activity's onCreate method. which means it will start the new connection every time the user opens the activity.
In the library documentation, they have written that
Caution: The install referrer information will be available for 90
days and won't change unless the application is reinstalled. To avoid
unnecessary API calls in your app, you should invoke the API only once
during the first execution after install.
This is where I'm stuck, should I just call this thing when the application starts the first time?
If yes, I can store this referrer in the shared preference, but then how will I able to know that 90 days have been passed and I need to trigger that action again? Or it there something else that should I need to implement? Kindly help me with this issue.

Android webRTC video call inside a Background Service

Forgive me if this question was already asked, I couldn't find an answer for my case.
So, I have an Android app with Voice & Video call feature. I used webRTC for this.
I was able to make both Voice and Video call working perfectly inside an Activity, but now I want to keep the call running while the user exit the CallActivity and go back to the ChatActivity (to send a file/link/photo for example).
I managed to make the Voice call run perfectly inside a Background Service, but video call won't work as expected.
The remote video won't be displayed even though the audio from the video track is playing.
here is my Background Service code :
#Override
public void onAddStream(MediaStream mediaStream) {
if (mediaStream.videoTracks.size() > Constants.ONE || mediaStream.audioTracks.size() > Constants.ONE) {
return;
}
//check for video track, means this is a video call
if (!isAudioCall && mediaStream.videoTracks.size() > Constants.ZERO) {
remoteVideoTrack = mediaStream.videoTracks.get(Constants.ZERO);
CallActivityNew.remoteVideoTrack = remoteVideoTrack;
try {
localAudioTrack.setEnabled(true);
//Now ask the UI to display the video track
sendOrderToActivity(Constants.START_REMOTE_VIDEO, null);
} catch (Exception ignored) {}
} else if (mediaStream.audioTracks.size() > Constants.ZERO) {
//Means this is a Voice call, only audio tracks available
remoteAudioTrack = mediaStream.audioTracks.get(Constants.ZERO);
try {
localAudioTrack.setEnabled(true);
remoteAudioTrack.setEnabled(true);
} catch (Exception ignored) {}
}
}
and below my CallActivity code :
case Constants.START_REMOTE_VIDEO: {
if (remoteVideoView == null) {
remoteVideoView = findViewById(R.id.remote_gl_surface_view);
}
remoteVideoView.init(eglBaseContext, null);
remoteVideoView.setEnableHardwareScaler(true);
remoteVideoView.setMirror(true);
remoteVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
remoteVideoView.setZOrderMediaOverlay(true);
//Apply video track to the Surface View in order to display it
remoteVideoTrack.addSink(remoteVideoView);
//now enable local video track
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//now enable local video track
remoteVideoTrack.setEnabled(true);
}
}, Constants.TIME_THREE_HUNDRED_MILLIS);
setSpeakerphoneOn(false);
break;
}
I am sending orders from Service to Activity, the "case Constants.START_REMOTE_VIDEO" work after receiving the order from Service.
I don't see where the problem, why am I only hearing sound but the remote video won't start display !!
Thank you in advance for helping.
After testing for long hours, I found that my code works just fine, I just forget to change the view visibility from "GONE" to "VISIBLE".
Yeah that was the solution, i swear xD

Detect if audio or video casting is active

I have recently added a system volume controller to my app & i have overlooked Casting.
The app detects a volume button click using an accessibility service, intercepts the system volume panel by broadcasting the close system dialogues intent and pops my overlay panel, allowing the user to control audio directly from the panel (alarm, music & ring).
I have already added stop checks if the user is in call or the screen is off.
Is there a way to determine if the android device is currently casting video or audio?
I have dug through several API's and they all seem to point to methods within the context of the app, nothing system wide.
The solution was to create a MediaSessionManager instance and check for active controllers, then get the PlaybackType.
MediaController = null;
boolean isCasting = false;
MediaSessionManager mediaSessionManager = (MediaSessionManager) getSystemService(MEDIA_SESSION_SERVICE);
assert mediaSessionManager != null;
List<MediaController> sessions = mediaSessionManager.getActiveSessions(new ComponentName(this, NotificationListener.class));
for(MediaController controller : sessions) {
try {
isCasting = Objects.requireNonNull(controller.getPlaybackInfo()).getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE;
} catch (Exception e) {
e.printStackTrace();
}
if(isCasting){
mediaController = controller;
break;
}
}

Changing Flash setting of Android Camera 2 at runtime

Basically, what I am trying to do is change the CONTROL_AE_MODE by button click in the app. The user can use AUTO flash(ON_AUTO_FLASH), turn if ON(ON_ALWAYS_FLASH), or OFF(CONTROL_AE_MODE_OFF).
In this example: https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
Line 818, they set the flash once:
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
And then builds the CaptureSession at line 840.
Is there a way to change the CONTROL_AE_MODE after the preview is made?
I have tried remaking the session, which kinda worked:
if(flashMode == CameraView.CAMERA_FLASH_ON){
Log.e("CAMERA 2", "FLASH ON");
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
}else if(flashMode == CameraView.CAMERA_FLASH_OFF){
Log.e("CAMERA 2", "FLASH OFF");
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
}else if(flashMode == CameraView.CAMERA_FLASH_AUTO){
Log.e("CAMERA 2", "FLASH AUTO");
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
mFlashMode = flashMode;
if (mCameraCaptureSession != null) {
mCameraCaptureSession.close();
mCameraCaptureSession = null;
}
createCameraPreviewSession();
For some reason, CONTROL_AE_MODE_OFF would turn the whole preview black.
I tried looking in the docs for methods to update but haven't found anything.
Any tutorials or docs is much appreciated.
As mentioned by #cyborg86pl when switching flash modes you should not switch CONTROL_AE_MODE . Instead you can switch between FLASH_MODEĀ“s. Here is a working example for my case:
when (currentFlashState) {
FlashState.AUTO -> {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
}
FlashState.ON -> {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH)
}
FlashState.OFF -> {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
}
}
previewRequest = previewRequestBuilder.build()
captureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler)
I don't know why your preview turn black, but you don't need to close capture session manually. From .close() method's docs:
Using createCaptureSession(List , CameraCaptureSession.StateCallback,
Handler) directly without closing is the recommended approach for
quickly switching to a new session, since unchanged target outputs can
be reused more efficiently.
So you can reuse existing CaptureRequest.Builder, set your changed value, build new PreviewRequest and just start new session with this new request, like this:
try {
// Change some capture settings
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
// Build new request (we can't just edit existing one, as it is immutable)
mPreviewRequest = mPreviewRequestBuilder.build();
// Set new repeating request with our changed one
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
It will be much faster (almost without any visible freeze of preview).
What you want is disabling flash, not auto-exposure (AE), thus you want to use CONTROL_AE_MODE_ON rather than CONTROL_AE_MODE_OFF.
As mentioned in the documentation:
CONTROL_AE_MODE_ON
The camera device's autoexposure routine is active, with no flash control.

Buy item facebook dont work(as3)

I was trying to develop system to purchase items at Facebook using as3 (flash), but when I test the application I get the response that "The app you are using is not responding. Please try again later."
I tried several examples including the Facebook Developer docs. This is the code I am using.
public function buyItens(event:MouseEvent):void {
Facebook.api('/me?access_token='+access_token);
var order_info:Object = {
title:'Test buy item.',
description:'Item test',
price:'10',
item_id:'1a'
};
var obj:Object = {
//method: 'pay',
action: 'buy_item',
order_info: order_info,
dev_purchase_params: {'oscif': true}
};
Facebook.ui('pay',obj,callback);
}
private var callback=function(data) {
dTrace(data['order_id']);
if (data['order_id']) {
dTrace("callback"+data['order_id']);
return true;
} else {
//handle errors here
dTrace("callback handle errors here");
return false;
}
};
I am a beginner Facebook developer. Other functions, such as buying credits and earning credits work, but buying items does not. What's the problem?

Categories