Using a module in Titanium Alloy - android

I am working on a project in Titanium Alloy.
I need to use the Beacon module to scan for beacons using BLE.
My problem is that i can't get the module to work.
I used the Install mobile module to install the module and i enabled it in the tiapp.xml file.
This is the code i have at the moment:
var Beacons = require('com.logicallabs.beacons');
function doClick(beacon) {
if(Beacons.BeaconsModule.isEnabled()){
alert('succes');
}else{
alert("suces");
}
}
$.index.open();
The function gets launched when you click a label. The module contains 3 classes. Do you have to specify wich method from which class you have to use?
Also when i start this program i get errors saying Could not find class 'android.bluetooth.BluetoothManager and Could not find class 'com.logicallabs.beacons.ScanService$2

Here is slightly modified code from example app which is included in module which you installed:
var Beacons = require('com.logicallabs.beacons');
function log(text) {
Ti.API.info(text);
}
if (Beacons.isSupported()) {
log('Bluetooth is supported!');
if (Beacons.isEnabled()) {
log('Bluetooth is already enabled!');
} else {
log('Bluetooth is disbled; enabling now.');
// This will eventually fire a stateChanged event with state set to
// STATE_ON, at which point we start the scanning.
Beacons.enable();
}
} else {
log('Bluetooth LE is not supported.');
}
For more details check documentation and example app. On OSX you can find it in ~/Library/Application Support/Titanium/modules/android/com.logicallabs.beacons/ directory.

It will only work if you test on a device with Android API version is >= 18

Related

Kotlin-android: Unresolved reference

I have received this project from the previous developer, and he said everything is working fine on his end. But on my end, when I try to sync the project I get a lot of errors, and I don't know where to even start. One of them is this:
Here's that code:
private fun setupScrollDirection() {
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFolders == VIEW_TYPE_GRID
excluded_vertical_fastscroller.isHorizontal = false
excluded_vertical_fastscroller.beGoneIf(allowHorizontalScroll)
excluded_vertical_fastscroller.allowBubbleDisplay = config.showInfoBubble
excluded_vertical_fastscroller.setViews(manage_folders_list) {
excluded_vertical_fastscroller.updateBubbleText(getBubbleTextItem(it))
}
}
I have a lot more errors of the same type, like this one for example:
Please have a call with the other developer and ask him/her to share his screen on call.
When the screen is being shared, ask the developer to Ctrl+ Click on beGoneIf variable/function and then check where the beGoneIf is defined in the project. This way you can check whether the required library/dependencies used by other developer is present in your local project or not.

Android printing with Brother SDK via WiFi throws ERROR_WRONG_LABEL despite selecting correct labelNameIndex

