MvvmCross FilePlugin save files to SD card - android

We use beautiful MvvmCross framework in our app and we also utilize the FilePlugin to work with filesystem in a cross-platform way.
By default the FilePlugin stores data in some default location, like /data/data/<appname> in Android.
But what if I want to store big files, like video or 3D models? In iOS you store everything in app folder, but in Android you'll likely want to store files on SD card.
What solution would you recommend for this usecase?
I mean, should I inherit the FilePlugin and override app root directory for Android somehow?

I hade the same problem, and solved it by creating my own implementation of IMvxFileStore. My implementation allows me to specify an absolute path.
internal class CustomMvxAndroidFileStore : MvxFileStore
{
private Context _context;
private Context Context
{
get
{
if (_context == null)
{
_context = Mvx.Resolve<IMvxAndroidGlobals>().ApplicationContext;
}
return _context;
}
}
protected override string FullPath(string path)
{
if (PathIsAbsolute(path)) return path;
return Path.Combine(Context.FilesDir.Path, path);
}
private bool PathIsAbsolute(string path)
{
return path.StartsWith("/");
}
}
And then inject it during Setup of the app:
Mvx.RegisterType<IMvxFileStore, CustomMvxAndroidFileStore>();
This worked fine for me.

Related

How to get ApplicationContext in ReactContextBaseJavaModule?

I am building a React Native Application, in a react native module in Android code I wish to access the path for cache files used by Android code.
At some point I am writing (from the native code) a json file in the cache of the app data, I use getApplicationContext() to get the context and apply getCacheDir() to get the path of the cache files.
In a class extending ReactContextBaseJavaModule I want to access the Application context to get the cache files path, but when invoking getApplicationContext() on the React context and using getCacheDir() the path returned is not the same as the one returned before.
What is the way to get the Global context in a react native module ?
Cheers
ReactApplicationContext is passed in to the constructor of your class that extends ReactContextBaseJavaModule. You can call ReactApplicationContext.getApplicationContext() to get the ApplicationContext.
#Alan answer is great but I wanted to add a code snippet for more clarity :
public class FlashModule extends ReactContextBaseJavaModule {
Context context;
FlashModule(ReactApplicationContext context) {
super(context);
this.context = context.getApplicationContext(); // This is where you get the context
}
#Override
public String getName() {
return "FlashModule";
}
}

How get a android asset without a activity

I have a non visual class that need to read some files from the assets folder.
Is totally out-of-band so don't have a activity. How I can refer to it without pass down the activity?
Also I can accept a alternative to the assets way to put files (like .sql) to be read later on the android devices.
P.D:
This is a sample of the code where is called:
//Load asset not belong to anyone. Is that radical
let loadAsset(path:string) =
#if __ANDROID__
let sr = new StreamReader(?????.Assets.Open(path.Substring(1)))
seq {
while not sr.EndOfStream do
yield sr.ReadLine ()
}
#else
File.ReadLines(path)
#endif
What you really need is a Context. If you application has an Application class, you can use its Context to retrieve asset resources.
It should look something like this:
public class App extends Application {
public static Context context;
#Override public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
You can then used App.context to get resources/assets.
How to get an android asset without an Activity
Try using the following code:
let sr = new StreamReader(Android.App.Application.Context.Assets.Open(path.Substring(1)))

How to access Android resources e.g. dimensions in libgdx?

I need to get dimensions defined in XML files under Android folder from classes in Core directory of libgdx.
I know I can use assets folder for accessing drawables. But how about dimensions or strings?
You can't access this kind of platform specific information directly in the core project. But this can be achieved by interfacing these functions with a Facade, providing a platform-specific implementation for each target.
In libgdx-wiki there is an example for platform specific interfaces.
public interface PlatformSpecificStuff {
public String getString();
public int getDimensions();
}
// In -Android project
public class AndroidSpecificStuff implements PlatformSpecificStuff {
public String getString(){
// do whaterver you want with the resources.
return "string resource";
}
public int getDimensions(){
// do whaterver you want with the resources.
return 42;
}
}
// In -Desktop project
public class DesktopSpecificStuff implements PlatformSpecificStuff {
public String getString(){
// there is no xml or any andorid specific resource
return null;
}
public int getDimensions(){
// there is no xml or any andorid specific resource
return 0;
}
}
public class MyGame implements ApplicationListener {
private final PlatformSpecificStuff pss;
public MyGame(PlatformSpecificStuff pss) {
this.pss= pss;
}
}
Update: I don't know what are trying to accomplish by getting the dimensions as android resources. But you are probably in wrong track. If you want to support multiple screen sizes, have a look at viewports

Using internal android classes

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.

Why is Context "becoming" null on Application class?

Problem using Application
I'm rewriting an app (first 'version' had little-to-nothing in terms of analysis and it ended up piling a bunch of problems I wanted to get rid of) and I'm bumping my head against a problem that never showed up in the first version.
Thing is: I have a Class for geographical data. It just supplies String arrays that I can tuck into spinners adapters. Since I used a values xml file, the class needs access to Context to get the proper resources.
Since I use this geographical data in several points of the app, I thought I could create a Class to extend Application and, in onCreate, instantiate the Geography Class, I thought it would be more efficient to load it just once and use it as many times as I wanted. This worked on my first version:
This is MyApplication class
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
geografiaEspana = GeographyClass.getInstance(context);
}
public static GeographyClass getGeografiaEspana() {
if(ctx==null){
Log.w("TAPABOOK", "Tapabook.context nulo");
}
if (geografiaEspana==null){
Log.w("TAPABOOK", "Tapabook.geografiaEspana nula, instanciando");
geografiaEspana = GeographyClass.getInstance(ctx);
}
Log.i("TAPABOOK", "Tapabook.geografiaEspana instanciada");
return geografiaEspana;
}
And this is my GeographyClass
private static GeographyClass instance = null;
public static GeographySpain getInstance(Context context){
if(instance== null){
instance = new GeographySpain(context);
}
return instance;
}
public GeographySpain(Context context){
Resources res = context.getResources();
// load resources data
}
This worked, as I said, ok in my first version. However, in my new version I'm getting a NullPointerException on this line "Resources res = context.getResources();" I've checked and it turns out that the context I'm supplying it's null... And I don't get to understand why or what I'm doing wrong
Ok, I solved it (I'd swear I already commented on this, but since it's gone...).
Thing is, I'm not used to use Application classes and I had forgotten to declare MyApplication in the Manifest file. Noob mistake. As soon as I declared it, the app ran OK

Categories

Resources