Using internal android classes - android

I want to use an android internal class, com.android.internal.widget.LockPatternUtils .
I searched for examples and I got this:
LockPatternUtils lpu = new LockPatternUtils(this.getContentResolver());
However, i cant import, autimport does not appear and manually doing
import com.android.internal.widget.LockPatternUtils
doesnt work.
How is this handled? I think there was something about creating an interface but not sure about it
EDIT: I got this:
boolean patternLocked = android.provider.Settings.System.getInt(
getContentResolver(),Settings.System.LOCK_PATTERN_ENABLED, 0)==1;
That works for the pattern lock, but i cant know about the pin or password lock

Use reflection to access the internal Android method getActivePasswordQuality (line 350 of LockPatternUtils.java) and compare the int it returns to the int for any of the DevicePolicyManager Constants:
protected boolean isSecure() {
String LOCK_PATTERN_UTILS = "com.android.internal.widget.LockPatternUtils";
try {
Class<?> lockPatternUtilsClass = Class.forName(LOCK_PATTERN_UTILS);
Object lockPatternUtils = lockPatternUtilsClass.getConstructor(Context.class).newInstance(this);
Method method = lockPatternUtilsClass.getMethod("getActivePasswordQuality");
int lockProtectionLevel = Integer.valueOf(String.valueOf(method.invoke(lockPatternUtils)));
// Then check if lockProtectionLevel == DevicePolicyManager.TheConstantForWhicheverLevelOfProtectionYouWantToEnforce, and return true if the check passes, false if it fails
}
catch (Exception ex) {
ex.printStackTrace();
}
return false;
}

How is this handled?
Those classes are only available as part of full firmware builds, not from Android SDK apps.

You can not use Android internal classes, they do not come with the public SDK.
You can build your own SDK exposing them more or less as they do here How do I build the Android SDK with hidden and internal APIs available?
This is not recommended because you will have no guarantees.

Related

How to send data from Android to Flutter properly?

I'm trying to send data back and forth from Flutter to my native platform (in this case Android).
In order to keep some model consistency, I have generated the models for all platforms by using Protocol-Buffers.
When I try to pass data from Android to Flutter I'm not finding any way to do it without shenanigans like serializing to a handcrafted JSON.
There must be a way to use protobuf in order to do so, isn't it?
In order to give context, I have made a minimal app to try to solve this problem:
My Protocol Buffer
syntax = "proto3";
option java_package = "com.test.protobuf_test";
option java_outer_classname = "ProtoModel";
message SimplePerson {
int32 id= 1;
string name= 2;
}
From which I generate my model using:
protoc --java_out and protoc --dart_out
In Dart I get my class
class SimplePerson extends $pb.GeneratedMessage {...}
And in Java
public final class ProtoModel {
...
public static final class SimplePerson extends
com.google.protobuf.GeneratedMessageV3 implements
SimplePersonOrBuilder {...}
}
From Android inside my method channel, I am trying to pass one or many ProtoModel.SimplePerson objects back to Dart.
No success so far.
How would you actually do it?
I'd expect it to be something like
In Java:
ProtoModel.SimplePerson person = ProtoModel.SimplePerson.newBuilder().setId(3).setName("Person Name").build();
result(person);
And in Dart:
var result = await platform.invokeMethod("generatePerson");
if(result is SimplePerson) {
print("Success!");
} else {
print("Failure!");
}
So far I'm only getting Failures or Exceptions.
Thanks!
your very close your using result but i have it working with result.success
when (call.method) {
"getPlatformVersion" -> result.success(getPlatformVersion().toByteArray())
}
private fun getPlatformVersion(): Models.Version {
return Models.Version.newBuilder().setVersionName("Android ${android.os.Build.VERSION.RELEASE}").build()
}
great example here https://www.freecodecamp.org/news/flutter-platform-channels-with-protobuf-e895e533dfb7/
EDIT didnt see how old this post was
I have to use this as Pigeon is sill early access, and although pigeon was generally harder to set up i do prefer it

Why does Carto Package Manager can't connect to it's database after resuming?

