I am using Image Cropper provided by ArthurHub, It used to work perfectly fine on all tested devices, I can crop images from both gallery and camera. Recently on Galaxy A51 device after updating; if you try to crop image camera the App crashes, but cropping from gallery works fine!
Here is my code and build.gradle files
This is my build.gradle(:app) file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.bostanji.cropper"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment:2.3.4'
implementation 'androidx.navigation:navigation-ui:2.3.4'
api 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
This is my code:
package com.bostanji.cropper;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.theartofdev.edmodo.cropper.CropImage;
import com.theartofdev.edmodo.cropper.CropImageView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
imageView = findViewById(R.id.imageView);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startCropper();
}
});
}
private void startCropper(){
CropImage.activity()
.setGuidelines(CropImageView.Guidelines.ON).setAspectRatio(1,1)
.start(this);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
CropImage.ActivityResult result = CropImage.getActivityResult(data);
if (resultCode == RESULT_OK) {
Uri resultUri = result.getUri();
imageView.setImageURI(resultUri);
} else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
Exception error = result.getError();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
The version of the gradle is 6.3-all. And here is my build.gradle:
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
}
group 'com.dennis'
version '1.0-SNAPSHOT'
repositories {
mavenLocal()
mavenCentral()
}
jar {
from {
configurations.runtime.collect { zipTree(it) }
}
manifest {
attributes 'Main-Class': 'com.dennis.tcp.robot.RobotClient'
}
}
dependencies {
/*...*/
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
And here is settings.gradle
rootProject.name = 'robot'
And here is the main class:
package com.dennis.tcp.robot;
/*import ignored*/
public class RobotClient {
private static final String URL = "192.168.10.140";
private static final int PORT = 9760;
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE,true)
.handler(new RobotClientInitializer());
ChannelFuture future = bootstrap.connect(URL, PORT).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
}
}
The packaging progress went well but the output jar cannot be executed and give the Exception of no main class
The jar file shows the main class RobotClient is compiled indeed. However, the java -jar cannot execute or find the mainclass.
Why did this happend?
I am using Java client library for Google Maps API Web Services to draw routes between two points. it works fine on Android Studio's Emulator but crashes on Blue Stack and my Smartphone.
I have created Maps Activity from project Templates, only edited AppGradle and MapsActivity. App works fine as intended but only on Android Studio's emulator.
Here is the working image in Android Studio Emulator(Android 10)
enter image description here
So app crashes at this line(what i found so far) :
-- directions.destination(destination).setCallback(new PendingResult.Callback() {
Here is my MapsActivity:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private static final String TAG = "TaG";
private GoogleMap mMap;
static final int REQUEST_LOCATION_PERMISSION = 99;
double mUserlatitude, mUserlongitude;
ArrayList<PolylineData> mPolyLinesData = new ArrayList<>();
Marker marker =null;
GeoApiContext mGeoApiContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
mGeoApiContext = new GeoApiContext.Builder().apiKey("google_maps_api_key").build();
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
enableMyLocation();
mMap.getUiSettings().setZoomControlsEnabled(true);
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(31.522738, 74.358556);
marker = mMap.addMarker(new MarkerOptions().position(sydney));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 12));
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
LatLng start = new LatLng(mUserlatitude,mUserlongitude);
calculateDirections(start,marker);
return false;
}
});
}
private void enableMyLocation() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 0, locationListener);
} else {
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION_PERMISSION);
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
// Check if location permissions are granted and if so enable the
// location data layer.
switch (requestCode) {
case REQUEST_LOCATION_PERMISSION:
if (grantResults.length > 0
&& grantResults[0]
== PackageManager.PERMISSION_GRANTED) {
enableMyLocation();
}else{
enableMyLocation();
}
break;
}
}
LocationListener locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
mUserlatitude = location.getLatitude();
mUserlongitude = location.getLongitude();
//Toast.makeText(MapsActivity.this, Double.toString(mUserlatitude), Toast.LENGTH_SHORT).show();
//Toast.makeText(MapsActivity.this, marker.getPosition().toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
};
private void calculateDirections(LatLng start, Marker marker){
Log.d(TAG, "calculateDirections: calculating directions.");
com.google.maps.model.LatLng destination = new com.google.maps.model.LatLng(
marker.getPosition().latitude,
marker.getPosition().longitude
);
DirectionsApiRequest directions = new DirectionsApiRequest(mGeoApiContext);
directions.alternatives(true);
directions.origin(
new com.google.maps.model.LatLng(
start.latitude,start.longitude
)
);
//Log.d(TAG, "calculateDirections: destination: " + destination.toString());
directions.destination(destination).setCallback(new PendingResult.Callback<DirectionsResult>() {
#Override
public void onResult(DirectionsResult result) {
Log.d(TAG, "calculateDirections: routes: " + result.routes[0].toString());
Log.d(TAG, "calculateDirections: duration: " + result.routes[0].legs[0].duration);
Log.d(TAG, "calculateDirections: distance: " + result.routes[0].legs[0].distance);
Log.d(TAG, "calculateDirections: geocodedWayPoints: " + result.geocodedWaypoints[0].toString());
addPolylinesToMap(result);
}
#Override
public void onFailure(Throwable e) {
Log.e(TAG, "calculateDirections: Failed to get directions: " + e.getMessage() );
return;
}
});
}
private void addPolylinesToMap(final DirectionsResult result){
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
if(mPolyLinesData.size() > 0){
for(PolylineData polylineData: mPolyLinesData){
polylineData.getPolyline().remove();
}
mPolyLinesData.clear();
mPolyLinesData = new ArrayList<>();
}
double firstduration = 0;
for(DirectionsRoute route: result.routes){
List<com.google.maps.model.LatLng> decodedPath = PolylineEncoding.decode(route.overviewPolyline.getEncodedPath());
List<LatLng> newDecodedPath = new ArrayList<>();
// This loops through all the LatLng coordinates of ONE polyline.
for(com.google.maps.model.LatLng latLng: decodedPath){
Log.d(TAG, "run: latlng: " + latLng.toString());
newDecodedPath.add(new LatLng(
latLng.lat,
latLng.lng
));
}
Polyline polyline = mMap.addPolyline(new PolylineOptions().addAll(newDecodedPath));
polyline.setColor(ContextCompat.getColor(getApplicationContext(), R.color.quantum_grey));
polyline.setClickable(true);
mPolyLinesData.add(new PolylineData(polyline, route.legs[0]));
double thisduration = route.legs[0].duration.inSeconds;
if(firstduration == 0) {
firstduration= thisduration;
onPolylineClickListener.onPolylineClick(polyline);
}
if(thisduration < firstduration){
firstduration = thisduration;
onPolylineClickListener.onPolylineClick(polyline);
}
if(result.routes.length == 1) onPolylineClickListener.onPolylineClick(polyline);
}
}
});
}
GoogleMap.OnPolylineClickListener onPolylineClickListener = new GoogleMap.OnPolylineClickListener() {
#Override
public void onPolylineClick(Polyline polyline) {
int index = 0;
for(PolylineData polylineData: mPolyLinesData){
index++;
//Log.d(TAG, "onPolylineClick: toString: " + polylineData.toString());
if(polyline.getId().equals(polylineData.getPolyline().getId())){
polylineData.getPolyline().setColor(ContextCompat.getColor(getApplicationContext(), R.color.quantum_lightblue));
polylineData.getPolyline().setZIndex(1);
if(marker != null)marker.remove();
LatLng endlocation = new LatLng(polylineData.getLeg().endLocation.lat, polylineData.getLeg().endLocation.lng);
marker = mMap.addMarker(new MarkerOptions().position(endlocation).title("Trip # "+ index).snippet("Duration: "+polylineData.getLeg().duration));
marker.showInfoWindow();
zoomRoute(polyline.getPoints());
}
else{
polylineData.getPolyline().setColor(ContextCompat.getColor(getApplicationContext(), R.color.quantum_grey));
polylineData.getPolyline().setZIndex(0);
}
}
}
};
public void zoomRoute(List<LatLng> lstLatLngRoute) {
if (mMap == null || lstLatLngRoute == null || lstLatLngRoute.isEmpty()) return;
LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
for (LatLng latLngPoint : lstLatLngRoute)
boundsBuilder.include(latLngPoint);
int routePadding = 120;
LatLngBounds latLngBounds = boundsBuilder.build();
mMap.animateCamera(
CameraUpdateFactory.newLatLngBounds(latLngBounds, routePadding),
600,
null
);
}
public static class PolylineData {
private Polyline polyline;
private DirectionsLeg leg;
public PolylineData(Polyline polyline, DirectionsLeg leg) {
this.polyline = polyline;
this.leg = leg;
}
public Polyline getPolyline() {
return polyline;
}
public void setPolyline(Polyline polyline) {
this.polyline = polyline;
}
public DirectionsLeg getLeg() {
return leg;
}
public void setLeg(DirectionsLeg leg) {
this.leg = leg;
}
#Override
public String toString() {
return "PolylineData{" +
"polyline=" + polyline +
", leg=" + leg +
'}';
}
}
}
Below is the App Gradle:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility = 1.8
sourceCompatibility = 1.8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.firebase:firebase-auth:19.3.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.google.maps:google-maps-services:0.13.0'
implementation 'org.slf4j:slf4j-simple:1.7.25'
implementation 'com.google.android.libraries.places:places:2.2.0'
}
This solved my problem.
After debugging my app, I found out that adding this to my dependencies in app-level gradle file (build.gradle(app)) helped resolve the issue.
implementation group: 'com.github.seratch', name: 'java-time-backport', version: '1.0.0'
I have referred AppInitializer always launches android for cross platform tests post
still none of the solutions are helping me out, whenever I run BDD tests by default Platform is getting value as Android.
How can I make it dynamically pick the platform values?
I'm having a BaseTest class that inherited by all test class with decorated with PlatformTestFixture attribute. Then we can start Android or iOS app based on platform parameter that passed in.
public class PlatformTestFixtureAttribute : TestFixtureAttribute
{
public PlatformTestFixtureAttribute()
{
}
public PlatformTestFixtureAttribute(params object[] arguments)
: base(arguments)
{
AddPlatformCategory(arguments);
}
private void AddPlatformCategory(object[] args)
{
// Not needed in TestCloud
if (!TestEnvironment.IsTestCloud)
{
foreach (var arg in args)
{
if (arg is Platform)
{
if (Platform.Android == (Platform)arg)
{
AddAndroidCategory();
}
else if (Platform.iOS == (Platform)arg)
{
AddiOSCategory();
}
}
}
}
}
private void AddAndroidCategory()
{
Category = "AndroidTest";
}
private void AddiOSCategory()
{
Category = "iOSTest";
}
}
[PlatformTestFixture(Platform.Android)]
[PlatformTestFixture(Platform.iOS)]
public abstract class BaseTest
{
Platform _platform;
protected BaseTest(Platform platform)
{
_platform = platform;
}
[SetUp]
public virtual void BeforeEachTest()
{
if (platform == Platform.Android)
{
StartAndroidApp();
}
else
{
StartiOSApp();
}
}
}
public class ChildTest : BaseTest
{
public ChildTest(Platform platform)
: base(platform)
{
}
[Test]
public void SomeTest()
{
...
}
}
Then I can run the test in command line specifying whether to run iOSTest or AndroidTest.
[NUnit] [Test Fixture DLL Path] -include=AndroidTest
OR
[NUnit] [Test Fixture DLL Path] -include=iOSTest
Today I noticed AdMob is offering rewarded interstitial option. I'd like to integrate it in my game. Does the current Xamarin.GooglePlayServices.Ads support the integration?
Has anyone tried it? Love to hear from your experience.
Thanks!
I have just attempted to integrate them and they work fine for me in debug (yet to try in release mode - will update once I've tried it)
Simply create an interstitial ad as you normally would but use the Reward Video ad unit ID instead of the usual interstitial ad ID.
If you want to try it yourself, the sample Reward Video ad unit ID provided by Google for testing is:
ca-app-pub-3940256099942544/5224354917
#region RewardedViewAd
private IRewardedVideoAd rewardedVideoAd;
private void InitialRewardVideo()
{
rewardedVideoAd = MobileAds.GetRewardedVideoAdInstance(this);
rewardedVideoAd.RewardedVideoAdListener = this;
this.LoadRewardAd();
}
private void LoadRewardAd()
{
if (!rewardedVideoAd.IsLoaded)
{
#if DEBUG
rewardedVideoAd.LoadAd(" ca-app-pub-3940256099942544/5224354917", new AdRequest.Builder().Build());
#else
rewardedVideoAd.LoadAd("ca-app-pub-9045308343519031/327467645", new AdRequest.Builder().Build());
#endif
}
}
private void StartRewardedVideoAd()
{
if (rewardedVideoAd.IsLoaded)
{
rewardedVideoAd.Show();
}
}
public void OnRewarded(IRewardItem reward)
{
var coins = reward.Amount;
}
public void OnRewardedVideoAdClosed()
{
this.LoadRewardAd();
}
public void OnRewardedVideoAdFailedToLoad(int errorCode)
{
}
public void OnRewardedVideoAdLeftApplication()
{
}
public void OnRewardedVideoAdLoaded()
{
}
public void OnRewardedVideoAdOpened()
{
}
public void OnRewardedVideoCompleted()
{
}
public void OnRewardedVideoStarted()
{
}
protected override void OnPause()
{
this.rewardedVideoAd.Pause(this);
base.OnPause();
}
protected override void OnResume()
{
this.rewardedVideoAd.Resume(this);
base.OnResume();
}
protected override void OnDestroy()
{
this.rewardedVideoAd.Destroy(this);
base.OnDestroy();
}
#endregion;