onRequestPermissionsResult not getting called in signed apk, works fine in debug mode - android-6.0-marshmallow

In debug mode the app permissions work perfectly fine. When a signed apk is created with code obfuscation the onRequestPermissionsResult () is not getting called. Its done from Activity. Also targetSdkVersion is 23.
public void requestStoragePermissions(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_EXTERNAL_STORAGE)
|| ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_STORAGE_ACCESS);
}else{
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_STORAGE_ACCESS);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_STORAGE_ACCESS:
boolean result=PermissionUtil.verifyPermissions(grantResults);
if(result){
checkObbIsAlreadyDownloaded();
}else{
showPermissionAlert();
}
break;
default:Log.d("APK", "from reader");
}
}

Related

Xamarin.Forms Speakerphone NOT Activating on Android 10, 11, 12

I have App that has been working for years on Android 10, 11, 12 to Turn On/Off SpeakerPhone for Inbound and Outbound calls, but now it works sometimes on Inbound calls but never on Outbound calls. Here is a simple BroadcastReciever and MainActivity.
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { TelephonyManager.ActionPhoneStateChanged })]
public class PhonecallReceiver : BroadcastReceiver
{
public override async void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "Received intent!", ToastLength.Long).Show();
var state = intent.GetStringExtra(TelephonyManager.ExtraState);
if (intent.Action == TelephonyManager.ActionPhoneStateChanged)
{
if (state == TelephonyManager.ExtraStateRinging)
{
//Task.Run(async () =>
//{
// await Task.Delay(1);
// Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
// {
// MainActivity.audioManager = (AudioManager)Application.Context.GetSystemService(Context.AudioService);
// if (!MainActivity.audioManager.SpeakerphoneOn)
// { MainActivity.audioManager.SpeakerphoneOn = true; }
// var mode = Mode.Normal;// | Mode.Ringtone | Mode.InCommunication | Mode.Normal;
// MainActivity.audioManager.SetRouting(mode, Route.Speaker, Route.All);
// });
//});
MainActivity.audioManager.SpeakerphoneOn = true;
}
else if (state == TelephonyManager.ExtraStateOffhook)
{
MainActivity.audioManager.SpeakerphoneOn = true;
}
else if (state == TelephonyManager.ExtraStateIdle)
{
MainActivity.audioManager.SpeakerphoneOn = false;
}
}
}
}
In the MainActivity
public static AudioManager audioManager { get; set; }
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
var permissions = new string[]
{
Manifest.Permission.ReadPhoneState,
Manifest.Permission.ModifyAudioSettings,
Manifest.Permission.ModifyPhoneState
};
ActivityCompat.RequestPermissions(this, permissions, 123);
audioManager = (AudioManager)Application.Context.GetSystemService(Context.AudioService);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 123 && grantResults.Length > 0 && grantResults[0] == Permission.Granted)
{
RegisterReceiver(new PhonecallReceiver(), new IntentFilter(TelephonyManager.ActionPhoneStateChanged));
}
}
The above code used to Turn On/Off SpeakerPhone for Inbound/Outbound calls. Now it does not Turn ON the Speakerphone for Outbound Call and sometimes work for Inbound call. My problem is occurring on LG-K51 Android 12 mobile phone that I have Factory Reset.
Thanks

Can't retrieve Firebase InstanceId Token after updating to newest library

