/** * Copyright 2011 Guenther Hoelzl * * This file is part of MINDdroid. * * MINDdroid is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MINDdroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MINDdroid. If not, see . **/ package com.lego.minddroid; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.bluetooth.BluetoothAdapter; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; /** * This class is for uploading programs to the NXT brick via Bluetooth. * Special programs will be able to communicate with MINDdroid, so no PC * is required for playing with a robot. */ public class NXJUploader extends Activity implements UploadThreadListener, DialogListener, BTConnectable { private static final int DIALOG_NXT = 0; private static final int DIALOG_FILE = 1; // preinstalled modules on res/raw/directoy private static String[] preinstalledNXJstring = new String[] { "AlphaRex.nxj", "MINDGameZ.nxj" }; private static final int REQUEST_CONNECT_DEVICE = 1000; private static final int REQUEST_ENABLE_BT = 2000; private BTCommunicator mNXT; private UploadThread uploadThread; private Handler handler; private ProgressDialog progressDialog; private int uploadStatus; private int runningDialog; private boolean pairing; private boolean btErrorPending = false; private static boolean btOnByUs = false; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.nxjuploader); initLayout(); // Create objects for communication mNXT = new BTCommunicator(this, null, BluetoothAdapter.getDefaultAdapter(), getResources()); handler = new Handler(); // Create and launch the upload thread uploadThread = new UploadThread(this, getResources()); uploadThread.setBluetoothCommunicator(mNXT); uploadThread.start(); } @Override protected void onStart() { super.onStart(); if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } } /** * Called when the activity is destroyed. */ @Override protected void onDestroy() { super.onDestroy(); // request the uploadthread to stop uploadThread.requestStop(); } /** * Asks if bluetooth was switched on during the runtime of the app. For saving * battery we switch it off when the app is terminated. * @return true, when bluetooth was switched on by the app */ public static boolean isBtOnByUs() { return btOnByUs; } /** * Sets a flag when bluetooth was switched on durin runtime * @param btOnByUs true, when bluetooth was switched on by the app */ public static void setBtOnByUs(boolean btOnByUs) { NXJUploader.btOnByUs = btOnByUs; } /** * @return true, when currently pairing */ @Override public boolean isPairing() { return pairing; } /** * Displays a message as a toast */ public void showToast(String message) { Toast toast = Toast.makeText(this, message, Toast.LENGTH_SHORT); toast.show(); return; } /** * Displays a message from resID as a toast */ public void showToast(int resID) { Toast toast = Toast.makeText(this, resID, Toast.LENGTH_SHORT); toast.show(); return; } /** * Displays resp. updates a progress dialog */ public void showProgressDialog(String message, int maxProgress, int currentProgress) { boolean initialized = false; if (progressDialog == null) { initialized = true; progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setCancelable(false); progressDialog.setMessage(message); } progressDialog.setMax(maxProgress); progressDialog.setProgress(currentProgress); if (initialized) progressDialog.show(); } /** * Displays resp. updates a progress dialog */ public void showProgressDialog(String message) { if (progressDialog == null) { progressDialog = new ProgressDialog(this); progressDialog.setCancelable(false); progressDialog.setMessage(message); progressDialog.show(); } } /** * Dismisses an existing progress dialog */ public void dismissProgressDialog() { if (progressDialog != null) { progressDialog.dismiss(); progressDialog = null; } } /** * Initializes the values on the main screen */ private void initLayout() { initNXTButton(); initFileButton(); initUploadButton(); } /** * Initializes the "SELECT NXT" button */ private void initNXTButton() { Button fileButton = (Button) findViewById(R.id.nxt_button); fileButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { selectNXT(); } }); } /** * Initializes the "SELECT FILE" button */ private void initFileButton() { Button fileButton = (Button) findViewById(R.id.file_button); fileButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { showFileDialog(); } }); } /** * Starts the NXT selection activity */ private void selectNXT() { Intent serverIntent = new Intent(this, DeviceListActivity.class); startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE); } /** * Shows the file dialog */ private void showFileDialog() { NXJFileDialog fileDialog = new NXJFileDialog(this, this); if (fileDialog.refreshFileList(preinstalledNXJstring) == 0) showToast(R.string.nxj_no_files); else { runningDialog = DIALOG_FILE; fileDialog.show(); } } /* * This is the method for returning values of dialogs * @param the selected text */ @Override public void dialogUpdate(String text) { TextView textView; switch (runningDialog) { case DIALOG_NXT: textView = (TextView) findViewById(R.id.nxt_name); textView.setText(text); break; case DIALOG_FILE: textView = (TextView) findViewById(R.id.nxj_file_name); textView.setText(text); break; } } /** * Initializes the "UPLOAD" button */ private void initUploadButton() { Button uploadButton = (Button) findViewById(R.id.upload_button); uploadButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { TextView nxtTextView = (TextView) findViewById(R.id.nxt_name); String macAddress = nxtTextView.getText().toString(); if (macAddress.compareTo("") == 0) { showToast(R.string.nxj_please_select_nxt); return; } macAddress = macAddress.substring(macAddress.lastIndexOf('-')+1); TextView nxjTextView = (TextView) findViewById(R.id.nxj_file_name); String fileName = nxjTextView.getText().toString(); if (fileName.compareTo("") == 0) { showToast(R.string.nxj_please_select_file); return; } uploadThread.enqueueUpload(macAddress, fileName); } }); } /** * This will be called by the UploadThread to signal an update of the * current status. * @param status The current state of the UploadThread */ @Override public void handleUploadThreadUpdate(final int status) { handler.post(new Runnable() { @Override public void run() { if (status != uploadStatus) { dismissProgressDialog(); uploadStatus = status; } showUploadStatus(); } }); } /** * Shows the current status of the uploader either in * a progress bar or in toast in case of an error. */ private void showUploadStatus() { switch (uploadStatus) { case UploadThread.CONNECTING: showProgressDialog(getResources().getString(R.string.nxj_connecting)); break; case UploadThread.UPLOADING: showProgressDialog(getResources().getString(R.string.nxj_uploading), uploadThread.getFileLength(), uploadThread.getBytesUploaded()); break; default: dismissProgressDialog(); } switch (uploadThread.getErrorCode()) { case UploadThread.NO_ERROR: break; case UploadThread.OPEN_BT_ERROR: if (pairing) showToast(R.string.nxj_bluetooth_pairing); else showBTErrorDialog(); break; case UploadThread.CLOSE_BT_ERROR: showBTErrorDialog(); break; case UploadThread.OPEN_FILE_ERROR: showToast(R.string.nxj_file_open_error); break; case UploadThread.UPLOAD_ERROR: showBTErrorDialog(); break; default: showToast(R.string.nxj_other_error); } uploadThread.resetErrorCode(); } /** * Shows an error dialog when there's an error regarding * bluettooth transfer. */ private void showBTErrorDialog() { if (btErrorPending == false) { btErrorPending = true; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getResources().getString(R.string.bt_error_dialog_title)) .setMessage(getResources().getString(R.string.bt_error_dialog_message)).setCancelable(false) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { btErrorPending = false; dialog.cancel(); } }); builder.create().show(); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CONNECT_DEVICE: // When DeviceListActivity returns with a device to connect if (resultCode == Activity.RESULT_OK) { // Get the device infos String infos = data.getExtras().getString(DeviceListActivity.DEVICE_NAME_AND_ADDRESS); pairing = data.getExtras().getBoolean(DeviceListActivity.PAIRING); TextView textView = (TextView) findViewById(R.id.nxt_name); textView.setText(infos); } break; case REQUEST_ENABLE_BT: // When the request to enable Bluetooth returns switch (resultCode) { case Activity.RESULT_OK: btOnByUs = true; break; case Activity.RESULT_CANCELED: showToast(R.string.bt_needs_to_be_enabled); finish(); break; } break; } } }