How I can detect that HMS services are available for some phone?
The question is a duplicate of answer but let it be cause googling with check huawei services is available didn't provide me with a link for StackOverflow question (Have both GMS and HMS in the project). Let Google indexing this for better search possibilities.
First of all you should read this answer.
The answer contains the link to the old documentation version of HMS. Here is the new one - link. Find the isHuaweiMobileServicesAvailable method and read about return constants description.
Best wishes!
You can use this method to detect
public static boolean isHmsAvailable(Context context) {
boolean isAvailable = false;
if (null != context) {
int result = HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context);
isAvailable = (com.huawei.hms.api.ConnectionResult.SUCCESS == result);
}
Log.i(TAG, "isHmsAvailable: " + isAvailable);
return isAvailable;
}
Related
I am using Google CoreAR package in my React-Native app for AR support. There are some devices which support AR and some not. I am getting error while I run the application in non-supported devices. I want to render a message instead showing error on the screen. For this Google CoreAR package is providing the solution which is not working for me.
void maybeEnableArButton() {
ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this);
if (availability.isTransient()) {
// Continue to query availability at 5Hz while compatibility is checked in the background.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
maybeEnableArButton();
}
}, 200);
}
if (availability.isSupported()) {
mArButton.setVisibility(View.VISIBLE);
mArButton.setEnabled(true);
} else { // The device is unsupported or unknown.
mArButton.setVisibility(View.INVISIBLE);
mArButton.setEnabled(false);
}
}
The problem with above code snippet is that availability.isSupported() is always returning true and that's why else part of code is not running. Can you guys please help me with this?
Thank you.
I found solution for this problem. ArCoreApk.Availability has some methods which can be used. You can find these methods in the
documentation. The method ArCoreApk.Availability
return either SUPPORTED_INSTALLED or SUPPORTED_NOT_INSTALLED depending on device support. So based on this return value we can do the stuff.
I did like this.
#ReactMethod
public ArCoreApk.Availability getSupport(){
ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this.getReactApplicationContext());
return availability.name();
}
having function to get AdvertisingIdClient.Info
private static AdvertisingIdClient.Info getAdsClientInfo(#NonNull final Context context) throws GooglePlayServicesNotAvailableException, IOException, GooglePlayServicesRepairableException {
int isGPAvailable = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
if (isGPAvailable == ConnectionResult.SUCCESS) {
return AdvertisingIdClient.getAdvertisingIdInfo(context);
}
return null;
}
it uses AdvertisingIdClient.getAdvertisingIdInfo(context)
there are three libs in https://developers.google.com/android/guides/setup
Google Mobile Ads com.google.android.gms:play-services-ads:20.1.0
Android Advertising ID (AAID) com.google.android.gms:play-services-ads-identifier:17.0.0
Lightweight version of Google Mobile Ads com.google.android.gms:play-services-ads-lite:20.1.0
what are the difference among these, and which one is safe to use for the purpose?
It turns out that com.google.android.gms:play-services-ads-identifier:17.0.0 is fine for this case but change the GoogleApiAvailability to GoogleApiAvailabilityLight and it will be included in this dependency.
Is there any way in Java to detect if an Android device has an offline speech recognition language installed, and if it does not prompt the user to download it?
I know you can ask to speech to text to prefer offline speech to text, but how do you know if the device has the language installed?
This question is not on how to use offline speech, this works.
The question is "how to detect and download/install offline speech languages" from Java app code. i.e. have the app detect if they have offline German language installed, and if not prompt the user to download/install it.
This is not the answer you are hoping for, as at the time of writing, I don't believe there is a straight forward solution to this. I very much hope to be proved wrong.
I requested an enhancement to provide this information programmatically a long time ago - here
The enhancement suggested an additional parameter RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES:
It would surely be trivial for this to be added and used in the following way:
final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final ArrayList<String> vrStringLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
// This would be nice
final ArrayList<String> vrStringOfflineLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES);
}
}, null, 1234, null, null);
Alas, it has never happened.
You do have two other options to attempt to handle this gracefully.
In the unlikely event you application runs with root permissions, you can check the location of /data/data/com.google.android.googlequicksearchbox/app_g3_models/ which contains the offline files, labelled quite handily by their locale.
The second involves knowing when the user needs a prompt to install the missing offline files.
From my experience, the recognition error of SpeechRecognizer.ERROR_SERVER most often denotes this, but it is not foolproof.
#Override
public void onError(final int error) {
switch (error) {
case SpeechRecognizer.ERROR_SERVER:
// TODO - prompt to install offline files
break;
}
}
When detected, you can guide the user to the correct installation screen.
public static final String PACKAGE_NAME_GOOGLE_NOW = "com.google.android.googlequicksearchbox";
public static final String ACTIVITY_INSTALL_OFFLINE_FILES = "com.google.android.voicesearch.greco3.languagepack.InstallActivity";
public static boolean showInstallOfflineVoiceFiles(#NonNull final Context ctx) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(PACKAGE_NAME_GOOGLE_NOW, ACTIVITY_INSTALL_OFFLINE_FILES));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
ctx.startActivity(intent);
return true;
} catch (final ActivityNotFoundException e) {
} catch (final Exception e) {
}
return false;
}
Using hard-coded values such as this, is of course not ideal, but neither is this situation!
Once you've messed around with all of the above and think you have a good interim solution - think again! Regardless of whether the user has correctly installed the missing offline files, it is highly likely it still won't work.....
My answer here describes the process I still have to guide my user's with. It's very frustrating.
Finally one more bug to throw into the mix - RecognitionListener.onError(int) can be thrown when there isn't an error. Check my gist from the answer here to use a BugRecognitionListener so you can check the callbacks are being sent in the correct order and ignore those that aren't. This remains a problem, despite my answer suggesting a fix in a previous release.
The above should keep you busy! Good luck....
To detect whether needed Language(German) is available, please follow below :
Iterate the Locale list and check whether Locale available for German language.
If you didn't get any Locale object in return, you can conclude that German language is not available offline. Then you can write code to download and do other stuff.
I did below implementation for my project. Hope below code helps you !!!
private TextToSpeech t1;
private void setForOtherLangAudio() {
Locale[] locales = Locale.getAvailableLocales();
Locale loc = null;
for (Locale locale : locales) {
// Replace XXX with your German codes
if (locale.getDisplayCountry().equals("XXX") && locale.getDisplayLanguage().equals("XXX")) {
loc = locale ;
break;
}
}
final Locale germanLocale = loc;
t1 = new TextToSpeech(getContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
t1.setLanguage(germanLocale);
}
}
});
}
I've throughtoutly searched this site as well as others for answers and found no actual one.
My question is what exactly does the Freedom Hack (which allows users to get in-app purchases without paying) do. That is, what part of the process is altered. I've found this list of applications for which the hack works, and some of the entries there are dated to this month, meaning that it hasn't been completely fixed yet. The responses I've seen were "verify the application in your server", but if the hack, for example, alters the Java.Security's signature verification function, so it always returns true, then adding my own signature in the server wouldn't help much.
I don't know if the author still follow this topic or not. But I spent sometime to find out (googling) the way how freedom work and how to prevent it (until they update the way freedom work) in my project and it works. My implementation is really simple and you don't need to verify by sending request to server (which affect the performance and take more effort to implement it).
The current implementation of freedom is that it will replace (redirect) all the method calls of java.security.Signature.verify(byte[]) to a freedom's jni method which in turn just simply always return true (or 1).
Take a look at java.security.Signature.verify(byte[]):
public final boolean verify(byte[] signature) throws SignatureException {
if (state != VERIFY) {
throw new SignatureException("Signature object is not initialized properly");
}
return engineVerify(signature);
}
Here the engineVerify method is an abstract protected method which is first defined in java.security.SignatureSpi(Signature extends SignatureSpi).
OK, that enough, because I can't believe java.security.Signature.verify(byte[]) method anymore, I would use engineVerify method directly. To do that, we need to use reflection. Modify the verify method of IABUtil/Security from:
public static boolean verify(PublicKey publicKey, String signedData, String signature) {
Signature sig;
try {
sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
if (!sig.verify(Base64.decode(signature))) {
Log.e(TAG, "Signature verification failed.");
return false;
}
return true;
} catch (...) {
...
}
return false;
}
To:
public static boolean verify(PublicKey publicKey, String signedData, String signature) {
Signature sig;
try {
sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
Method verify = java.security.SignatureSpi.class.getDeclaredMethod("engineVerify", byte[].class);
verify.setAccessible(true);
Object returnValue = verify.invoke(sig, Base64.decode(signature));
if (!(Boolean)returnValue) {
Log.e(TAG, "Signature verification failed.");
return false;
}
return true;
} catch (...) {
...
}
return false;
}
That is simple but it works with the current implementation of freedom until they update its algorithm in the future.
then adding my own signature in the server wouldn't help much.
That is not correct, the signature that "Freedom" uses is invalid and the order id is also invalid.
What I did to ensure that my Application is safe is:
Send isPurchaseValid(myPurchase.getSignature(), myPurchase.getOriginalJson()) to my server to verify over there and it works with real purchases but freedom fails everytime.
On the server I check if the signature matches
If it does match I contact "Google APIs Google Play Android Developer API > androidpublisher.inapppurchases.get" to verify that the Purchase exists and that returns my developer payload.
I then use the developer payload to make sure that this purchase is for this specific user and not some other user and this user is sending me his data.
P.S. The developer payload is a String you set before the purchase is made from your android app, it should be something unique to your user.
It maybe a lot of work but It ensure that no one will buy your stuff with freedom and succeed.
The only thing that I am unable to do is not let freedom have an affect on my application, for example the folks in Path did something I don't know what which made Freedom have no effect what so ever!!!!
I'm using something like this, I know it's not a good solution compared to a remote server check for your signature. I'm checking if Freedom app is installed, if so I'm not opening my app.
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
if(isHackerAppIsntalled())
finish();
}
private boolean isHackerAppInstalled() {
final PackageManager pm = getApplication().getPackageManager();
List<ApplicationInfo> packages = pm
.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo packageInfo : packages) {
String packageName = packageInfo.packageName;
if (packageName.contains("cc.madkite.freedom")
|| packageName.contains("madkite.freedom")) {
return true;
}
}
return false;
}
Im developing an app with the latest android version (4.2.1 API-Level 17) for tablets with multiuser capabilities.
I want to restrict certain features (like the access to the app preferences) to the owner of the tablet (that is the user who can add and remove other user accounts)
is there any way i can find out if the current user is the owner?
i read through the UserManager and UserHandle API docs but couldn't find a function that allows me to check for it.
have i missed something or is there another way to do that?
Similar but without reflection:
static boolean isAdminUser(Context context)
{
UserHandle uh = Process.myUserHandle();
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if(null != um)
{
long userSerialNumber = um.getSerialNumberForUser(uh);
Log.d(TAG, "userSerialNumber = " + userSerialNumber);
return 0 == userSerialNumber;
}
else
return false;
}
You can create an extension property in Kotlin to make it simpler:
val UserManager.isCurrentUserDeviceOwner: Boolean
get() = if (SDK_INT >= 23) isSystemUser
else if (SDK_INT >= 17) getSerialNumberForUser(Process.myUserHandle()) == 0L
else true
Then, using it is as simple as the following:
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
if (userManager.isCurrentUserDeviceOwner) TODO() else TODO()
You can further reduce boilerplate by using global system services definitions that makes userManager and other Android System Services available anywhere in your Kotlin code, with code included in this library I made: https://github.com/LouisCAD/Splitties/tree/master/systemservices
After researching further i found out that the multiuser api is not functional yet, it cant really be used for anything. there is a hack though for checking if the user is the owner using reflections:
public boolean isCurrentUserOwner(Context context)
{
try
{
Method getUserHandle = UserManager.class.getMethod("getUserHandle");
int userHandle = (Integer) getUserHandle.invoke(context.getSystemService(Context.USER_SERVICE));
return userHandle == 0;
}
catch (Exception ex)
{
return false;
}
}
This works for me on the Nexus 7 and Nexus 10 with Android 4.2.1
Its very dirty. so i wouldnt recommend using it unless you are making an app thats device and version specific