We are using Carto Xamarin Mobile SDK to develop app with offline maps support. It works fine until user does not try to resume application after it has been disposed. Activity creation (activity uses carto package manager) crashes with exception:
Carto.PackageManager.CartoPackageManager.CartoPackageManager(string source, string dataFolder)<01980a2dae7148abb92e6b982667f448>:0
App.Droid.OfflineMaps.AndroidMapPackageManager.AndroidMapPackageManager()<76ae23b9271c407d865ebb6162639870>:0
App.Droid.Plugins.MapDownloader.Plugin.<>c.<Load>b__0_0()<76ae23b9271c407d865ebb6162639870>:0
MvvmCross.Platform.IoC.MvxSimpleIoCContainer.<>c__DisplayClass33_0<TInterface>.<RegisterSingleton>b__0()<4ddde23419c5494288c799fcdbb0f189>:0
MvvmCross.Platform.IoC.MvxSimpleIoCContainer.ConstructingSingletonResolver.Resolve()<4ddde23419c5494288c799fcdbb0f189>:0
MvvmCross.Platform.IoC.MvxSimpleIoCContainer.InternalTryResolve(Type type, MvxSimpleIoCContainer.IResolver resolver, ref object resolved
App.Core.ViewModels.Blocks.Maps.Offline.MapDownloaderOwnerViewModel.EnableMapDownloader(City city)<d6cca792b401420d922bc024
Here on line 105 you can see where exception is originally thrown.
In the regular entering page it works fine.
PackageManager request is happening in the ctor of the page ViewModel via:
Mvx.Resolve<MapDownloadsManager>(); // It receivs as injection platform-dependent packageManager
It seems that the problem is in the database path.
We are generating the folder name that then passed to the CartoPackageManager constructor in the following way:
private static string CreateFolder(string folderPath)
{
var folder = GetDocumentDirectory(folderPath);
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
return folder;
}
private static string GetDocumentDirectory(string withFolder = null)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
return withFolder == null ? documents : Path.Combine(documents, withFolder + "/");
}
Do you have any ideas where the source of the problem could be?
P.S.: Carto SDK v 4.0.2, MvvmCross 4.4.0, unfortunately can't update to the newer now.
After some research I have spotted that task queue is reset, now supposing that app actually crashes here in source code:
std::string taskDbFileName = "tasks_v1.sqlite";
try {
_taskQueue = std::make_shared<PersistentTaskQueue>(createLocalFilePath(taskDbFileName));
}
catch (const std::exception& ex) {
//This looks like: Error while constructing PackageManager: Package encryption keys do not match, trying to remove
Log::Errorf("PackageManager: Error while constructing PackageManager::PersistentTaskQueue: %s, trying to remove...", ex.what());
_taskQueue.reset();
utf8_filesystem::unlink(taskDbFileName.c_str());
try {
_taskQueue = std::make_shared<PersistentTaskQueue>(createLocalFilePath(taskDbFileName));
}
catch (const std::exception& ex) {
**throw FileException("Failed to create/open package manager task queue database", taskDbFileName); //App gets here.**
}
}
Initialization of package manager:
public class AndroidMapPackageManager : PackageManagerListener, IPackageManger
{
private readonly CartoPackageManager _packageManager;
public AndroidMapPackageManager()
{
var folder = CreateFolder(OfflineMapStrings.MapsFolderName); // /data/user/0/com.app.cityguide/files/mapmap2/
_packageManager =
new CartoPackageManager(OfflineMapsStrings.PackageManagerSource, folder)
{
PackageManagerListener = this
};
}
}
I am starting it just after the constructor worked after subscription to the listener events by other class. And, frankly saying, I never stop it. Do I need it?
With FIllRam Repoductivity is 100%. I used debug mode with no background allowed and now I tryed Ram Filler and result is same.
License issues:
05-25 12:41:41.091 26101 26101 E carto-mobile-sdk: CartoPackageManager: RegisterLicense not called, using random key for package encryption!
05-25 12:41:41.094 26101 26101 E carto-mobile-sdk: PackageManager: Error while constructing PackageManager: Package encryption keys do not match, trying to remove
The problem was that I was registering license key in SplashActivity. But, after resuming splash activity is not shown and, obviously, Registering of the license key was not performed. I have moved it to the custom application class and it worked:
public class CustomApplication : Application
{
public override void OnCreate()
{
base.OnCreate();
MapView.RegisterLicense(CartoApiKey, this);
}
}

Android Suporting older SDK where the method is not available

I've been looking for an answer but have not found a way to do it yet I hope somebody could point me in the right direction
I want support sdk8 and up, there is this method createInsecureRfcommSocketToServiceRecord
from the android.bluetooth.BluetoothDevice library that is supported on SDk10 and up only
Quick and dirty is make the minSDK=10 but I dont want to leave my users with older devices out in the cold
I've seen pretty involved(or should I say wacky) ways of attempting this , reflections??? but they all fail for me the simplest way I thought would be:
if( Build.VERSION.SDK_INT>=10)
{
BluetoothDevice device;
Class myC = ClassforName("android.bluetooth.BluetoothDevice")
Method myM = myC.getDeclaredMethod("createInsecureRfcommSocketToServiceRecord");
BluetoothSocket bb = (BluetoothSocket)myM.invoke(device, MYUUID);
}
But it throws a NoSuchExceptionMethod, so it looks like maybe the library has to have other name???? or how would you handle this??
Thanks in advance
If you don't want to increase your minSDK version you have either to wrap your calls with reflection ...
BluetoothDevice device;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
Class myC = ClassforName("android.bluetooth.BluetoothDevice")
Method myM = myC.getDeclaredMethod("createInsecureRfcommSocketToServiceRecord",
new Class[] { UUID.class } );
BluetoothSocket bb = (BluetoothSocket)myM.invoke(device, MYUUID);
}
... or you provide an (abstract) class android.bluetooth.BluetoothDevice that has only some empty method stubs. That allows you to compile your source without any errors. During run time the virtual machine will try to load that class from the system.
public abstract class BluetoothDevice {
BluetoothDevice () {
}
public void createInsecureRfcommSocketToServiceRecord(UUID uuid) {
}
}
The class has to be place in root-source/android/bluetooth. In any case it's important that you restrict any call to the right OS version (see my code above) otherwise you might get an NoSuchExceptionMethod -exception.
Finally: don't forget the signature (parameters) of the method (in getDeclaredMethod()).
Cheers!
You have to pass also the declared parameters
Class myC = ClassforName("android.bluetooth.BluetoothDevice")
Method myM = myC.getDeclaredMethod("createInsecureRfcommSocketToServiceRecord",UUID.class);

