7 package com.google.appinventor.components.runtime;
9 import android.app.Activity;
11 import android.content.ActivityNotFoundException;
12 import android.content.ComponentName;
13 import android.content.Intent;
14 import android.content.pm.PackageManager;
15 import android.content.pm.ResolveInfo;
17 import android.net.Uri;
19 import android.text.TextUtils;
21 import android.util.Log;
76 @DesignerComponent(version = YaVersion.ACTIVITYSTARTER_COMPONENT_VERSION,
77 designerHelpDescription =
"A component that can launch an activity " +
78 "using the <code>StartActivity</code> method." +
79 "<p>Activities that can be launched include: <ul> \n" +
80 "<li> starting other App Inventor for Android apps </li> \n" +
81 "<li> starting the camera application </li> \n" +
82 "<li> performing web search </li> \n" +
83 "<li> opening a browser to a specified web page</li> \n" +
84 "<li> opening the map application to a specified location</li></ul> \n" +
85 "You can also launch activities that return text data. See the " +
86 "documentation on using the Activity Starter for examples.</p>",
91 description =
"A component that can launch an activity using " +
92 "the <code>StartActivity</code> method. \n" +
93 "<p>Activities that can be launched include:<ul> " +
94 "<li> Starting another App Inventor for Android app. \n To do so, first " +
95 " find out the <em>class</em> of the other application by " +
96 " downloading the source code and using a file explorer or unzip " +
97 " utility to find a file named " +
98 " \"youngandroidproject/project.properties\". \n The first line of " +
99 " the file will start with \"main=\" and be followed by the class " +
100 " name; for example, " +
101 " <code>main=com.gmail.Bitdiddle.Ben.HelloPurr.Screen1</code>. " +
102 " (The first components indicate that it was created by " +
103 " Ben.Bitdiddle@gmail.com.) \n To make your " +
104 " <code>ActivityStarter</code> launch this application, set the " +
105 " following properties: <ul>\n " +
106 " <li> <code>ActivityPackage</code> to the class name, dropping the " +
107 " last component (for example, " +
108 " <code>com.gmail.Bitdiddle.Ben.HelloPurr</code>)</li>\n " +
109 " <li> <code>ActivityClass</code> to the entire class name (for " +
111 " <code>com.gmail.Bitdiddle.Ben.HelloPurr.Screen1</code>)</li> " +
113 "<li> Starting the camera application by setting the following " +
114 " properties:<ul> \n" +
115 " <li> <code>Action: android.intent.action.MAIN</code> </li> \n" +
116 " <li> <code>ActivityPackage: com.android.camera</code> </li> \n" +
117 " <li> <code>ActivityClass: com.android.camera.Camera</code></li>\n " +
119 "<li> Performing web search. Assuming the term you want to search " +
120 " for is \"vampire\" (feel free to substitute your own choice), \n" +
121 " set the properties to:\n<ul><code>" +
122 " <li>Action: android.intent.action.WEB_SEARCH</li> " +
123 " <li>ExtraKey: query</li> " +
124 " <li>ExtraValue: vampire</li> " +
125 " <li>ActivityPackage: com.google.android.providers.enhancedgooglesearch</li>" +
126 " <li>ActivityClass: com.google.android.providers.enhancedgooglesearch.Launcher</li> " +
127 " </code></ul></li> \n" +
128 "<li> Opening a browser to a specified web page. Assuming the page you " +
129 " want to go to is \"www.facebook.com\" (feel free to substitute " +
130 " your own choice), set the properties to:\n<ul><code> " +
131 " <li>Action: android.intent.action.VIEW</li> " +
132 " <li>DataUri: http://www.facebook.com</li> </code> </ul> </li> " +
134 category = ComponentCategory.CONNECTIVITY,
136 iconName =
"images/activityStarter.png")
141 private String action;
142 private String dataUri;
143 private String dataType;
144 private String activityPackage;
145 private String activityClass;
146 private String extraKey;
147 private String extraValue;
148 private String resultName;
149 private Intent resultIntent;
150 private String result;
151 private int requestCode;
155 private static final String LOG_TAG =
"ActivityStarter";
163 super(container.
$form());
165 this.container = container;
167 Action(Intent.ACTION_MAIN);
194 this.action = action.trim();
217 description =
"Returns the extra key that will be passed to the activity.\n" +
218 "DEPRECATED: New code should use Extras property instead.",
232 this.extraKey = extraKey.trim();
241 description =
"Returns the extra value that will be passed to the activity.\n" +
242 "DEPRECATED: New code should use Extras property instead.",
256 this.extraValue = extraValue.trim();
292 this.resultName = resultName.trim();
320 this.dataUri = dataUri.trim();
339 this.dataType = dataType.trim();
348 return activityPackage;
358 this.activityPackage = activityPackage.trim();
367 return activityClass;
377 this.activityClass = activityClass.trim();
384 @
SimpleEvent(description =
"Event raised after this ActivityStarter returns.")
393 "Event raised if this ActivityStarter returns because the activity was canceled.")
404 if (resultIntent !=
null) {
405 String resultType = resultIntent.getType();
406 if (resultType !=
null) {
419 if (resultIntent !=
null) {
420 String resultUri = resultIntent.getDataString();
421 if (resultUri !=
null) {
433 for (Object pair : pairs.
toArray()) {
434 boolean isYailList = pair instanceof
YailList;
435 boolean isPair = isYailList ? ((
YailList) pair).
size() == 2 :
false;
436 if (!isYailList || !isPair) {
438 "ActivityStarter Error");
457 @
SimpleFunction(description =
"Returns the name of the activity that corresponds to this " +
458 "ActivityStarter, or an empty string if no corresponding activity can be found.")
460 Intent intent = buildActivityIntent();
461 PackageManager pm = container.
$context().getPackageManager();
462 ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
463 if (resolveInfo !=
null && resolveInfo.activityInfo !=
null) {
464 return resolveInfo.activityInfo.name;
472 @
SimpleFunction(description =
"Start the activity corresponding to this ActivityStarter.")
477 Intent intent = buildActivityIntent();
479 if (requestCode == 0) {
487 if (intent ==
null) {
492 container.
$context().startActivityForResult(intent, requestCode);
495 }
catch (ActivityNotFoundException e) {
502 private Intent buildActivityIntent() {
503 Uri uri = (dataUri.length() != 0) ? Uri.parse(dataUri) :
null;
504 Intent intent =
new Intent(action);
506 if (uri !=
null && dataUri.toLowerCase().startsWith(
"file://") ) {
507 Log.d(LOG_TAG,
"Using file://");
508 File file =
new File(uri.getPath());
510 Log.d(LOG_TAG,
"It's a file");
512 intent =
new Intent(action);
513 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
514 Log.d(LOG_TAG,
"added permissions");
518 if (TextUtils.isEmpty(
Action())) {
522 if (dataType.length() != 0) {
524 intent.setDataAndType(uri, dataType);
526 intent.setType(dataType);
532 if (activityPackage.length() != 0 || activityClass.length() != 0) {
533 ComponentName component =
new ComponentName(activityPackage, activityClass);
534 intent.setComponent(component);
535 }
else if (
Action().equals(
"android.intent.action.MAIN")) {
539 if (extraKey.length() != 0 && extraValue.length() != 0) {
540 Log.i(LOG_TAG,
"Adding extra, key = " + extraKey +
" value = " + extraValue);
541 intent.putExtra(extraKey, extraValue);
546 for (Object extra : extras.
toArray()) {
547 YailList castExtra = (YailList) extra;
548 String key = castExtra.getString(0);
549 Object value = castExtra.getObject(1);
550 Log.i(LOG_TAG,
"Adding extra, key = " + key +
" value = " + value);
551 if ((key.length() != 0)) {
552 if (value instanceof YailList) {
553 Log.i(LOG_TAG,
"Adding extra list, key = " + key +
" value = " + value);
554 intent.putExtra(key, ((YailList) value).toStringArray());
557 String stringValue = castExtra.getString(1);
558 Log.i(LOG_TAG,
"Adding extra string, key = " + key +
" value = " + stringValue);
559 intent.putExtra(key, stringValue);
568 if (requestCode == this.requestCode) {
569 Log.i(LOG_TAG,
"resultReturned - resultCode = " + resultCode);
570 if (resultCode == Activity.RESULT_OK) {
572 if (resultName.length() != 0 && resultIntent !=
null &&
573 resultIntent.hasExtra(resultName)) {
574 result = resultIntent.getStringExtra(resultName);
580 }
else if (resultCode == Activity.RESULT_CANCELED) {
586 @
SimpleEvent(description =
"The ActivityError event is no longer used. " +
587 "Please use the Screen.ErrorOccurred event instead.",