Categories
discuss

How to map lambda expressions in Java

I’m coming from Python, and trying to understand how lambda expressions work differently in Java. In Python, you can do stuff like:

opdict = { "+":lambda a,b: a+b, "-": lambda a,b: a-b, 
           "*": lambda a,b: a*b, "/": lambda a,b: a/b }
sum = opdict["+"](5,4) 

How can I accomplish something similar in Java? I have read a bit on Java lambda expressions, and it seems I have to declare an interface first, and I’m unclear about how and why you need to do this.

Edit: I attempted to do this myself with a custom interface. Here’s the code I have tried:

Map<String, MathOperation> opMap = new HashMap<String, MathOperation>(){
        { put("+",(a,b)->b+a);
          put("-",(a,b)->b-a);
          put("*",(a,b)->b*a);
          put("/",(a,b)->b/a); }
};
...
...

interface MathOperation {
   double operation(double a, double b);
}

However, this gives an error:

The target type of this expression must be a functional interface.

Where exactly do I declare the interface?

Answer

Easy enough to do with a BiFunction in Java 8:

final Map<String, BiFunction<Integer, Integer, Integer>> opdict = new HashMap<>();
opdict.put("+", (x, y) -> x + y);
opdict.put("-", (x, y) -> x - y);
opdict.put("*", (x, y) -> x * y);
opdict.put("/", (x, y) -> x / y);

int sum = opdict.get("+").apply(5, 4);
System.out.println(sum);

The syntax is a bit more verbose than Python to be sure, and using getOrDefault on opdict would probably be preferable as to avoid a scenario in which you use an operator that doesn’t exist, but this should get the ball rolling at least.

If you’re exclusively working with ints, using IntBinaryOperator would be preferable, as this would take care of any generic typing that you’d have to do.

final Map<String, IntBinaryOperator> opdict = new HashMap<>();
opdict.put("+", (x, y) -> x + y);
opdict.put("-", (x, y) -> x - y);
opdict.put("*", (x, y) -> x * y);
opdict.put("/", (x, y) -> x / y);

int sum = opdict.get("+").applyAsInt(5, 4);
System.out.println(sum);
Categories
discuss

Regular Expression for Extracting Operands from Mathematical Expression

No question on SO addresses my particular problem. I know very little about regular expression. I am building an expression parser in Java using Regex Class for that purpose. I want to extract Operands, Arguments, Operators, Symbols and Function Names from expression and then save to ArrayList. Currently I am using this logic

String string = "2!+atan2(3+9,2+3)-2*PI+3/3-9-12%3*sin(9-9)+(2+6/2)" //This is just for testing purpose later on it will be provided by user
List<String> res = new ArrayList<>();
Pattern pattern = Pattern.compile((\Q^\E|\Q/\E|\Q-\E|\Q-\E|\Q+\E|\Q*\E|\Q)\E|\Q)\E|\Q(\E|\Q(\E|\Q%\E|\Q!\E)) //This string was build in a function where operator names were provided. Its mean that user can add custom operators and custom functions 
Matcher m = pattern.matcher(string);
int pos = 0;
while (m.find()) 
{
    if (pos != m.start()) 
    {
        res.add(string.substring(pos, m.start()))
    }
    res.add(m.group())
    pos = m.end();
}
if (pos != string.length()) 
{
     addToTokens(res, string.substring(pos));
}
for(String s : res)
{
     System.out.println(s);
}

Output:

2
!
+
atan2
(
3
+
9
,
2
+
3
)
-
2
*
PI
+
3
/
3
-
9
-
12
%
3
*
sin
(
9
-
9
)
+
(
2
+
6
/
2
)

Problem is that now Expression can contain Matrix with user defined format. I want to treat every Matrix as a Operand or Argument in case of functions.

Input 1:

String input_1 = "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6"

Output Should be:

2
+
3
-
9
*
[{2+3,2,6},{7,2+3,2+3i}]
+
9
*
6

Input 2:

String input_2 = "{[2,5][9/8,func(2+3)]}+9*8/5"

Output Should be:

{[2,5][9/8,func(2+3)]}
+
9
*
8
/
5

Input 3:

String input_3 = "<[2,9,2.36][2,3,2!]>*<[2,3,9][23+9*8/8,2,3]>"

Output Should be:

<[2,9,2.36][2,3,2!]>
*
<[2,3,9][23+9*8/8,2,3]>

I want that now ArrayList should contain every Operand, Operators, Arguments, Functions and symbols at each index. How can I achieve my desired output using Regular expression. Expression validation is not required.

Answer

I think you can try with something like:

(?<matrix>(?:[[^]]+])|(?:<[^>]+>)|(?:{[^}]+}))|(?<function>w+(?=())|(d+[eE][-+]d+)|(?<operand>w+)|(?<operator>[-+/*%])|(?<symbol>.)

DEMO

elements are captured in named capturing groups. If you don’t need it, you can use short:

[[^]]+]|<[^>]+>|{[^}]+}|d+[eE][-+]d+|w+(?=()|w+|[-+/*%]|.


The [[^]]+]|<[^>]+>|{[^}]+} match opening bracket ({, [ or <), non clasing bracket characters, and closing bracket (},],>) so if there are no nested same-type brackets, there is no problem. Implementatin in Java:

public class Test {
    public static void main(String[] args) {
        String[] expressions = {"2!+atan2(3+9,2+3)-2*PI+3/3-9-12%3*sin(9-9)+(2+6/2)", "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6",
        "{[2,5][9/8,func(2+3)]}+9*8/5","<[2,9,2.36][2,3,2!]>*<[2,3,9][23 + 9 * 8 / 8, 2, 3]>"};
        Pattern pattern = Pattern.compile("(?<matrix>(?:\[[^]]+])|(?:<[^>]+>)|(?:\{[^}]+}))|(?<function>\w+(?=\())|(?<operand>\w+)|(?<operator>[-+/*%])|(?<symbol>.)");
        for(String expression : expressions) {
            List<String> elements = new ArrayList<String>();
            Matcher matcher = pattern.matcher(expression);
            while (matcher.find()) {
                elements.add(matcher.group());
            }
            for (String element : elements) {
                System.out.println(element);
            }
            System.out.println("nnn");
        }
    }
}

Explanation of alternatives:

  • [[^]]+]|<[^>]+>|{[^}]+} – match opening bracket of given type, character which are not closing bracket of that type (everything byt not closing bracket), and closing bracket of that type,
  • d+[eE][-+]d+ = digit, followed by e or E, followed by operator + or -, followed by digits, to capture elements like 2e+3
  • w+(?=() – match one or more word characters (A-Za-z0-9_) if it is followed by ( for matching functions like sin,
  • w+ – match one or more word characters (A-Za-z0-9_) for matching operands,
  • [-+/*%] – match one character from character class, to match operators
  • . – match any other character, to match other symbols

Order of alternatives is quite important, as last alternative . will match any character, so it need to be last option. Similar case with w+(?=() and w+, the second one will match everything like previous one, however if you don’t wont to distinguish between functions and operands, the w+ will be enough for all of them.

In longer exemple the part (?<name> ... ) in every alternative, is a named capturing group, and you can see in demo, how it group matched fragments in gorups like: operand, operator, function, etc.

Categories
discuss

add ionic framework to an existing android studio app

I’m developing a project with android studio for a ODROID XU4 board. Because of the nature of the project I’m using android studio to make a native app in order to use some of the Harware features of the board as Ethernet, GPIO,… and because there is no intention of developing this for any other platform.

The problem now is that the customer wants a nice looking ionic interface. I’ve been testing most of the approaches I found in google, ionic forums, stack overflow and many others sites but without success.

The nearest I’ve got is creating an ionic app, adding android platform and importing it to android studio.

My first question is: 1- Is this the correct approach?

My work flow is:

ionic start myapp 
ionic platform add android
ionic build android

and then I import the myapp folder with android studio. first of all I get an android studio error:

 19:40:40 Migrate Project to Gradle?
         This project does not use the Gradle build system. We recommend that you migrate to using the Gradle build system.
         More Information about migrating to Gradle
         Don't show this message again.
19:40:41 Update Property Files
         The structure of following Android modules was changed:
         android
         CordovaLib
         Would you like to update related project.properties files?
         Only once
         Always for these modules
         Never for these modules
19:40:44 Update Property Files
         The structure of following Android modules was changed:
         android
         Would you like to update related project.properties files?
         Only once
         Always for these modules
         Never for these modules
19:40:45 IndexNotReadyException: Please change caller according to com.intellij.openapi.project.IndexNotReadyException documentation
19:48:09 Error Report: Submitted

Now its time to migrate the project to gradle:

here is the main problem, I don’t know where to put the new gradle file or how to continue. enter image description here

thanks.

Answer

First off: Your looking in the right direction. This is the correct approach. However, I think your problem is based on the fact that you importing the wrong folder to Android Studio.

Please import the folder “android” that is generated by ionic (cordova) in your myApp/platforms folder.

The recent Versions of cordova are using the Gradle build system. So if generated with a recent version of cordova the gradle build configuration files are already existing in that “android” folder.

By importing the myapp folder (as you did) these files are not present in your Android Studio projekt. Hence you see the error: This project does not use the Gradle build system.

Categories
discuss

How to make my Android app appear in the app chooser when emailing a WhatsApp chat?

I am interested in making my app appear in the apps list shown when I use the “email conversation” feature in WhatsApp.

When logging my phone while using the “email conversation” WhatsApp feature I can see a SEND_MULTIPLE intent being received by Gmail:

I/ActivityManager(  859): START u0 {act=android.intent.action.SEND_MULTIPLE typ=text/* flg=0xb080001 pkg=com.google.android.gm cmp=com.google.android.gm/.ComposeActivityGmail (has clip) (has extras)} from uid 10114 on display 0

So I suppose I need to add an intent filter for the SEND_MULTIPLE action in my app manifest.

Currently my AndroidManifest.xml is:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="co.xxx.xxx" >


<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >


    <activity
        android:name=".MyActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>


        <intent-filter>
            <action android:name="android.intent.action.SENDTO" />

            <data android:scheme="mailto" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

        <intent-filter>
            <action android:name="android.intent.action.VIEW" />

            <data android:scheme="mailto" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
        </intent-filter>

        <intent-filter>
            <action android:name="android.intent.action.SEND_MULTIPLE" />

            <data android:mimeType="*/*" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

        <intent-filter>
            <action android:name="android.intent.action.SEND" />

            <data android:mimeType="*/*" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

    </activity>

</application>

</manifest>

However, when I run my app in my phone via Android Studio, it does not show up when trying to export my WhatsApp conversation. Conversely, it shows up in the app chooser when trying to share a picture of my gallery.

What am I missing in the AndroidManifest that prevents my app from being shown when emailing my WhatsApp conversations? Is there something else I need to announce to the OS to make my app elligible for appearing in the app chooser?

I have tried to install K-9 Mail app. Just after installing it, it does not appear in the app chooser when emailing a chat in WhatsApp, but after setting up an account in K-9, it appears in the chooser. Is it possible that K9 announces to the OS that it is ready for sending emails?

Thank you!

Answer

Unfortunately even if your manifest is properly configured you cannot see your app in the app chooser when emailing a chat because your app need to be whitelisted by WhatsApp. Only the chosen package names will be available in the WhatsApp’s app chooser.

For example we have an app with the package name com.example.whatsappemailchat. The AndroidManifest.xml is something like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.whatsappemailchat" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.whatsappemailchat.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SENDTO"/>
                <data android:scheme="mailto"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
                <data android:mimeType="*/*"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE"/>
                <data android:mimeType="*/*"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <data android:scheme="mailto"/>

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

and this is the build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.example.whatsappemailchat"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Everything is correctly configured, we run our application, but if we choose More > Email chat our app will not appear.

Now change the applicationId to com.google.android.gm.test (the package name of Gmail plus .test as suffix to avoid collision with real Gmail) in our build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.google.android.gm.test"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Now run our application, open WhatsApp, select a chat, choose More > Email chat and magically our app will be in the app chooser, as you can see in this screenshot:

enter image description here

I can confirm that these package names are whitelisted by WhatsApp:

  • com.google.android.gm
  • com.fsck.k9
  • com.boxer.email
  • com.google.android.email

I think that the only viable solution is to try to contact WhatsApp and ask if it’s possible to whitelist your package name.

Categories
discuss

How to remove Log.d() calls in release build of an Android app?

I have noticed that my release build, which i made in eclipse via:

Android Tools -> Export signed application package …

My proguard-project.txt contains:

-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int v(...);
    public static int i(...);
    public static int w(...);
    public static int d(...);
    public static int e(...);
}

Yet, if I run the app on a device und use CatLog to look at logs I see that there are all the Log.d(), Log.v() messages that shouldn’t be there. Is there something else I should set? I have spent many hours googling but there are no clear instructions on that subject. Well most of the things i find are people with similar problems but no solutions.

Answer

Make sure your proguard configuration does not have -dontoptimize in it. It’s the proguard optimizer that removes method calls that have “no side effects”.

The SDK default proguard-android.txt has -dontoptimize in it. Use proguard-android-optimize.txt instead, and don’t add -dontoptimize in your project-specific proguard configuration.

Could you please state some source where I could read up on the subject. If it exists of course.

Well, for starters -assumenosideeffects is listed under optimization options in the documentation.

One more thing bothers is that, I have read that using proguard-android-optimize.txt can cause problems on some devices. So, it is a sort od catch 22 situation.

Proguard in general can have side effects. You need to test your proguard-processed application thoroughly.


If you want to remove logging from release builds without using proguard at all, you can e.g. add

if (BuildConfig.DEBUG)

before every logging call where BuildConfig is the build configuration generated by the Gradle Android plugin. Since the DEBUG there is a compile-time constant, the Java compiler sees the condition can never be true on a release configuration and won’t emit the bytecode inside the conditional block.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..