Okay so after updating to the newest firebase messaging library, I can't seem to retrieve the token. I t said in the docs that it should not be run in the main thread but when I tried, it still didn't work. So I simply removed it. What could I be doing wrong?
Below is my try/catch code.
String device_token;
try {
device_token = FirebaseInstanceId.getInstance().getToken(R.string.sender_id, "FCM");
student_token_reference = FirebaseDatabase.getInstance().getReference().child("MakeUpArtists_Info").child(uid);
student_token_reference.child("device_token").setValue(device_token).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
DatabaseReference check_variablesRef = FirebaseDatabase.getInstance().getReference().child("MakeUpArtists_Info").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("Verification");
check_variablesRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String id_card = dataSnapshot.child("id_card").getValue().toString();
String image = dataSnapshot.child("image").getValue().toString();
if (id_card.equals("Not yet") && image.equals("Not yet")) {
Toast.makeText(LoginActivity.this, "Please finish uploading your documents", Toast.LENGTH_SHORT).show();
Intent id_card_intent = new Intent(LoginActivity.this, IDcard.class);
startActivity(id_card_intent);
finish();
} else if (id_card.equals("Received") && image.equals("Received")) {
Intent intentMain = new Intent(LoginActivity.this, MainActivity.class);
intentMain.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intentMain);
finish();
} else if (id_card.equals("Received") && image.equals("Not yet")) {
Toast.makeText(LoginActivity.this, "Please upload your profile picture", Toast.LENGTH_SHORT).show();
Intent success_intent = new Intent(LoginActivity.this, DisplayProfile.class);
startActivity(success_intent);
finish();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
}
Any help would be greatly appreciated!
The Firebase Release Notes for the June 28 release recommend using FirebaseInstanceId.getInstance().getInstanceId(). Here is an example (as you requested in comments) of how to do that:
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(
new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(Task<InstanceIdResult> task) {
if (task.isSuccessful()) {
final InstanceIdResult iidResult = task.getResult();
final String token = iidResult.getToken();
Log.d(TAG, "token=" + token);
// process token as you need...
} else {
Log.e(TAG, "get IID/token failed", task.getException());
}
}
});

Gluon Mobile iOS Audio Player