I've been trying to print with Brother Print SDK 3.5.1 on Android 8.1.0. I keep getting ERROR_WRONG_LABEL.
This is the code I use
void printPdf() {
// Specify printer
final Printer printer = new Printer();
PrinterInfo settings = printer.getPrinterInfo();
settings.printerModel = PrinterInfo.Model.QL_810W;
settings.port = PrinterInfo.Port.NET;
settings.ipAddress = "192.168.1.73";
settings.workPath = "storage/emulated/0/Download/";
// Print Settings
settings.labelNameIndex = LabelInfo.QL700.W62RB.ordinal();
settings.printMode = PrinterInfo.PrintMode.FIT_TO_PAGE;
settings.orientation = PrinterInfo.Orientation.PORTRAIT;
settings.isAutoCut = true;
printer.setPrinterInfo(settings);
// Connect, then print
new Thread(new Runnable() {
#Override
public void run() {
if (printer.startCommunication()) {
PrinterStatus result = printer.printPdfFile("/storage/emulated/0/Download/hello world red.pdf", 1);
if (result.errorCode != PrinterInfo.ErrorCode.ERROR_NONE) {
Log.d("TAG", "ERROR - " + result.errorCode);
}
printer.endCommunication();
}
}
}).start();
}
My printer model is QL-810W and I use the black and red W62 roll.
I've tried the Sample Application, where setting W62RB in labelNameIndex prints fine.
Changing the roll for different one with different width didn't help.
I've also tried iterating over numbers 0 to 50 and using them as labelNameIndex.
Based on this thread, I thought that the issue may be in specifying the workPath attribute. Setting workPath to getContext().getCacheDir().getPath() results in ERROR_OUT_OF_MEMORY instead of ERROR_WRONG_LABEL. Not specifying workPath and adding <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> to AndroidManifest.xml results in ERROR_WRONG_LABEL
EDIT
I've modified the Brother Sample app and uploaded it to GitHub. The app now launches Activity_PrintPdf.java by default where I inserted my printing code with hardcoded values at the beginning of onCreate method - this works fine and prints the PDF file as expected.
Then I created a new Empty Activity project in Android Studio, copy pasted the library, added the imports to build.gradle and copy pasted the permissions into AndroidManifest.xml. Then I copy pasted the printing code at the beginning of onCreate method in MainActivity.java. Running the app results in ERROR_WRONG_LABEL.
This is the modified working example app and this is the one that results in the error. I want to use the code as native module that I call from my React Native app, so it's important that I manage to set up the printing code from scratch rather than modifying the existing example app.
EDIT 2
I've inspected the library with a debugger: when executing printer.setPrinterInfo(mPrinterInfo) the library internally calls private boolean createWorkPath(String dirPath) of Printer object. On return from this method, the debugger shows Source code doesn't match the bytecode and seems to forget the created directory. This also internally sets mResult.errorCode = ErrorCode.ERROR_WORKPATH_NOT_SET. However, instead of rising any error here the code just silently proceeds, which later results in ERROR_WRONG_LABEL when trying to print. Running the same code snipper in the modified Sample app works fine.
I'd be grateful if you could help or suggest what to try next.
Thank you!
I've now fixed the issue, which was that the Brother library silently failed to create a temporarily folder and instead of reporting an error, it continued and failed later to read the label information. Based on this thread, it is now required to specify runtime file read and write permissions as opposed to the compile-time ones in AndroidManifest.xml.
Adding
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
at the beginning of onCreate before the printing code fixed the issue.

Pepper Robot - How to launch tablet applications through DialogFlow?

I'm trying to incorporate Pepper's built in Android tablet more in DialogFlow interactions. Particularly, my goal is to open applications installed on the tablet itself for people to use while they're talking with Pepper. I'm aware there is a 'j-tablet-browser' app installed on Pepper's end that can let a person browse the tablet like an ordinary Android device, but I would like to take it one step further and directly launch an Android app, like Amazon's Alexa.
The best solution I can up with is:
User says specific utterance (e.g. "Pepper, open Alexa please")
DialogFlow launches the j-tablet-browser behavior
{
"speak": "Sure, just a second",
"action": "startApp",
"action_parameters": {
"appId": "j-tablet-browser/."
}
}
User navigates the Android menu manually to tap the Alexa icon
My ideal goal is to make the process seamless:
User says specific utterance (e.g. "Pepper, open Alexa please")
DialogFlow launches the Alexa app installed on the Android tablet
Does anyone have an idea how this could be done?
This is quite a broad question so I'll try and focus on the specifics for launching an app with a Dialogflow chatbot. If you don't already have a QiSDK Dialogflow chatbot running on Pepper, there is a good tutorial here which details the full process. If you already have a chatbot implemented I hope the below steps are general enough for you to apply to your project.
This chatbot only returns text results for Pepper to say, so you'll need to make some modifications to allow particular actions to be launched.
Modifying DialogflowDataSource
Step 2 on this page of the tutorial details how to send a text query to Dialogflow and get a text response. You'll want to modify it to return the full reponse object (including actions), not just the text. Define a new function called detectIntentFullResponse for example.
// Change this
return response.queryResult.fulfillmentText
// to this
return response.queryResult
Modifying DialogflowChatbot
Step 2 on this page shows how to implement a QiSDK Chatbot. Add some logic to check for actions in the replyTo function.
var response: DetectIntentResponse? = null
// ...
response = dataSource.detectIntentFullResponse(input, dialogflowSessionId, language)
// ...
return if (reponse.action != null) {
StandardReplyReaction(
ActionReaction(qiContext, response), ReplyPriority.NORMAL
)
} else if (reponse.answer != null) {
StandardReplyReaction(
SimpleSayReaction(qiContext, reponse.answer), ReplyPriority.NORMAL
)
} else {
StandardReplyReaction(
EmptyChatbotReaction(qiContext), ReplyPriority.FALLBACK
)
}
Now make a new Class, ActionReaction. Note that the below is incomplete, but should serve as an example of how you can determine which action to run (if you want others). Look at SimpleSayReaction for more implementation details.
class ActionReaction internal constructor(context: QiContext, private val response: DetectIntentResponse) :
BaseChatbotReaction(context) {
override fun runWith(speechEngine: SpeechEngine) {
if (response.action == "launch-app") {
var appID = response.parameters.app.toString()
// launch app at appID
}
}
}
As for launching the app, various approaches are detailed in other questions, such as here. It is possible to extend this approach to do other actions, such as running or retrieving online data.

