AppLauncher.java
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  * Copyright (c) 2011, Willow Garage, Inc.
00005  * Copyright (c) 2013, OSRF.
00006  * Copyright (c) 2013, Yujin Robot.
00007  *
00008  * All rights reserved.
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions
00011  * are met:
00012  *
00013  * * Redistributions of source code must retain the above copyright
00014  * notice, this list of conditions and the following disclaimer.
00015  * * Redistributions in binary form must reproduce the above
00016  * copyright notice, this list of conditions and the following
00017  * disclaimer in the documentation and/or other materials provided
00018  * with the distribution.
00019  * * Neither the name of Willow Garage, Inc. nor the names of its
00020  * contributors may be used to endorse or promote products derived
00021  * from this software without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  * POSSIBILITY OF SUCH DAMAGE.
00035  */
00036 
00037 package com.github.rosjava.android_remocons.common_tools.rocon;
00038 
00039 import android.app.Activity;
00040 import android.content.ActivityNotFoundException;
00041 import android.content.Intent;
00042 import android.content.pm.ApplicationInfo;
00043 import android.content.pm.PackageManager;
00044 import android.net.Uri;
00045 import android.util.Log;
00046 import android.util.Patterns;
00047 
00048 import com.github.robotics_in_concert.rocon_rosjava_core.rocon_interactions.InteractionMode;
00049 import com.github.rosjava.android_remocons.common_tools.master.RoconDescription;
00050 
00051 import org.yaml.snakeyaml.Yaml;
00052 
00053 import java.net.MalformedURLException;
00054 import java.net.URISyntaxException;
00055 import java.net.URL;
00056 import java.net.URLEncoder;
00057 import java.util.List;
00058 import java.util.Map;
00059 
00068 public class AppLauncher {
00069 
00070     public enum Result {
00071         SUCCESS,
00072         NOT_INSTALLED,
00073         NOTHING,
00074         CANNOT_CONNECT,
00075         MALFORMED_URI,
00076         CONNECT_TIMEOUT,
00077         OTHER_ERROR;
00078 
00079         public String message;
00080 
00081         Result withMsg(String message) {
00082             this.message = message;
00083             return this;
00084         }
00085     }
00086 
00087     public enum AppType {
00088         NATIVE,
00089         URL,
00090         WEB_URL,
00091         WEB_APP,
00092         NOTHING;
00093     }
00097     static public Result launch(final Activity parent, final RoconDescription concert,
00098                                 final rocon_interaction_msgs.Interaction app){
00099         Log.i("AppLaunch", "launching concert app " + app.getDisplayName() + " on service " + app.getNamespace());
00100         // On android apps, app name will be an intent action, while for web apps it will be its URL
00101         AppType app_type = checkAppType(app.getName());
00102         if(app_type == AppType.URL){
00103             return launchUrl(parent, concert, app);
00104         }
00105         else if(app_type == AppType.WEB_URL){
00106             return launchWebUrl(parent, concert, app);
00107         }
00108         else if(app_type == AppType.WEB_APP){
00109             return launchWebApp(parent, concert, app);
00110         }
00111         else if(app_type == AppType.NATIVE){
00112             return launchAndroidApp(parent, concert, app);
00113         }
00114         else if(app_type == AppType.NOTHING){
00115             return Result.NOTHING;
00116         }
00117         else{
00118             return Result.NOTHING;
00119         }
00120     }
00124     static public AppType checkAppType(String app_name){
00125         String web_url_desc = "web_url(";
00126         String web_app_desc = "web_app(";
00127         if (Patterns.WEB_URL.matcher(app_name).matches() == true) {
00128             return AppType.URL;
00129         }
00130         else if(app_name.length() == 0){
00131             return AppType.NOTHING;
00132         }
00133         else if(app_name.contains(web_app_desc)){
00134             return AppType.WEB_APP;
00135         }
00136         else if(app_name.contains(web_url_desc)){
00137             return AppType.WEB_URL;
00138         }
00139         else{
00140             return AppType.NATIVE;
00141         }
00142     }
00143 
00147     static private Result launchAndroidApp(final Activity parent, final RoconDescription concert,
00148                                            final rocon_interaction_msgs.Interaction app) {
00149         // Create the Intent from rapp's name, pass it parameters and remaps and start it
00150         Result result  = Result.OTHER_ERROR;
00151         String appName = app.getName();
00152         Intent intent = new Intent(appName);
00153         // Copy all app data to "extra" data in the intent.
00154         intent.putExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name", appName);
00155         intent.putExtra(RoconDescription.UNIQUE_KEY, concert);
00156         intent.putExtra("RemoconActivity", Constants.ACTIVITY_ROCON_REMOCON);
00157         intent.putExtra("Parameters", app.getParameters());  // YAML-formatted string
00158 
00159         // Remappings come as a messages list that make YAML parser crash, so we must digest if for him
00160         if ((app.getRemappings() != null) && (app.getRemappings().size() > 0)) {
00161             String remaps = "{";
00162             for (rocon_std_msgs.Remapping remap: app.getRemappings())
00163                 remaps += remap.getRemapFrom() + ": " + remap.getRemapTo() + ", ";
00164             remaps = remaps.substring(0, remaps.length() - 2) + "}";
00165             intent.putExtra("Remappings", remaps);
00166         }
00167         try {
00168             Log.i("AppLaunch", "launchAndroidApp trying to start activity (action: " + appName + " )");
00169             parent.startActivity(intent);
00170             result = Result.SUCCESS;
00171         } catch (ActivityNotFoundException e) {
00172             Log.i("AppLaunch", "launchAndroidApp activity not found for action, find package name: " + appName);
00173             result = launchAndroidAppWithPkgName(parent, concert, app);
00174         }
00175         return result;
00176     }
00177 
00178     static private Result launchAndroidAppWithPkgName(final Activity parent, final RoconDescription concert,
00179                                            final rocon_interaction_msgs.Interaction app) {
00180         // Create the Intent from rapp's name, pass it parameters and remaps and start it
00181         Result result  = Result.OTHER_ERROR;
00182         String appName = app.getName();
00183         PackageManager manager = parent.getPackageManager();
00184         Intent intent = manager.getLaunchIntentForPackage(appName);
00185         if(intent != null) {
00186             // Copy all app data to "extra" data in the intent.
00187             intent.putExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name", appName);
00188             intent.putExtra(RoconDescription.UNIQUE_KEY, concert);
00189             intent.putExtra("RemoconActivity", Constants.ACTIVITY_ROCON_REMOCON);
00190             intent.putExtra("Parameters", app.getParameters());  // YAML-formatted string
00191 
00192             // Remappings come as a messages list that make YAML parser crash, so we must digest if for him
00193             if ((app.getRemappings() != null) && (app.getRemappings().size() > 0)) {
00194                 String remaps = "{";
00195                 for (rocon_std_msgs.Remapping remap : app.getRemappings())
00196                     remaps += remap.getRemapFrom() + ": " + remap.getRemapTo() + ", ";
00197                 remaps = remaps.substring(0, remaps.length() - 2) + "}";
00198                 intent.putExtra("Remappings", remaps);
00199             }
00200             try {
00201                 Log.i("AppLaunch", "launchAndroidAppWithPkgName trying to start activity (action: " + appName + " )");
00202                 parent.startActivity(intent);
00203                 return Result.SUCCESS;
00204             } catch (ActivityNotFoundException e) {
00205                 Log.i("AppLaunch", "launchAndroidAppWithPkgName activity not found for action: " + appName);
00206                 result = launchAndroidAppWithAppId(parent, concert, app);
00207             }
00208         }
00209         else{
00210             result = launchAndroidAppWithAppId(parent, concert, app);
00211         }
00212         return result;
00213     }
00214 
00215     static private Result launchAndroidAppWithAppId(final Activity parent, final RoconDescription concert,
00216                                                       final rocon_interaction_msgs.Interaction app) {
00217         // Create the Intent from rapp's name, pass it parameters and remaps and start it
00218         Result result  = Result.OTHER_ERROR;
00219         String launchablePkgName = "";
00220         PackageManager manager = parent.getPackageManager();
00221         List<ApplicationInfo> applicationInfo = manager.getInstalledApplications(manager.GET_META_DATA);
00222         for (int i = 0; i < applicationInfo.size(); i++){
00223             ApplicationInfo appInfo = applicationInfo.get(i);
00224             if (app.getName().contains(appInfo.processName)){
00225                 launchablePkgName = appInfo.packageName;
00226                 break;
00227             }
00228         }
00229         if(launchablePkgName.length()!=0) {
00230             Intent intent = manager.getLaunchIntentForPackage(launchablePkgName);
00231             if(intent != null) {
00232                 // Copy all app data to "extra" data in the intent.
00233                 intent.putExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name", launchablePkgName);
00234                 intent.putExtra(RoconDescription.UNIQUE_KEY, concert);
00235                 intent.putExtra("RemoconActivity", Constants.ACTIVITY_ROCON_REMOCON);
00236                 intent.putExtra("Parameters", app.getParameters());  // YAML-formatted string
00237                 // Remappings come as a messages list that make YAML parser crash, so we must digest if for him
00238                 if ((app.getRemappings() != null) && (app.getRemappings().size() > 0)) {
00239                     String remaps = "{";
00240                     for (rocon_std_msgs.Remapping remap : app.getRemappings())
00241                         remaps += remap.getRemapFrom() + ": " + remap.getRemapTo() + ", ";
00242                     remaps = remaps.substring(0, remaps.length() - 2) + "}";
00243                     intent.putExtra("Remappings", remaps);
00244                 }
00245                 try {
00246                     Log.i("AppLaunch", "launchAndroidAppWithoutRosVer trying to start activity (action: " + launchablePkgName + " )");
00247                     parent.startActivity(intent);
00248                     result = Result.SUCCESS;
00249                 } catch (ActivityNotFoundException e) {
00250                     Log.i("AppLaunch", "launchAndroidAppWithoutRosVer activity not found for action, find package name: " + launchablePkgName);
00251                     result = Result.NOT_INSTALLED;
00252                 }
00253             }
00254         }
00255         {
00256             result = Result.NOT_INSTALLED;
00257         }
00258         return result;
00259     }
00260 
00264     static private Result launchUrl (final Activity parent, final RoconDescription concert,
00265                                        final rocon_interaction_msgs.Interaction app) {
00266         try
00267         {
00268             // Validate the URL before starting anything
00269             String app_name = "";
00270             app_name = app.getName();
00271             URL appURL = new URL(app_name);
00272             //2014.12.03 comment by dwlee
00273             //reason of blocking, Not necessary in web app launcher.
00274             /*
00275             AsyncTask<URL, Void, String> asyncTask = new AsyncTask<URL, Void, String>() {
00276                 @Override
00277                 protected String doInBackground(URL... urls) {
00278                     try {
00279                         HttpURLConnection urlConnection = (HttpURLConnection)urls[0].openConnection();
00280                         int unused_responseCode = urlConnection.getResponseCode();
00281                         urlConnection.disconnect();
00282                         return urlConnection.getResponseMessage();
00283                     }
00284                     catch (IOException e) {
00285                         return e.getMessage();
00286                     }
00287                 }
00288             }.execute(appURL);
00289             String result = asyncTask.get(5, TimeUnit.SECONDS);
00290             if (result == null || (result.startsWith("OK") == false && result.startsWith("ok") == false)) {
00291                 return Result.CANNOT_CONNECT.withMsg(result);
00292             }
00293             */
00294 
00295             // We pass concert URL, parameters and remaps as URL parameters
00296             String appUriStr = app_name;
00297             Uri appURI =  Uri.parse(appUriStr);
00298 
00299             // Create an action view intent and pass rapp's name + extra information as URI
00300             Intent intent = new Intent(Intent.ACTION_VIEW, appURI);
00301             intent.putExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name",app_name);
00302 
00303             Log.i("AppLaunch", "trying to start web app (URI: " + appUriStr + ")");
00304             parent.startActivity(intent);
00305             return Result.SUCCESS;
00306         }
00307         catch (MalformedURLException e)
00308         {
00309             return Result.MALFORMED_URI.withMsg("App URL is not valid. " + e.getMessage());
00310         }
00311         catch (ActivityNotFoundException e) {
00312             // This cannot happen for a web site, right? must mean that I have no web browser!
00313             return Result.NOT_INSTALLED.withMsg("Activity not found for view action??? muoia???");
00314         } catch (Exception e)
00315         {
00316             return Result.OTHER_ERROR.withMsg(e.getMessage());
00317         }
00318     }
00319 
00323     static private Result launchWebUrl(final Activity parent, final RoconDescription concert,
00324                                        final rocon_interaction_msgs.Interaction app) {
00325         try
00326         {
00327             // Validate the URL before starting anything
00328             String app_name = "";
00329             String app_type = "web_url";
00330             app_name = app.getName().substring(app_type.length()+1,app.getName().length()-1);
00331 
00332             URL appURL = new URL(app_name);
00333 
00334             //2014.12.03 comment by dwlee
00335             //reason of blocking, Not necessary in web app launcher.
00336             /*
00337             AsyncTask<URL, Void, String> asyncTask = new AsyncTask<URL, Void, String>() {
00338                 @Override
00339                 protected String doInBackground(URL... urls) {
00340                     try {
00341                         HttpURLConnection urlConnection = (HttpURLConnection)urls[0].openConnection();
00342                         int unused_responseCode = urlConnection.getResponseCode();
00343                         urlConnection.disconnect();
00344                         return urlConnection.getResponseMessage();
00345                     }
00346                     catch (IOException e) {
00347                         return e.getMessage();
00348                     }
00349                 }
00350             }.execute(appURL);
00351             String result = asyncTask.get(5, TimeUnit.SECONDS);
00352             if (result == null || (result.startsWith("OK") == false && result.startsWith("ok") == false)) {
00353                 return Result.CANNOT_CONNECT.withMsg(result);
00354             }
00355             */
00356 
00357             // We pass concert URL, parameters and remaps as URL parameters
00358             String appUriStr = app_name;
00359             Uri appURI =  Uri.parse(appUriStr);
00360 
00361             // Create an action view intent and pass rapp's name + extra information as URI
00362             Intent intent = new Intent(Intent.ACTION_VIEW, appURI);
00363             intent.putExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name",app_name);
00364 
00365             Log.i("AppLaunch", "trying to start web url (URI: " + appUriStr + ")");
00366             parent.startActivity(intent);
00367             return Result.SUCCESS;
00368         }
00369         catch (MalformedURLException e)
00370         {
00371             return Result.MALFORMED_URI.withMsg("App URL is not valid. " + e.getMessage());
00372         }
00373         catch (ActivityNotFoundException e) {
00374             // This cannot happen for a web site, right? must mean that I have no web browser!
00375             return Result.NOT_INSTALLED.withMsg("Activity not found for view action??? muoia???");
00376         }
00377         catch (Exception e)
00378         {
00379             return Result.OTHER_ERROR.withMsg(e.getMessage());
00380         }
00381     }
00385     static private Result launchWebApp(final Activity parent, final RoconDescription concert,
00386                                        final rocon_interaction_msgs.Interaction app) {
00387         try
00388         {
00389             // Validate the URL before starting anything
00390             String app_name = "";
00391             String app_type = "";
00392             app_type = "web_app";
00393             app_name = app.getName().substring(app_type.length()+1,app.getName().length()-1);
00394             URL appURL = new URL(app_name);
00395             //2014.05.27 comment by dwlee
00396             //reason of blocking, Not necessary in web app launcher.
00397             /*
00398             Log.i("AppLaunch", "Connection test (URI: " + app_name + ")");
00399             AsyncTask<URL, Void, String> asyncTask = new AsyncTask<URL, Void, String>() {
00400                 @Override
00401                 protected String doInBackground(URL... urls) {
00402                     try {
00403                         HttpURLConnection urlConnection = (HttpURLConnection)urls[0].openConnection();
00404                         int unused_responseCode = urlConnection.getResponseCode();
00405                         urlConnection.disconnect();
00406                         return urlConnection.getResponseMessage();
00407                     }
00408                     catch (IOException e) {
00409                         return e.getMessage();
00410                     }
00411                 }
00412             }.execute(appURL);
00413 
00414             String result = asyncTask.get(15, TimeUnit.SECONDS);
00415 
00416             if (result == null || (result.startsWith("OK") == false && result.startsWith("ok") == false)) {
00417                 Log.i("AppLaunch", "Connection test Fail (URI: " + app_name + ")");
00418                 return Result.CANNOT_CONNECT.withMsg(result);
00419             }
00420             Log.i("AppLaunch", "Connection test Success (URI: " + app_name + ")");
00421             */
00422 
00423             // We pass concert URL, parameters and remaps as URL parameters
00424             String appUriStr = app_name;
00425             String interaction_data = "{";
00426             //add remap
00427             String remaps = "\"remappings\": {";
00428             if ((app.getRemappings() != null) && (app.getRemappings().size() > 0)) {
00429                 for (rocon_std_msgs.Remapping remap: app.getRemappings())
00430                     remaps += "\"" + remap.getRemapFrom() + "\":\"" + remap.getRemapTo() + "\",";
00431                 remaps = remaps.substring(0, remaps.length() - 1) + "}";
00432             }
00433             else{
00434                 remaps+="}";
00435             }
00436             remaps += ",";
00437             interaction_data += remaps;
00438 
00439             //add displayname
00440             String displayname = "\"display_name\":";
00441             if ((app.getDisplayName() != null) && (app.getDisplayName().length() > 0)) {
00442                 displayname += "\"" + app.getDisplayName() +"\"";
00443             }
00444             displayname +=",";
00445             interaction_data += displayname;
00446 
00447             //add parameters
00448             String parameters = "\"parameters\": {";
00449             if ((app.getParameters() != null) && (app.getParameters().length() > 2)) {
00450                 Yaml yaml = new Yaml();
00451                 Map<String, String> params = (Map<String, String>) yaml.load(app.getParameters());
00452                 for( String key : params.keySet() ) {
00453                     parameters += "\"" + key + "\":\"" + String.valueOf(params.get(key))+"" + "\",";
00454                 }
00455                 parameters = parameters.substring(0, parameters.length() - 1);
00456             }
00457 
00458             parameters +="}";
00459             interaction_data += parameters;
00460             interaction_data +="}";
00461 
00462             appUriStr = appUriStr + "?" + "interaction_data=" + URLEncoder.encode(interaction_data);
00463             appURL.toURI(); // throws URISyntaxException if fails; probably a redundant check
00464             Uri appURI =  Uri.parse(appUriStr);
00465 
00466             // Create an action view intent and pass rapp's name + extra information as URI
00467             Intent intent = new Intent(Intent.ACTION_VIEW, appURI);
00468             intent.putExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name",app_name);
00469 
00470             Log.i("AppLaunch", "trying to start web app (URI: " + appUriStr + ")");
00471             parent.startActivity(intent);
00472             return Result.SUCCESS;
00473         }
00474         catch (URISyntaxException e) {
00475             return Result.MALFORMED_URI.withMsg("Cannot convert URL into URI. " + e.getMessage());
00476         }
00477         catch (MalformedURLException e)
00478         {
00479             return Result.MALFORMED_URI.withMsg("App URL is not valid. " + e.getMessage());
00480         }
00481         catch (ActivityNotFoundException e) {
00482             // This cannot happen for a web site, right? must mean that I have no web browser!
00483             return Result.NOT_INSTALLED.withMsg("Activity not found for view action??? muoia???");
00484         }
00485         catch (Exception e)
00486         {
00487             return Result.OTHER_ERROR.withMsg(e.getMessage());
00488         }
00489     }
00490 }


android_remocons
Author(s): Daniel Stonier, Kazuto Murase
autogenerated on Sat Jun 8 2019 19:32:24