Remocon.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.rocon_remocon;
00038 
00039 import android.app.AlertDialog;
00040 import android.content.DialogInterface;
00041 import android.content.Intent;
00042 import android.net.Uri;
00043 import android.net.wifi.WifiManager;
00044 import android.os.AsyncTask;
00045 import android.os.Bundle;
00046 import android.util.Log;
00047 import android.view.Menu;
00048 import android.view.MenuItem;
00049 import android.view.View;
00050 import android.view.Window;
00051 import android.view.WindowManager;
00052 import android.widget.AdapterView;
00053 import android.widget.AdapterView.OnItemClickListener;
00054 import android.widget.Button;
00055 import android.widget.GridView;
00056 import android.widget.TextView;
00057 import android.widget.Toast;
00058 
00059 import com.github.robotics_in_concert.rocon_rosjava_core.rocon_interactions.InteractionMode;
00060 import com.github.rosjava.android_remocons.common_tools.master.ConcertChecker;
00061 import com.github.rosjava.android_remocons.common_tools.master.MasterId;
00062 import com.github.rosjava.android_remocons.common_tools.master.RoconDescription;
00063 import com.github.rosjava.android_remocons.common_tools.rocon.AppLauncher;
00064 import com.github.rosjava.android_remocons.common_tools.rocon.Constants;
00065 import com.github.rosjava.android_remocons.common_tools.rocon.InteractionsManager;
00066 import com.github.rosjava.android_remocons.common_tools.system.WifiChecker;
00067 import com.github.rosjava.android_remocons.rocon_remocon.dialogs.AlertDialogWrapper;
00068 import com.github.rosjava.android_remocons.rocon_remocon.dialogs.LaunchInteractionDialog;
00069 import com.github.rosjava.android_remocons.rocon_remocon.dialogs.ProgressDialogWrapper;
00070 import com.google.common.base.Preconditions;
00071 
00072 import org.ros.android.RosActivity;
00073 import org.ros.exception.RemoteException;
00074 import org.ros.exception.RosRuntimeException;
00075 import org.ros.node.NodeConfiguration;
00076 import org.ros.node.NodeMainExecutor;
00077 import org.ros.node.service.ServiceResponseListener;
00078 
00079 import java.io.IOException;
00080 import java.net.URI;
00081 import java.net.URISyntaxException;
00082 import java.util.ArrayList;
00083 import java.util.List;
00084 
00085 import rocon_interaction_msgs.GetInteractionsResponse;
00086 import rocon_interaction_msgs.Interaction;
00087 
00096 public class Remocon extends RosActivity {
00097 
00098     /* startActivityForResult Request Codes */
00099         private static final int CONCERT_MASTER_CHOOSER_REQUEST_CODE = 1;
00100 
00101     private Interaction selectedInteraction;
00102     private String concertAppName = null;
00103     private String defaultConcertAppName = null;
00104     private RoconDescription roconDescription;
00105     private NodeConfiguration nodeConfiguration;
00106         private ArrayList<Interaction> availableAppsCache;
00107     private TextView concertNameView;
00108         private Button leaveConcertButton;
00109     private LaunchInteractionDialog launchInteractionDialog;
00110     private ProgressDialogWrapper progressDialog;
00111         private AlertDialogWrapper wifiDialog;
00112         private AlertDialogWrapper evictDialog;
00113         private AlertDialogWrapper errorDialog;
00114     private InteractionsManager interactionsManager;
00115     private StatusPublisher statusPublisher;
00116     private PairSubscriber pairSubscriber;
00117         private boolean alreadyClicked = false;
00118         private boolean validatedConcert;
00119         private long availableAppsCacheTime;
00120 
00121     /*
00122       By default we assume the remocon has just launched independently, however
00123       it can be launched upon the closure of one of its children applications.
00124      */
00125     private boolean fromApplication = false;  // true if it is a remocon activity getting control from a closing app
00126     private boolean fromNfcLauncher = false;  // true if it is a remocon activity started by NfcLauncherActivity
00127 
00128     public Remocon() {
00129         super("Remocon", "Remocon");
00130         availableAppsCacheTime = 0;
00131                 availableAppsCache = new ArrayList<Interaction>();
00132         statusPublisher = StatusPublisher.getInstance();
00133         pairSubscriber= PairSubscriber.getInstance();
00134         pairSubscriber.setAppHash(0);
00135         }
00136 
00137     @Override
00138     protected void init() {
00139         Log.d("Remocon", "init()");
00140         if (!fromApplication && !fromNfcLauncher) {
00141             super.init();
00142         } else {
00143             Log.i("Remocon", "init() - returned from closing interaction, or started by Nfc launcher");
00144             // In both cases we expect a concert description in the intent
00145             if (getIntent().hasExtra(RoconDescription.UNIQUE_KEY)) {
00146                 Log.w("Remocon", "init() - successfully retrieved concert description key and moving to init(Intent)");
00147                 init(getIntent());
00148                 Log.i("Remocon", "Successfully retrieved concert description from the intent");
00149             } else {
00150                 Log.e("Remocon", "Closing interaction didn't return the concert description");
00151                 // We are fucked-up in this case... TODO: recover or close all
00152             }
00153         }
00154     }
00155 
00156     @Override
00157     protected void onStart() {
00158         super.onResume();
00159         if ( getIntent().getExtras() != null ) {
00160             Log.i("Remocon", "onStart: " + Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name");
00161             concertAppName = getIntent().getStringExtra(Constants.ACTIVITY_SWITCHER_ID + "." + InteractionMode.CONCERT + "_app_name");
00162             if (concertAppName == null){
00163                 fromApplication = false;
00164                 fromApplication = false;
00165             }
00166             else{
00167                 if (concertAppName.equals("AppChooser")) { // TODO ugly legacy identifier, it's misleading so change it sometime
00168                     Log.i("Remocon", "got intent from a closing remocon application");
00169                     statusPublisher.update(false, 0, null);
00170                     fromApplication = true;
00171                 }
00172                 else if (concertAppName.equals("NfcLauncher")) {
00173                     Log.i("Remocon", "got intent from an Nfc launched application");
00174                     fromNfcLauncher = true;
00175                 }
00176             }
00177         }
00178         super.onStart();
00179     }
00180 
00182         @Override
00183         public void onCreate(Bundle savedInstanceState) {
00184         super.onCreate(savedInstanceState);
00185         Log.i("[Remocon]", "Oncreate");
00186         requestWindowFeature(Window.FEATURE_NO_TITLE);
00187         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
00188                              WindowManager.LayoutParams.FLAG_FULLSCREEN);
00189         setContentView(R.layout.rocon_remocon);
00190                 concertNameView = (TextView) findViewById(R.id.concert_name_view);
00191         // Prepare the app manager; we do here instead of on init to keep using the same instance when switching roles
00192         interactionsManager = new InteractionsManager(
00193                 new InteractionsManager.FailureHandler() {
00194                     public void handleFailure(String reason) {
00195                         Log.e("Remocon", "Failure on interactions manager: " + reason);
00196                     }
00197                 }
00198         );
00199         interactionsManager.setupGetInteractionsService(new ServiceResponseListener<GetInteractionsResponse>() {
00200             @Override
00201             public void onSuccess(rocon_interaction_msgs.GetInteractionsResponse response) {
00202                 List<Interaction> apps = response.getInteractions();
00203                 if (apps.size() > 0) {
00204                     availableAppsCache = (ArrayList<Interaction>) apps;
00205                     Log.i("Remocon", "Interaction Publication: " + availableAppsCache.size() + " apps");
00206                     runOnUiThread(new Runnable() {
00207                         @Override
00208                         public void run() {
00209                             updateAppList(availableAppsCache, roconDescription.getMasterName(), roconDescription.getCurrentRole());
00210                             progressDialog.dismiss();
00211                         }
00212                     });
00213                 } else {
00214                     // TODO: maybe I should notify the user... he will think something is wrong!
00215                     Log.w("Remocon", "No interactions available for the '" + roconDescription.getCurrentRole() + "' role.");
00216                 }
00217                 availableAppsCacheTime = System.currentTimeMillis();
00218             }
00219 
00220             @Override
00221             public void onFailure(RemoteException e) {
00222                 progressDialog.dismiss();
00223                 Log.e("Remocon", "retrieve interactions for the role '"
00224                         + roconDescription.getCurrentRole() + "' failed: " + e.getMessage());
00225             }
00226         });
00227         interactionsManager.setupRequestService(new ServiceResponseListener<rocon_interaction_msgs.RequestInteractionResponse>() {
00228             @Override
00229             public void onSuccess(rocon_interaction_msgs.RequestInteractionResponse response) {
00230                 Preconditions.checkNotNull(selectedInteraction);
00231 
00232                 final boolean allowed = response.getResult();
00233                 final String reason = response.getMessage();
00234 
00235                 boolean ret_launcher_dialog = false;
00236                 progressDialog.dismiss();
00237 
00238                 if(AppLauncher.checkAppType(selectedInteraction.getName()) == AppLauncher.AppType.NOTHING){
00239                     pairSubscriber.setAppHash(selectedInteraction.getHash());
00240                     ret_launcher_dialog = true;
00241                 }
00242                 else{
00243                     launchInteractionDialog.setup(selectedInteraction, allowed, reason);
00244                     if(allowed){
00245                         pairSubscriber.setAppHash(selectedInteraction.getHash());
00246                     }
00247                     else{
00248                         pairSubscriber.setAppHash(0);
00249                     }
00250                     ret_launcher_dialog = launchInteractionDialog.show();
00251                 }
00252 
00253                 if (ret_launcher_dialog) {
00254                     Log.i("Remocon", "Selected Launch button");
00255                     runOnUiThread(new Runnable() {
00256                         @Override
00257                         public void run() {
00258 
00259                             AppLauncher.Result result =
00260                                     AppLauncher.launch(Remocon.this, roconDescription, selectedInteraction);
00261                             if (result == AppLauncher.Result.SUCCESS) {
00262                                 // App successfully launched! Notify the concert and finish this activity
00263                                 //statusPublisher.update(true, selectedInteraction.getHash(), selectedInteraction.getName());
00264                                 // TODO try to no finish so statusPublisher remains while on app;  risky, but seems to work!    finish();
00265                             }
00266                             else if (result == AppLauncher.Result.NOTHING){
00267                                 //statusPublisher.update(false, selectedInteraction.getHash(), selectedInteraction.getName());
00268                             }
00269                             else if (result == AppLauncher.Result.NOT_INSTALLED) {
00270                                // App not installed; ask for going to play store to download the missing app
00271                                 statusPublisher.update(false, 0, null);
00272                                 Log.i("Remocon", "Showing not-installed dialog.");
00273                                 final String installPackage = selectedInteraction.getName().substring(0, selectedInteraction.getName().lastIndexOf("."));
00274                                 selectedInteraction = null;
00275 
00276                                 AlertDialog.Builder dialog = new AlertDialog.Builder(Remocon.this);
00277                                 dialog.setIcon(R.drawable.playstore_icon_small);
00278                                 dialog.setTitle("Android app not installed.");
00279                                 dialog.setMessage("This interaction requires an android application to be installed.\n"
00280                                         + "Would you like to install '" + installPackage + "' from the market place?");
00281                                 dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener()
00282                                 {
00283                                     @Override
00284                                     public void onClick(DialogInterface dlog, int i) {
00285                                         Uri uri = Uri.parse("market://details?id=" + installPackage);
00286                                         Intent intent = new Intent(Intent.ACTION_VIEW, uri);
00287                                         Remocon.this.startActivity(intent);
00288                                     }
00289                                 });
00290                                 dialog.setNegativeButton("No", new DialogInterface.OnClickListener()
00291                                 {
00292                                     @Override
00293                                     public void onClick(DialogInterface dlog, int i) {
00294                                         dlog.dismiss();
00295                                     }
00296                                 });
00297                                 dialog.show();
00298                             }
00299                             else {
00300                                 AlertDialog.Builder dialog = new AlertDialog.Builder(Remocon.this);
00301                                 dialog.setIcon(R.drawable.failure_small);
00302                                 dialog.setTitle("Cannot start app");
00303                                 dialog.setMessage(result.message);
00304                                 dialog.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
00305                                     @Override
00306                                     public void onClick(DialogInterface dlog, int i) {
00307                                         // nothing todo?
00308                                     }
00309                                 });
00310                                 dialog.show();
00311                             }
00312 
00313                         };
00314                     });
00315                 }
00316                 else {
00317                     Log.i("[Remocon]","User select cancel");
00318                     statusPublisher.update(false, 0, null);
00319                 }
00320             }
00321 
00322             @Override
00323             public void onFailure(RemoteException e) {
00324                 progressDialog.dismiss();
00325                 Log.e("Remocon", "Retrieve rapps for role "
00326                         + roconDescription.getCurrentRole() + " failed: " + e.getMessage());
00327             }
00328         });
00329 
00330         pairSubscriber.setAppHash(0);
00331         }
00332 
00345         @Override
00346         protected void init(final NodeMainExecutor nodeMainExecutor) {
00347         try {
00348             java.net.Socket socket = new java.net.Socket(getMasterUri().getHost(), getMasterUri().getPort());
00349             java.net.InetAddress local_network_address = socket.getLocalAddress();
00350             socket.close();
00351             NodeConfiguration nodeConfiguration =
00352                     NodeConfiguration.newPublic(local_network_address.getHostAddress(), getMasterUri());
00353             interactionsManager.init(roconDescription.getInteractionsNamespace());
00354             interactionsManager.getAppsForRole(roconDescription.getMasterId(), roconDescription.getCurrentRole());
00355             interactionsManager.setRemoconName(statusPublisher.REMOCON_FULL_NAME);
00356             progressDialog.show("Getting apps...",
00357                     "Retrieving interactions for the '" + roconDescription.getCurrentRole() + "' role");
00358             //execution of publisher
00359             if (! statusPublisher.isInitialized()) {
00360                 // If we come back from an app, it should be already initialized, so call execute again would crash
00361                 nodeMainExecutorService.execute(statusPublisher, nodeConfiguration.setNodeName(StatusPublisher.NODE_NAME));
00362             }
00363             //execution of subscriber
00364             pairSubscriber.setAppHash(0);
00365 
00366             if (! pairSubscriber.isInitialized()) {
00367                 // If we come back from an app, it should be already initialized, so call execute again would crash
00368                 nodeMainExecutorService.execute(pairSubscriber, nodeConfiguration.setNodeName(pairSubscriber.NODE_NAME));
00369             }
00370         } catch (IOException e) {
00371             // Socket problem
00372         }
00373     }
00374 
00388     void init(Intent intent) {
00389         URI uri;
00390         try {
00391             roconDescription = (RoconDescription) intent.getSerializableExtra(RoconDescription.UNIQUE_KEY);
00392             validatedConcert = false;
00393             validateConcert(roconDescription.getMasterId());
00394 
00395             uri = new URI(roconDescription.getMasterId().getMasterUri());
00396             Log.i("Remocon", "init(Intent) - master uri is " + uri.toString());
00397         } catch (ClassCastException e) {
00398             Log.e("Remocon", "Cannot get concert description from intent. " + e.getMessage());
00399             throw new RosRuntimeException(e);
00400         } catch (URISyntaxException e) {
00401             throw new RosRuntimeException(e);
00402         }
00403         nodeMainExecutorService.setMasterUri(uri);
00404         // Run init() in a new thread as a convenience since it often
00405         // requires network access. This would be more robust if it
00406         // had a failure handler for uncontactable errors (override
00407         // onPostExecute) that occurred when calling init. In reality
00408         // this shouldn't happen often - only when the connection
00409         // is unavailable inbetween validating and init'ing.
00410         if (roconDescription.getCurrentRole() == null) {
00411             chooseRole();
00412         }
00413         else {
00414             new AsyncTask<Void, Void, Void>() {
00415                 @Override
00416                 protected Void doInBackground(Void... params) {
00417                     while (!validatedConcert) {
00418                         // should use a sleep here to avoid burnout
00419                         try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
00420                     }
00421                     Log.i("Remocon", "init(Intent) passing control back to init(nodeMainExecutorService)");
00422                     Remocon.this.init(nodeMainExecutorService);
00423                     return null;
00424                 }
00425             }.execute();
00426         }
00427     }
00428 
00429     private void chooseRole() {
00430         Log.i("Remocon", "concert chosen; show choose user role dialog");
00431         roconDescription.setCurrentRole(-1);
00432 
00433         AlertDialog.Builder builder = new AlertDialog.Builder(Remocon.this);
00434         builder.setTitle("Choose your role");
00435         builder.setSingleChoiceItems(roconDescription.getUserRoles(), -1,
00436                 new DialogInterface.OnClickListener() {
00437                     @Override
00438                     public void onClick(DialogInterface dialog, int selectedRole) {
00439                         roconDescription.setCurrentRole(selectedRole);
00440                         String role = roconDescription.getCurrentRole();
00441                         Toast.makeText(Remocon.this, role + " selected", Toast.LENGTH_SHORT).show();
00442                         dialog.dismiss();
00443 
00444                         new AsyncTask<Void, Void, Void>() {
00445                             @Override
00446                             protected Void doInBackground(Void... params) {
00447                                 while (!validatedConcert) {
00448                                     // should use a sleep here to avoid burnout
00449                                     try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
00450                                 }
00451                                 Remocon.this.init(nodeMainExecutorService);
00452                                 return null;
00453                             }
00454                         }.execute();
00455                     }
00456                 });
00457         AlertDialog alert = builder.create();
00458         alert.show();
00459     }
00460 
00470         @Override
00471         public void onActivityResult(int requestCode, int resultCode, Intent data) {
00472         Log.i("Remocon", "onActivityResult [" + requestCode + "][" + resultCode + "]");
00473                 if (resultCode == RESULT_CANCELED) {
00474             Log.i("Remocon", "activityResult...RESULT_CANCELLED");
00475                         finish();
00476                 } else if (resultCode == RESULT_OK) {
00477             Log.i("Remocon", "activityResult...RESULT_OK");
00478                         if (requestCode == CONCERT_MASTER_CHOOSER_REQUEST_CODE) {
00479                 init(data);
00480             } else {
00481                                 // Without a master URI configured, we are in an unusable state.
00482                                 nodeMainExecutorService.shutdown();
00483                                 finish();
00484                         }
00485                 } else {
00486             Log.w("Remocon", "activityResult...??? [" + resultCode + "]");
00487         }
00488         }
00489 
00497         @Override
00498         public void startMasterChooser() {
00499                 if (!fromApplication && !fromNfcLauncher) {
00500                         super.startActivityForResult(new Intent(this,
00501                                         MasterChooser.class),
00502                                         CONCERT_MASTER_CHOOSER_REQUEST_CODE);
00503         }
00504         }
00505 
00506         public void validateConcert(final MasterId id) {
00507         // TODO:  why built here?  and why recreate a builder, if wrapper already has?
00508         launchInteractionDialog = new LaunchInteractionDialog(this);
00509         wifiDialog = new AlertDialogWrapper(this, new AlertDialog.Builder(this)
00510                                 .setTitle("Change Wifi?").setCancelable(false), "Yes", "No");
00511                 evictDialog = new AlertDialogWrapper(this,
00512                                 new AlertDialog.Builder(this).setTitle("Evict User?")
00513                                                 .setCancelable(false), "Yes", "No");
00514                 errorDialog = new AlertDialogWrapper(this,
00515                                 new AlertDialog.Builder(this).setTitle("Could Not Connect")
00516                                                 .setCancelable(false), "Ok");
00517                 progressDialog = new ProgressDialogWrapper(this);
00518                 final AlertDialogWrapper wifiDialog = new AlertDialogWrapper(this,
00519                                 new AlertDialog.Builder(this).setTitle("Change Wifi?")
00520                                                 .setCancelable(false), "Yes", "No");
00521 
00522                 // Run a set of checkers in series. The last step must ensure the master is up.
00523                 final ConcertChecker cc = new ConcertChecker(
00524                                 new ConcertChecker.ConcertDescriptionReceiver() {
00525                                         public void receive(RoconDescription concertDescription) {
00526                         progressDialog.dismiss();
00527                         if(!fromApplication) {
00528                             // Check that it's not busy
00529                             if ( concertDescription.getConnectionStatus() == RoconDescription.UNAVAILABLE ) {
00530                                 errorDialog.show("Concert is unavailable : busy serving another remote controller.");
00531                                 errorDialog.dismiss();
00532                                 startMasterChooser();
00533                             } else {
00534                                 validatedConcert = true;   // for us this is enough check!
00535                             }
00536                         } else { // fromApplication
00537                             // Working on the lovely assumption that we're already controlling the rapp manager
00538                             // since we come from a running app. Note that this code is run after platform info
00539                             // checks have been made (see MasterChecker).
00540                             validatedConcert = true;
00541                         }
00542                                         }
00543                                 }, new ConcertChecker.FailureHandler() {
00544                                         public void handleFailure(String reason) {
00545                                                 final String reason2 = reason;
00546                         // Kill the connecting to ros master dialog.
00547                         progressDialog.dismiss();
00548                         errorDialog.show("Cannot contact ROS master: " + reason2);
00549                                                 errorDialog.dismiss();
00550                         // TODO : gracefully abort back to the concert master chooser instead.
00551                         finish();
00552                                         }
00553                                 });
00554 
00555                 // Ensure that the correct WiFi network is selected.
00556                 final WifiChecker wc = new WifiChecker(
00557                                 new WifiChecker.SuccessHandler() {
00558                                         public void handleSuccess() {
00559                         progressDialog.show("Checking...", "Starting connection process");
00560                                                 cc.beginChecking(id);
00561                                         }
00562                                 }, new WifiChecker.FailureHandler() {
00563                                         public void handleFailure(String reason) {
00564                                                 final String reason2 = reason;
00565                         progressDialog.dismiss();
00566                                                 errorDialog.show("Cannot connect to concert WiFi: " + reason2);
00567                                                 errorDialog.dismiss();
00568                                                 finish();
00569                                         }
00570                                 }, new WifiChecker.ReconnectionHandler() {
00571                                         public boolean doReconnection(String from, String to) {
00572                         progressDialog.dismiss();
00573                                                 if (from == null) {
00574                                                         wifiDialog.setMessage("To interact with this master, you must connect to " + to
00575                                     + "\nDo you want to connect to " + to + "?");
00576                                                 } else {
00577                                                         wifiDialog.setMessage("To interact with this master, you must switch wifi networks"
00578                                                                         + "\nDo you want to switch from " + from + " to " + to + "?");
00579                                                 }
00580 
00581                         progressDialog.show("Checking...", "Switching wifi networks");
00582                                                 return wifiDialog.show();
00583                                         }
00584                                 });
00585                 progressDialog.show("Connecting...", "Checking wifi connection");
00586                 wc.beginChecking(id, (WifiManager) getSystemService(WIFI_SERVICE));
00587         }
00588 
00589         protected void updateAppList(final ArrayList<Interaction> apps, final String master_name, final String role) {
00590                 Log.d("Remocon", "updating app list gridview");
00591         selectedInteraction = null;
00592         concertNameView.setText(master_name + " - " + role);
00593                 GridView gridview = (GridView) findViewById(R.id.gridview);
00594                 AppAdapter appAdapter = new AppAdapter(Remocon.this, apps);
00595                 gridview.setAdapter(appAdapter);
00596                 registerForContextMenu(gridview);
00597                 gridview.setOnItemClickListener(new OnItemClickListener() {
00598                         @Override
00599                         public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
00600                 selectedInteraction = apps.get(position);
00601                 progressDialog.show("Requesting app...", "Requesting permission to use "
00602                                    + selectedInteraction.getDisplayName());
00603                 interactionsManager.requestAppUse(roconDescription.getMasterId(), role, selectedInteraction);
00604                 statusPublisher.update(true, selectedInteraction.getHash(), selectedInteraction.getName());
00605 
00606                         }
00607                 });
00608                 Log.d("Remocon", "app list gridview updated");
00609         }
00610 
00614     public void changeRoleClicked(View view) {
00615         chooseRole();
00616     }
00617 
00623     public void leaveConcertClicked(View view) {
00624         availableAppsCache.clear();
00625         startActivityForResult(new Intent(this, MasterChooser.class),
00626                 CONCERT_MASTER_CHOOSER_REQUEST_CODE);
00627 
00628         nodeMainExecutorService.shutdownNodeMain(statusPublisher);
00629         nodeMainExecutorService.shutdownNodeMain(pairSubscriber);
00630 
00631         interactionsManager.shutdown();
00632     }
00633 
00634         @Override
00635         public boolean onCreateOptionsMenu(Menu menu) {
00636                 menu.add(0, 0, 0, R.string.exit);
00637                 return super.onCreateOptionsMenu(menu);
00638         }
00639 
00640         @Override
00641         public boolean onOptionsItemSelected(MenuItem item) {
00642                 super.onOptionsItemSelected(item);
00643                 switch (item.getItemId()) {
00644                 case 0:
00645                         finish();
00646                         break;
00647                 }
00648                 return true;
00649         }
00650 
00651     @Override
00652     public void onBackPressed() {
00653         Log.i("Remocon", "Press Back Button");
00654         leaveConcertClicked(null);
00655     }
00656 
00657 }


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