Android dynamic feature module, resource not found

I'm having a problem starting an activity in a downloaded feature module when it's published to the play store. It always crashes on setContentView() in the downloaded modules activity.
java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx/xxxActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x7e080000
Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7e080000
at android.content.res.ResourcesImpl.getValue(ResourcesImpl.java:227)
at android.content.res.Resources.loadXmlResourceParser(Resources.java:2149)
at android.content.res.Resources.getLayout(Resources.java:1158)
at android.view.LayoutInflater.inflate(LayoutInflater.java:421)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
The really strange part is that if I publish a new version of the app (only change is versionCode) to play store and update the app everything works perfectly.
When I uninstall the app and install it again the crash returns.
my Application is inheriting SplitCompatApplication() and just to be sure I've since tried to add:
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
SplitCompat.install(this)
}
to the activty in the feature module and disabled proguard to make sure nothing is removed during minify
My SplitInstallStateUpdatedListener
private val listener = SplitInstallStateUpdatedListener { state ->
val multiInstall = state.moduleNames().size > 1
state.moduleNames().forEach { name ->
// Handle changes in state.
when (state.status()) {
SplitInstallSessionStatus.DOWNLOADING -> {
// In order to see this, the application has to be uploaded to the Play Store.
displayLoadingState(state, "Laddar ner $name")
}
SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> {
/*
This may occur when attempting to download a sufficiently large module.
In order to see this, the application has to be uploaded to the Play Store.
Then features can be requested until the confirmation path is triggered.
*/
startIntentSender(state.resolutionIntent()?.intentSender, null, 0, 0, 0)
}
SplitInstallSessionStatus.INSTALLED -> {
if(toInstall.isNotEmpty() && toInstall.contains(name)) {
toInstall.remove(name)
}
if(toInstall.isEmpty()) {
// Updates the app’s context with the code and resources of the
// installed module. (should only be for instant apps but tried it anyway, no change)
SplitInstallHelper.updateAppInfo(applicationContext)
Handler().post {
viewModel.goToOverview()
}
}
}
SplitInstallSessionStatus.INSTALLING -> displayLoadingState(state, "Installerar $name")
SplitInstallSessionStatus.FAILED -> {
toastAndLog("Error: ${state.errorCode()} for module ${state.moduleNames()}")
}
}
}
}
This code downloads modules depending on user claims and starts an activity in the base app
The downloaded modules activity is then started from a BottomSheetDialogFragment like this:
xxx.setOnClickListener(view -> {
Intent intent = new Intent();
String packageName = Constants.MODULE_BASEPACKAGE + "." + Constants.MODULE_XXXXX;
intent.setClassName(getActivity().getPackageName(),packageName + ".XxxxxActivity" );
ParcelUuid parcelUuid = new ParcelUuid(UUID.randomUUID());
intent.putExtra("uuid", parcelUuid);
startActivity(intent);
dismiss();
});
I'm all out of ideas about what to try next. It seems like it's something that doesn't update the resource list until an update is installed and a restart of the app is not enough, or am I just missing something simple?
You can always access the resources from the main project inside the dynamic module, so you could just put your resources for the dynamic module in the main app, and then use the R.java from the main App.
However, the proper way to open these resources is to use SplitCompat.install(this) inside the dynamic delivered activity
This seems to have been a bug in com.android.tools.build:gradle:3.2.1
When I upgraded to 3.3.0 the problem resolved itself.
Hopefully it might help someone else who has this problem...
I had an exactly same problem; fresh install crashes with Resources$NotFoundException, but subsequent upgrade works OK (the dynamic module is not downloaded again). But my case was slightly different, because instead of starting an Activity in the dynamic module, I wanted to load a Fragment through Navigation. In that case, I should have just navigated and let Navigation do its thing without manually checking the module was loaded or not (refer to https://developer.android.com/guide/navigation/navigation-dynamic for more info).
// Just navigate without calling splitInstallManager.installedModules.contains()
findNavController().navigate(DynamicDeliveryDirections.actionDynamicFragment())
If you want to start an Activity, you do need to check whether the module is loaded or not, as you are already doing. I suggest you take a look at Google's example, which does exactly what you are trying to do.
https://codelabs.developers.google.com/codelabs/on-demand-dynamic-delivery/index.html?index=..%2F..index#1
As for my case, I had to make sure the package names were correct. For example, if the main module's package name is com.example.foo and dynamic module is com.example.foo.dynamic_activity, then starting the Activity in the dynamic module would look like the following.
Intent().setClassName(
"com.example.foo",
"com.example.foo.dynamic_activity.DynamicActivity"
).also {
startActivity(it)
}
I don't know why it works, but for me using AppCompatActivity solves this problem

Appcelerator reset app to initial state

I am working on an app with Appcelerator.
Appcelerator uses nearly the same kind of require.js like node.js does.
Now I want to implement a feature that logges out the current user and does not leave any trace.
The most simple way would be to restart the app, but Appcelerator and especially Apple does not support this.
So i have to open the login window and clean all the data that leaves a trace to the old user.
The easiest way would be to dereference one of the main nodes in the require chain leaving all the data dereferenced and garbage collected.
I know there is a way (as mentioned here) to do that in node:
/**
* Removes a module from the cache
*/
function purgeCache(moduleName) {
// Traverse the cache looking for the files
// loaded by the specified module name
searchCache(moduleName, function (mod) {
delete require.cache[mod.id];
});
// Remove cached paths to the module.
// Thanks to #bentael for pointing this out.
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName)>0) {
delete module.constructor._pathCache[cacheKey];
}
});
};
/**
* Traverses the cache to search for all the cached
* files of the specified module name
*/
function searchCache(moduleName, callback) {
// Resolve the module identified by the specified name
var mod = require.resolve(moduleName);
// Check if the module has been resolved and found within
// the cache
if (mod && ((mod = require.cache[mod]) !== undefined)) {
// Recursively go over the results
(function traverse(mod) {
// Go over each of the module's children and
// traverse them
mod.children.forEach(function (child) {
traverse(child);
});
// Call the specified callback providing the
// found cached module
callback(mod);
}(mod));
}
};
So I tried to read out the require-cache in Appcelerator with:console.log(require, "-" ,require.cache); with an output like: <KrollCallback: 0x79f6fe50> - <null>
So now my questions:
Is there a way to reach the require-cache in Appcelerator?
Do you know a way to clean up a big Appcelerator-App?
Since it is possible to wirte native Modules for Appcelerator:
Do you know a way to clean up a big Android App?
Do you know a way to clean up a big iOS App?
Thank you very much

Categories

Resources