Since the JavaFx Media has not been ported to the Mobile Platforms yet, can anyone help me with using the native iOS APi's to play a sound mp3 file that would be stored in my main/resources folder in my gluon project.
While on Android we can easily add native API to the Android folders of a Gluon project (check this solution for using native Media on Android), the use of native code (Objetive-C) with the Media API on iOS folders is not enough, since it has to be compiled, and the compiled files have to be included into the ipa.
Currently, Charm Down is doing this for a bunch of services. If you have a look at the build.gradle script for iOS, it includes the xcodebuild task to compile and build the native library libCharm.a, that later should be included in any iOS project using any of those services.
My suggestion will be cloning Charm Down, and providing a new service: AudioService, with some basic methods like:
public interface AudioService {
void play(String audioName);
void pause();
void resume();
void stop();
}
This service will be added to the Platform class:
public abstract class Platform {
...
public abstract AudioService getAudioService();
}
and you should provide implementations for Desktop (empty), Android (like the one here) and iOS.
IOS implementation - Java
You will have to add this to the IOSPlatform class:
public class IOSPlatform extends Platform {
...
#Override
public AudioService getAudioService() {
if (audioService == null) {
audioService = new IOSAudioService();
}
return audioService;
}
}
and create the IOSAudioService class:
public class IOSAudioService implements AudioService {
#Override
public void play(String audioName) {
CharmApplication.play(audioName);
}
#Override
public void pause() {
CharmApplication.pause();
}
#Override
public void resume() {
CharmApplication.resume();
}
#Override
public void stop() {
CharmApplication.stop();
}
}
Finally, you will have to add the native calls in CharmApplication:
public class CharmApplication {
static {
System.loadLibrary("Charm");
_initIDs();
}
...
public static native void play(String audioName);
public static native void pause();
public static native void resume();
public static native void stop();
}
IOS implementation - Objective-C
Now, on the native folder, on CharmApplication.m, add the implementation of those calls:
#include "CharmApplication.h"
...
#include "Audio.h"
// Audio
Audio *_audio;
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_play
(JNIEnv *env, jclass jClass, jstring jTitle)
{
NSLog(#"Play audio");
const jchar *charsTitle = (*env)->GetStringChars(env, jTitle, NULL);
NSString *name = [NSString stringWithCharacters:(UniChar *)charsTitle length:(*env)->GetStringLength(env, jTitle)];
(*env)->ReleaseStringChars(env, jTitle, charsTitle);
_audio = [[Audio alloc] init];
[_audio playAudio:name];
return;
}
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_pause
(JNIEnv *env, jclass jClass)
{
if (_audio)
{
[_audio pauseAudio];
}
return;
}
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_resume
(JNIEnv *env, jclass jClass)
{
if (_audio)
{
[_audio resumeAudio];
}
return;
}
JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_stop
(JNIEnv *env, jclass jClass)
{
if (_audio)
{
[_audio stopAudio];
}
return;
}
and create the header file Audio.h:
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
#interface Audio :UIViewController <AVAudioPlayerDelegate>
{
}
- (void) playAudio: (NSString *) audioName;
- (void) pauseAudio;
- (void) resumeAudio;
- (void) stopAudio;
#end
and the implementation Audio.m. This one is based on this tutorial:
#include "Audio.h"
#include "CharmApplication.h"
#implementation Audio
AVAudioPlayer* player;
- (void)playAudio:(NSString *) audioName
{
NSString* fileName = [audioName stringByDeletingPathExtension];
NSString* extension = [audioName pathExtension];
NSURL* url = [[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:#"%#",fileName] withExtension:[NSString stringWithFormat:#"%#",extension]];
NSError* error = nil;
if(player)
{
[player stop];
player = nil;
}
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if(!player)
{
NSLog(#"Error creating player: %#", error);
return;
}
player.delegate = self;
[player prepareToPlay];
[player play];
}
- (void)pauseAudio
{
if(!player)
{
return;
}
[player pause];
}
- (void)resumeAudio
{
if(!player)
{
return;
}
[player play];
}
- (void)stopAudio
{
if(!player)
{
return;
}
[player stop];
player = nil;
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSLog(#"%s successfully=%#", __PRETTY_FUNCTION__, flag ? #"YES" : #"NO");
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
NSLog(#"%s error=%#", __PRETTY_FUNCTION__, error);
}
#end
Build the native library
Edit the build.gradle for the iOS module, and add the Audio service to the xcodebuild task:
def nativeSources = ["$project.projectDir/src/main/native/CharmApplication.m",
...,
"$project.projectDir/src/main/native/Audio.m"]
...
def compileOutputs = [
"$project.buildDir/native/$arch/CharmApplication.o",
"$project.buildDir/native/$arch/Charm.o",
...,
"$project.buildDir/native/$arch/Audio.o"]
Build the project
Save the project, and from the root of the Charm Down project, on command line run:
./gradlew clean build
If everything is fine, you should have:
Common/build/libs/charm-down-common-2.1.0-SNAPSHOT.jar
Desktop/build/libs/charm-down-desktop-2.1.0-SNAPSHOT.jar
Android/build/libs/charm-down-android-2.1.0-SNAPSHOT.jar
IOS/build/libs/charm-down-ios-2.1.0-SNAPSHOT.jar
IOS/build/native/libCharm.a
Gluon Project
With those dependencies and the native library, you will be able to create a new Gluon Project, and add the jars as local dependencies (to the libs folder).
As for the native library, it should be added to this path: src/ios/jniLibs/libCharm.a.
Update the build.gradle script:
repositories {
flatDir {
dirs 'libs'
}
jcenter()
...
}
dependencies {
compile 'com.gluonhq:charm-glisten:3.0.0'
compile 'com.gluonhq:charm-down-common:2.1.0-SNAPSHOT'
compile 'com.gluonhq:charm-glisten-connect-view:3.0.0'
iosRuntime 'com.gluonhq:charm-glisten-ios:3.0.0'
iosRuntime 'com.gluonhq:charm-down-ios:2.1.0-SNAPSHOT'
}
On your View, retrieve the service and provide some basic UI to call the play("audio.mp3"), pause(), resume() and stop() methods:
private boolean pause;
public BasicView(String name) {
super(name);
AudioService audioService = PlatformFactory.getPlatform().getAudioService();
final HBox hBox = new HBox(10,
MaterialDesignIcon.PLAY_ARROW.button(e -> audioService.play("audio.mp3")),
MaterialDesignIcon.PAUSE.button(e -> {
if (!pause) {
audioService.pause();
pause = true;
} else {
audioService.resume();
pause = false;
}
}),
MaterialDesignIcon.STOP.button(e -> audioService.stop()));
hBox.setAlignment(Pos.CENTER);
setCenter(new StackPane(hBox));
}
Finally, place an audio file like audio.mp3, under src/ios/assets/audio.mp3, build and deploy to iOS.
Hopefully, this API will be provided by Charm Down any time soon. Also if you come up with a nice implementation, feel free to share it and create a Pull Request.

No 'output' extra specified Exception

I use the Google Photo app to pick gallery photo and then when I crop the picture and save, it catches an exception, Here is my code :
goto_picture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
IMAGE_UNSPECIFIED);
startActivityForResult(intent, PHOTO_ZOOM);
dialog.cancel();
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PHOTO_GRAPH) {
startPhotoZoom(Uri.fromFile(file));
String imagePath = SystemUtils.getSDPath() + "/temp.jpg";
File picture = new File(imagePath);
if (picture.exists()) {
pictureBitmap = BitmapFactory.decodeFile(imagePath);
ImageUtils.SaveCacheBitmap(pictureBitmap);
rvEditAvatar.setImageBitmap(pictureBitmap);
}
}
if (requestCode == PHOTO_ZOOM) {
startPhotoZoom(data.getData());
}
if (requestCode == PHOTO_RESULT) {
Bundle extras = data.getExtras();
if (extras != null) {
pictureBitmap = extras.getParcelable("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 100,
stream);
ImageUtils.SaveCacheBitmap(pictureBitmap);
rvEditAvatar.setImageBitmap(pictureBitmap);
}
}
}
}
public void startPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 180);
intent.putExtra("outputY", 180);
intent.putExtra("return-data", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(intent, PHOTO_RESULT);
}
Logcat:
Process: com.google.android.apps.photos, PID: 7031
java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.photos/com.google.android.apps.photos.photoeditor.intents.EditActivity}:
java.lang.UnsupportedOperationException: No 'output' extra specified
and can not save to specified inputUri:
content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F72072/ACTUAL
As the exception said, you have to specify output extra like the following code.
intent.putExtra(MediaStore.EXTRA_OUTPUT, someOutPutPath);
And return data is not secure in case of big image cropped which may cause crash. I think that's why it forces you to use an output extra but not the data directly. So you may set the return-data to false as well:
intent.putExtra("return-data", false);
I meet this problem today, and solved by double check the data pass-back.I test following code on both Android L and Android 4. On Android L the fileUri is not empty while pre Android L we got fileUri null(in this case, I got the bitmap by simply getData).
private Bitmap decodeBitmapFromCrop(Intent data) {
Bundle extras = data.getExtras();
Bitmap photo = null;
if (extras != null) {
photo = extras.getParcelable("data");
} else {
Uri fileUri = data.getData();
if (fileUri != null) {
try {
photo = MediaStore.Images.Media.getBitmap(getContentResolver(), fileUri);
} catch (IOException e) {
XXLog.d(TAG, "Media.getBitmap", e);
}
}
}
return photo;
}

