RFO-BASIC / Basic

The Repository for the files the Basic project that creates the BASIC! APK for Google Play
62 stars 42 forks source link

App.start PackageName Component #240

Open olimaticer opened 7 years ago

olimaticer commented 7 years ago

Solution for App.start (App.broadcast still fails)

    private Intent buildIntentForAPP() {
        // Six optional string expressions and two optional numeric expressions:
        // the action, data, package, component, type, categories, bundle pointer, flags
        byte[] type = { 2, 2, 2, 2, 2, 2, 1, 1 };
        Double[] nVal = { null, null, null, null, null, null, null, null  };
        String[] sVal = { null, null, null, null, null, null, null, null };

        if (!getOptExprs(type, nVal, sVal)) return null;
        String action = sVal[0];
        String data   = sVal[1];
        String pkg    = sVal[2];
        String comp   = sVal[3];
        String mime   = sVal[4];
        String cats   = sVal[5];
        Double bIdx   = nVal[6];
        Double flags  = nVal[7];

        Intent intent = new Intent();                           // corresponding adb "am start" parameters
        if (action != null) { intent.setAction(action); }       // am -a
        if (data != null) {                                     // am -d and -t
            Uri dataUri = Uri.parse(data);
            if (mime == null) { intent.setData(dataUri); }          // data, no MIME type
            else              { intent.setDataAndType(dataUri, mime); } // data and MIME type
        }
        else if (mime != null) { intent.setType(mime); }            // MIME type, no data
        if (pkg != null) {//vv2016-06-24gt Often you need the package name but no component!
            intent.setPackage(pkg);
        }//^^2016-06-24gt
        if (comp != null) {                                         // component name for am -n
            if (pkg != null) {
                //intent.setClassName(pkg, comp);                       // package name given
                intent.setComponent(new ComponentName(pkg,comp));//2016-06-24gt

            } else {
                //intent.setClassName(Run.this, comp);              // no package given
                intent.setComponent(new ComponentName(Run.this,comp));//2016-06-24gt
            }
        }
        if (cats != null) {                                     // am -c (multiple allowed)
            String[] catArray = sVal[5].split("\\s+,\\s+", 0);      // comma-separated list of categories
            for (String cat : catArray) { intent.addCategory(cat); }
        }
        if (bIdx != null) {                                     // am -e (limited subset)
            int bundleIndex = bIdx.intValue();                      // index of a bundle of extras
            if ((bundleIndex <= 0) || (bundleIndex >= theBundles.size())) {
                return null;                                        // expression is not valid Bundle pointer
            }
            intent.putExtras(theBundles.get(bundleIndex));
        }
        if (flags != null) { intent.addFlags(flags.intValue()); } // am -f
        return intent;
    }

Now BASIC!-dependent Apps can start properly.

Gregor

jMarcS commented 7 years ago

That's a very concise fix!

But I am not clear about what you are fixing. "Often you need the package name but no component!" and "Now BASIC!-dependent Apps can start properly." Can you give an example of a case that fails without your fix?

Also, with this fix, if both pkg and comp are non-null, it will run both intent.setPackage(pkg) and intent.setComponent(new ComponentName(pkg,comp)). Is that okay? Perhaps the two if blocks should be combined -- it makes the change less concise, but it may make the code more efficient. (Remember that there is no value in keeping a record of changes in the source -- that's what git does for you. The code should always look like it would if it had been done right in the first place!)

Finally, why did you change intent.setClassName to intent.setComponent? (I am not saying that you should not do that. I want to understand why it is better.)

olimaticer commented 7 years ago

There is a link to the Forum https://www.tapatalk.com/groups/rfobasic/app-broadcast-start-t3922.html In this thread it is also a link to a system write command "am start ... ", but today dead. This last link pointed to a working solution on System level.

APP.START "android.intent.action.MAIN", , "com.rfo.MyApp", "com.rfo.MyApp.Basic" APP.START "android.intent.action.MAIN" , , "com.rfo.basic", "com.rfo.basic.Basic"

I use .setComponent (Usually optional) Explicitly set the component to handle the intent. If left with the default value of null, the system will determine the appropriate class to use based on the other fields (action, data, type, categories) in the Intent. If this class is defined, the specified class will always be used regardless of the other fields. You should only set this value when you know you absolutely want a specific class to be used; otherwise it is better to let the system find the appropriate class so that you will respect the installed applications and user preferences. Parameters: component The name of the application component to handle the intent, or null to let the system find one for you.Returns:Returns the same Intent object, for chaining multiple calls into a single statement. , because it runs well in my test version with the App.SAR command as one of the single line commands.

Yes you can combine these two if blocks. As I fixed that, I had the opinion, that setting the component is a really seldom option. If you want to interact with two instances of BASIC! for receiving results at finishing one Basic! instance, you need the component. But before you combine APP.Broadcast should be fixed first, deleted or enhanced with a separate buildIntentForAPPbroadcast(). For a USB/RS232 interface I implemented a faster BROADCAST command interface in the test version.

Gregor

olimaticer commented 7 years ago

After tests, It seems, that with additonal information Android calls the intents not in an expected way. If I use my APP.SAR I put only relevant elements into the intent bundle. App.Start and App.Broadcast put unusesd elements also into the intent bundle. In this case app.broadcast crashs.

Gregor

olimaticer commented 7 years ago

Finally, why did you change intent.setClassName to intent.setComponent? (I am not saying that you should not do that. I want to understand why it is better.)

Remembering: Eclipse suggestion after typing a point.

APP.START "android.intent.action.MAIN", , "com.rfo.MyApp", "com.rfo.MyApp.Basic" Should also work, but does not. Only APP.START , , "com.rfo.MyApp", "com.rfo.MyApp.Basic" works today.

Gregor