Is it safe to write Android compatible code this way?

is it safe to write such compatible code on Android?
if (Build.os.SDK_INT >= 11) {
newClass instance = new newClass();
....
}
else {
oldClass instance = new oldClass();
....
}
one of my colleagues argue with me that ClassNotFoundException might be thrown up when running the above code since ClassLoader is attempting to load newClass on an android os device which is below android 11. But I've tried couple times, and didn't see this happen.
After googling around for couple hours, I didn't find any information on how and when android default classLoader loads a specific class.
You should check the compatability like the following... It gives you more accurate than the above:
private static int currentApi = 0;
public static int getApiLevel() {
if (currentApi > 0) {
return currentApi;
}
if (android.os.Build.VERSION.SDK.equalsIgnoreCase("3")) {
currentApi = 3;
} else {
try {
Field f = android.os.Build.VERSION.class.getDeclaredField("SDK_INT");
currentApi = (Integer) f.get(null);
} catch (Exception e) {
return 0;
}
}
return currentApi;
}
you can alway use reflection to check if the class exists:
try {
Class.forName("yourclass")
} catch (ClassNotFoundExecption) {
oldClass instance = new oldClass();
}
Yes, this is safe to do on recent versions of Android. I want to say froyo and above, but it may have been even earlier than that. I don't recall for sure.
What happens is that dalvik performs a verification pass on the dex file at install time. For any classes/methods/fields that it can't resolve, it replaces those accesses with an instruction that throws a VerifyError.
In your example, if that code got loaded on, e.g. api 10, newClass instance = new newClass() would conceptually be replaced with throw new VerifYError(). So as long as that branch never gets executed at runtime, everything is good.
Short answer - don't do it.
Most VMs only load a class when it is absolutely needed. However a class loader is allowed to cache binary representation of classes beforehand[1].
Class loaders are allowed to cache binary representations of types,
load types early in anticipation of eventual use, or load types
together in related groups.
[1] - http://www.artima.com/insidejvm/ed2/lifetype2.html
[2] - http://developer.android.com/tools/extras/support-library.html
Edit - Have you checked if the class you need is available as part of the android support package ? [2]

Android In-app billing general questions

I know In-App billing is new in Android and I would like to use it, but the version requirements make me think twice whether it's worth the effort. I would appreciate any input from those who have implemented or worked with In App Billing in detail.
I still have 10% 1.5 users. In app billing requires at least 1.6 to work. Does that mean 1.5 users will crash immediately? If not, at what point does it fail? I don't want to write a bunch of hacky code to stay compatible with 1.5 users.
If user reinstalls the app, are their app purchases remembered?
At what point does it fail if you don't have the required Market version?
Thanks.
Regarding version support, you'll have write some extra code to detect the device OS version (see android.os.Build.VERSION) so make sure it will run on 1.5 devices. I strongly suggest isolating that code in its own class, and only instantiate that class after your version check. That way your code stays clean (not "hacky") and you don't accidentally reference a 1.6+ class from a class field. In my code, I have version test classes that look like this:
public class Android8 {
private static final String TAG = "Android8";
// public test variables
public static final boolean IS_V8;
public static final boolean AT_LEAST_V8;
private static final Object pimpl;
static {
int sdk_int = 0;
try {
Field field = Build.VERSION.class.getField( "SDK" );
String sdk_str = (String)field.get( null );
sdk_int = Integer.parseInt( sdk_str );
} catch( Throwable e ) {
}
IS_V8 = (sdk_int==8);
AT_LEAST_V8 = (sdk_int>=8);
if( AT_LEAST_V8 ) {
pimpl = new Implementation();
} else {
pimpl = null;
}
}
// Version safe interface
public static void Camera_setDisplayOrientation( Camera camera, int degrees ) {
if( AT_LEAST_V8 )
((Implementation)pimpl).Camera_setDisplayOrientation( camera, degrees );
}
// Will cause a verify error if loaded in a pre Android8 environment
private static final class Implementation {
public static void Camera_setDisplayOrientation( Camera camera, int degrees ) {
camera.setDisplayOrientation( degrees );
}
}
}
Question 2: NO, if items are UNMANAGED. Yes if they are.
That's the point with managed items, let's the Google's servers manage (remenber) the purchased items for this sort of cases.
(The "manage by user account" purchase type is useful if you are selling items such as game levels or application features. These items are not transient and usually need to be restored whenever a user reinstalls your application, wipes the data on their device, or installs your application on a new device.)
from: http://developer.android.com/guide/market/billing/billing_admin.html#billing-purchase-type

Categories

Resources