WinRun4J - service not stopping

I'm using this to install my application as a windows service. Everything works fine except the service does not stop;
#Override
public int serviceMain(String[] strings) throws ServiceException {
try {
System.out.println("BootService: init");
System.out.println("BootService: service loop start");
while (ws.isServiceRunning()) {
System.out.println("BootService: loop");
ws.serviceHandler();
}
System.out.println("BootService: stopped");
return 0;
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
#Override
public int serviceRequest(int control) throws ServiceException {
try {
switch (control) {
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
if (ws!=null) {
ws.stopService();
}
break;
}
return 0;
} catch (WindowsServiceException ex) {
throw new ServiceException(ex);
}
}
My service backend code is stopped by the call to serviceRequest(), which in turn makes the loop in serviceMain() exit. I see the message "BootService: stopped" in my logs, yet the Window Control Panel Services Applet just sits says "Stopping service...", but it never does.
What would stop the service from stopping even though I'm sure it has exited the serviceMain() without error?
I donĀ“t know if you could solve it, but I had a simmilar problem and I fixed it by adding a timer that called System.exit(0)
public int serviceMain(String[] args) throws ServiceException {
while (!shutdown) {
try {
if (!myservice.isRunning()) {
(new Thread(new LaucherRunnable(args))).start();
}
Thread.sleep(6000);
} catch (InterruptedException e) {
}
}
periodicRunner.stop();
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
t.setRepeats(false);
t.start();
return 0;
}

Resources