Java tutorial
/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.teeptrak.controller; import java.io.File; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.util.Date; import com.teeptrak.controller.dfu.DfuService; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.LoaderManager.LoaderCallbacks; import android.app.NotificationManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.CursorLoader; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.Loader; import android.content.ServiceConnection; import android.content.res.Configuration; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.provider.MediaStore; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import no.nordicsemi.android.dfu.DfuProgressListener; import no.nordicsemi.android.dfu.DfuProgressListenerAdapter; import no.nordicsemi.android.dfu.DfuServiceInitiator; import no.nordicsemi.android.dfu.DfuServiceListenerHelper; public class MainActivity extends Activity implements LoaderCallbacks<Cursor> { public static final String TAG = "TeepTrakController"; private static final int REQUEST_SELECT_DEVICE = 1; private static final int REQUEST_ENABLE_BT = 2; private static final int REQUEST_SELECT_FILE = 3; private static final int TTC_BUSY = 10; private static final int TTC_READY = 11; private static final int UART_PROFILE_CONNECTED = 20; private static final int UART_PROFILE_DISCONNECTED = 21; private static final int FILE_TYPE_NONE = -1; private static final int FILE_TYPE_ZIP = 1; private static final int FILE_TYPE_CFG = 2; private static final int FILE_TYPE_TST = 3; private static final int STATE_OFF = 10; private static final String MIME_TYPE_TEXT = "text/plain"; private static final String EXTRA_URI = "uri"; private TextView mBtDeviceAddress; private int mState = UART_PROFILE_DISCONNECTED; private UartService mUartService = null; private BluetoothDevice mBtDevice = null; private BluetoothAdapter mBtAdapter = null; private ListView mMsgList; private ArrayAdapter<String> mMsgListAdapter; private Button mConnectBtn; private Button mSendBtn; private Button mDatBtn; private Button mUpgradeBtn; private Button mSetFwFileBtn; private Button mSetCfgFileBtn; private Button mSetTstFileBtn; private Button mConfigDeviceBtn; private Button mTestDeviceBtn; private EditText mSendMsg; private TextView mStateLabel; private TextView mBtDeviceName; private ProgressBar mProgressBar; private CheckBox mLedBox; private int mFileType = FILE_TYPE_NONE; private String mFwFilePath = null; private String mCfgFilePath = null; private String mTstFilePath = null; private aScriptTask mScriptTask = null; private CompatTable mCompatTable = null; private final DfuProgressListener mProgressBarListener = new DfuProgressListenerAdapter() { @Override public void onDeviceConnecting(final String deviceAddress) { mProgressBar.setIndeterminate(true); mStateLabel.setText(R.string.dfu_status_connecting); printMessage(getString(R.string.dfu_status_connecting), true); } @Override public void onDfuProcessStarting(final String deviceAddress) { mProgressBar.setIndeterminate(true); mStateLabel.setText(R.string.dfu_status_starting); printMessage(getString(R.string.dfu_status_starting), true); } @Override public void onEnablingDfuMode(final String deviceAddress) { mProgressBar.setIndeterminate(true); mStateLabel.setText(R.string.dfu_status_switching_to_dfu); printMessage(getString(R.string.dfu_status_switching_to_dfu), true); } @Override public void onFirmwareValidating(final String deviceAddress) { mProgressBar.setIndeterminate(true); mStateLabel.setText(R.string.dfu_status_validating); printMessage(getString(R.string.dfu_status_validating), true); } @Override public void onDeviceDisconnecting(final String deviceAddress) { mProgressBar.setIndeterminate(true); mStateLabel.setText(R.string.dfu_status_disconnecting); printMessage(getString(R.string.dfu_status_disconnecting), true); } @Override public void onDfuCompleted(final String deviceAddress) { mProgressBar.setIndeterminate(false); mProgressBar.setProgress(0); mStateLabel.setText(R.string.dfu_status_completed); // Let's wait a bit until we cancel the notification. // When canceled immediately it will be recreated by service again. new Handler().postDelayed(new Runnable() { @Override public void run() { printMessage(getString(R.string.dfu_status_completed), true); // If this activity is still open and upload process was completed, cancel the notification final NotificationManager manager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); manager.cancel(DfuService.NOTIFICATION_ID); } }, 200); } @Override public void onDfuAborted(final String deviceAddress) { mStateLabel.setText(R.string.dfu_status_aborted); // Let's wait a bit until we cancel the notification. // When canceled immediately it will be recreated by service again. new Handler().postDelayed(new Runnable() { @Override public void run() { printMessage(getString(R.string.dfu_status_aborted), true); // if this activity is still open and upload process was completed, cancel the notification final NotificationManager manager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); manager.cancel(DfuService.NOTIFICATION_ID); } }, 200); } @Override public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) { mProgressBar.setIndeterminate(false); mProgressBar.setProgress(percent); mStateLabel.setText(getString(R.string.dfu_uploading_percentage, percent)); } @Override public void onError(final String deviceAddress, final int error, final int errorType, final String message) { mStateLabel.setText(getString(R.string.dfu_uploading_error, 0)); // We have to wait a bit before canceling notification. This is called before DfuService creates the last notification. new Handler().postDelayed(new Runnable() { @Override public void run() { printMessage(getString(R.string.dfu_uploading_error, 0), true); // if this activity is still open and upload process was completed, cancel the notification final NotificationManager manager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); manager.cancel(DfuService.NOTIFICATION_ID); } }, 200); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mBtAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBtAdapter == null) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); finish(); return; } mConnectBtn = (Button) findViewById(R.id.idConnectBtn); mBtDeviceName = (TextView) findViewById(R.id.idDeviceName); mBtDeviceAddress = (TextView) findViewById(R.id.idDeviceAddress); mStateLabel = (TextView) findViewById(R.id.idStateLabel); mProgressBar = (ProgressBar) findViewById(R.id.idProgressBar); mMsgList = (ListView) findViewById(R.id.idMessageList); mSendMsg = (EditText) findViewById(R.id.idSendText); mLedBox = (CheckBox) findViewById(R.id.idLedBox); mDatBtn = (Button) findViewById(R.id.idDatBtn); mSendBtn = (Button) findViewById(R.id.idSendBtn); mSetFwFileBtn = (Button) findViewById(R.id.idSetFwFileBtn); mUpgradeBtn = (Button) findViewById(R.id.idUpgradeFwBtn); mSetCfgFileBtn = (Button) findViewById(R.id.idSetCfgFileBtn); mConfigDeviceBtn = (Button) findViewById(R.id.idCinfigDeviceBtn); mSetTstFileBtn = (Button) findViewById(R.id.idSetTstFileBtn); mTestDeviceBtn = (Button) findViewById(R.id.idTestDeviceBtn); mMsgListAdapter = new ArrayAdapter<String>(this, R.layout.message_detail); mMsgList.setAdapter(mMsgListAdapter); mMsgList.setDivider(null); try { mCompatTable = new CompatTable(getResources()); if (!mCompatTable.isValid()) throw new Exception("Config Compatibility Table isn't valid!"); } catch (Exception e) { printMessage("ERROR: " + e.getMessage(), true); } initUartService(); } private void printMessage(String aMsg, boolean aInsertDate) { String dateTime = DateFormat.getTimeInstance().format(new Date()); if (aInsertDate) { mMsgListAdapter.add("[" + dateTime + "] " + aMsg); } else { mMsgListAdapter.add(" " + aMsg); } mMsgList.smoothScrollToPosition(mMsgListAdapter.getCount() - 1); } //UART service connected/disconnected private ServiceConnection mUartServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder rawBinder) { mUartService = ((UartService.LocalBinder) rawBinder).getService(); Log.d(TAG, "onServiceConnected mUartService= " + mUartService); if (!mUartService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); finish(); } } public void onServiceDisconnected(ComponentName classname) { mUartService = null; } }; private Handler mHandler = new Handler() { @Override //Handler events that received from UART service public void handleMessage(Message msg) { } }; private void setUIState(int aState) { switch (aState) { case UART_PROFILE_CONNECTED: mConnectBtn.setText("Disconnect"); mConnectBtn.setEnabled(true); mStateLabel.setText("Connected"); mSendMsg.setEnabled(true); mSendBtn.setEnabled(true); mDatBtn.setEnabled(true); mSetFwFileBtn.setEnabled(true); mUpgradeBtn.setEnabled(true); mSetCfgFileBtn.setEnabled(true); mConfigDeviceBtn.setEnabled(true); mSetTstFileBtn.setEnabled(true); mTestDeviceBtn.setEnabled(true); mLedBox.setEnabled(true); break; case UART_PROFILE_DISCONNECTED: mConnectBtn.setText("Connect"); mConnectBtn.setEnabled(true); mStateLabel.setText("Disconnected"); mSendMsg.setEnabled(false); mSendBtn.setEnabled(false); mDatBtn.setEnabled(false); mSetFwFileBtn.setEnabled(true); mUpgradeBtn.setEnabled(false); mSetCfgFileBtn.setEnabled(true); mConfigDeviceBtn.setEnabled(false); mSetTstFileBtn.setEnabled(true); mTestDeviceBtn.setEnabled(false); mLedBox.setEnabled(false); break; case TTC_BUSY: mConnectBtn.setText("Disconnect"); mConnectBtn.setEnabled(false); mStateLabel.setText("Connected -> Busy"); mSendMsg.setEnabled(false); mSendBtn.setEnabled(false); mDatBtn.setEnabled(false); mSetFwFileBtn.setEnabled(false); mUpgradeBtn.setEnabled(false); mSetCfgFileBtn.setEnabled(false); mConfigDeviceBtn.setEnabled(false); mSetTstFileBtn.setEnabled(false); mTestDeviceBtn.setEnabled(false); mLedBox.setEnabled(false); break; case TTC_READY: mConnectBtn.setText("Disconnect"); mConnectBtn.setEnabled(true); mStateLabel.setText("Connected -> Ready"); mSendMsg.setEnabled(true); mSendBtn.setEnabled(true); mDatBtn.setEnabled(true); mSetFwFileBtn.setEnabled(true); mUpgradeBtn.setEnabled(true); mSetCfgFileBtn.setEnabled(true); mConfigDeviceBtn.setEnabled(true); mSetTstFileBtn.setEnabled(true); mTestDeviceBtn.setEnabled(true); mLedBox.setEnabled(true); break; } } private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); final Intent mIntent = intent; //*********************// if (action.equals(UartService.ACTION_GATT_CONNECTED)) { runOnUiThread(new Runnable() { public void run() { Log.d(TAG, "UART_CONNECT_MSG"); mBtDeviceName.setText(mBtDevice.getName() + " - Ready"); mBtDeviceAddress.setText(mBtDevice.getAddress()); printMessage("Connected to: " + mBtDevice.getName(), true); mState = UART_PROFILE_CONNECTED; setUIState(mState); } }); } //*********************// if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) { runOnUiThread(new Runnable() { public void run() { Log.d(TAG, "UART_DISCONNECT_MSG"); mBtDeviceName.setText("Not Connected"); mBtDeviceAddress.setText("-"); printMessage("Disconnected to: " + mBtDevice.getName(), true); mUartService.close(); mState = UART_PROFILE_DISCONNECTED; setUIState(mState); } }); } //*********************// if (action.equals(UartService.ACTION_GATT_SERVICES_DISCOVERED)) { mUartService.enableTXNotification(); } //*********************// if (action.equals(UartService.ACTION_DATA_AVAILABLE)) { final byte[] mRxValue = intent.getByteArrayExtra(UartService.EXTRA_DATA); if (mScriptTask != null) { mScriptTask.putRxData(mRxValue); synchronized (mScriptTask) { mScriptTask.notify(); } } else { runOnUiThread(new Runnable() { public void run() { try { String mText = new String(mRxValue, "UTF-8"); printMessage("RX: " + mText, true); } catch (Exception e) { Log.e(TAG, e.toString()); } } }); } } //*********************// if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_UART)) { showMessage("Device doesn't support UART. Disconnecting"); mUartService.disconnect(); } } }; private void initUartService() { Intent bindIntent = new Intent(this, UartService.class); bindService(bindIntent, mUartServiceConnection, Context.BIND_AUTO_CREATE); LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter()); } private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(UartService.ACTION_GATT_CONNECTED); intentFilter.addAction(UartService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(UartService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(UartService.ACTION_DATA_AVAILABLE); intentFilter.addAction(UartService.DEVICE_DOES_NOT_SUPPORT_UART); return intentFilter; } @Override public void onStart() { super.onStart(); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy()"); try { LocalBroadcastManager.getInstance(this).unregisterReceiver(UARTStatusChangeReceiver); } catch (Exception ignore) { Log.e(TAG, ignore.toString()); } unbindService(mUartServiceConnection); mUartService.stopSelf(); mUartService = null; } @Override protected void onStop() { Log.d(TAG, "onStop"); super.onStop(); } @Override protected void onPause() { Log.d(TAG, "onPause"); super.onPause(); DfuServiceListenerHelper.unregisterProgressListener(this, mProgressBarListener); } @Override protected void onRestart() { super.onRestart(); Log.d(TAG, "onRestart"); } @Override public void onResume() { super.onResume(); Log.d(TAG, "onResume"); DfuServiceListenerHelper.registerProgressListener(this, mProgressBarListener); if (!mBtAdapter.isEnabled()) { Log.i(TAG, "onResume - BT not enabled yet"); Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_SELECT_DEVICE: { //When the DeviceListActivity return, with the selected device address if (resultCode == Activity.RESULT_OK && data != null) { String deviceAddress = data.getStringExtra(BluetoothDevice.EXTRA_DEVICE); mBtDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress); Log.d(TAG, "... onActivityResultdevice.address==" + mBtDevice + "mserviceValue" + mUartService); mBtDeviceName.setText(mBtDevice.getName() + " - Connecting"); if (mBtDevice.getName().equals("DfuTarg")) { if (mFwFilePath != null) { final DfuServiceInitiator DFU = new DfuServiceInitiator(mBtDevice.getAddress()) .setDeviceName(mBtDevice.getName()).setKeepBond(false).setZip(null, mFwFilePath); DFU.start(this, DfuService.class); } else { printMessage("Selected Device is in DFU mode.", false); printMessage("You must Set FirmWare file first!", false); Toast.makeText(this, "You must Set FirmWare file first!", Toast.LENGTH_SHORT).show(); } } else { mUartService.connect(deviceAddress); } } break; } case REQUEST_ENABLE_BT: { // When the request to enable Bluetooth returns if (resultCode == Activity.RESULT_OK) { Toast.makeText(this, "Bluetooth has turned on ", Toast.LENGTH_SHORT).show(); } else { // User did not enable Bluetooth or an error occurred Log.d(TAG, "BT not enabled"); Toast.makeText(this, "Problem in BT Turning ON ", Toast.LENGTH_SHORT).show(); finish(); } break; } case REQUEST_SELECT_FILE: { // Clear previous data mFwFilePath = null; mCfgFilePath = null; mTstFilePath = null; //mFileUri = null; // Read new one final Uri uri = data.getData(); /* * The URI returned from application may be in 'file' or 'content' schema. * 'File' schema allows us to create a File object and read details from it * directly. Data from 'Content' schema must be read by Content Provider. * To do that we are using a Loader. */ if (uri.getScheme().equals("file")) { // the direct path to the file has been returned final String path = uri.getPath(); final File file = new File(path); switch (mFileType) { case FILE_TYPE_ZIP: mFwFilePath = path; break; case FILE_TYPE_CFG: mCfgFilePath = path; break; case FILE_TYPE_TST: mTstFilePath = path; break; case FILE_TYPE_NONE: default: break; } updateFileInfo(file.getName(), file.length(), path, mFileType); } else if (uri.getScheme().equals("content")) { // an Uri has been returned //mFileUri = uri; // If application returned Uri for streaming, let's use it. Does it works? // FIXME both Uris works with Google Drive app. Why both? What's the difference? // How about other apps like DropBox? final Bundle extras = data.getExtras(); //if(extras != null && extras.containsKey(Intent.EXTRA_STREAM)) // mFileUri = extras.getParcelable(Intent.EXTRA_STREAM); // File name and size must be obtained from Content Provider final Bundle bundle = new Bundle(); bundle.putParcelable(EXTRA_URI, uri); getLoaderManager().restartLoader(REQUEST_SELECT_FILE, bundle, this); } break; } default: Log.e(TAG, "wrong request code"); break; } } private void showMessage(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } @Override public void onBackPressed() { if (mState == UART_PROFILE_CONNECTED) { Intent startMain = new Intent(Intent.ACTION_MAIN); startMain.addCategory(Intent.CATEGORY_HOME); startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(startMain); showMessage("nRFUART's running in background.\n Disconnect to exit"); } else { new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.popup_title) .setMessage(R.string.popup_message) .setPositiveButton(R.string.popup_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }).setNegativeButton(R.string.popup_no, null).show(); } } /************************************************************************************************/ /*** Buttons Click Callbacks ********************************************************************/ /************************************************************************************************/ // Handler Disconnect & Connect button public void onConnectBtnClicked(final View v) { if (!mBtAdapter.isEnabled()) { Log.i(TAG, "onClick - BT not enabled yet"); Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { if (mConnectBtn.getText().equals("Connect")) { //Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices Intent newIntent = new Intent(MainActivity.this, DeviceListActivity.class); startActivityForResult(newIntent, REQUEST_SELECT_DEVICE); } else { //Disconnect button pressed if (mBtDevice != null) { mUartService.disconnect(); } } } } // Handler Send button public void onSendBtnClicked(final View v) { String message = mSendMsg.getText().toString(); byte[] value; try { //Send Data to Service value = message.getBytes("UTF-8"); mUartService.writeRXCharacteristic(value); //Update the log with time stamp String currentDateTimeString = DateFormat.getTimeInstance().format(new Date()); mMsgListAdapter.add("[" + currentDateTimeString + "] TX: " + message); mMsgList.smoothScrollToPosition(mMsgListAdapter.getCount() - 1); mSendMsg.setText(""); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // Handler DAT Button public void onDatBtnClicked(final View v) { String message = "DAT"; byte[] value; try { //Send data to service value = message.getBytes("UTF-8"); mUartService.writeRXCharacteristic(value); //Update the log with time stamp String currentDateTimeString = DateFormat.getTimeInstance().format(new Date()); mMsgListAdapter.add("[" + currentDateTimeString + "] TX: " + message); mMsgList.smoothScrollToPosition(mMsgListAdapter.getCount() - 1); mSendMsg.setText(""); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // Handler Upload Button public void onUpgradeBtnClicked(final View view) { if (isDfuServiceRunning()) { showUploadCancelDialog(); return; } if (mFwFilePath == null) { printMessage("ERROR: Wrong FirmWare File!", true); return; } // Save current state in order to restore it if user quit the Activity //final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); //final SharedPreferences.Editor editor = preferences.edit(); //editor.putString(PREFS_DEVICE_NAME, mSelectedDevice.getName()); //editor.putString(PREFS_FILE_NAME, mFileNameView.getText().toString()); //editor.putString(PREFS_FILE_TYPE, mFileTypeView.getText().toString()); //editor.putString(PREFS_FILE_SIZE, mFileSizeView.getText().toString()); //editor.apply(); //showProgressBar(); //final boolean keepBond = preferences.getBoolean(SettingsFragment.SETTINGS_KEEP_BOND, false); final DfuServiceInitiator starter = new DfuServiceInitiator(mBtDevice.getAddress()) .setDeviceName(mBtDevice.getName()).setKeepBond(false).setZip(null, mFwFilePath); starter.start(this, DfuService.class); } public void onLedBoxClicked(final View view) { String message; if (mLedBox.isChecked()) { message = "N5"; } else { message = "F5"; } byte[] value; try { value = message.getBytes("UTF-8"); mUartService.writeRXCharacteristic(value); printMessage("TX: " + message, true); mSendMsg.setText(""); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void showUploadCancelDialog() { final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION); pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_PAUSE); manager.sendBroadcast(pauseAction); //final UploadCancelFragment fragment = UploadCancelFragment.getInstance(); //fragment.show(getSupportFragmentManager(), TAG); } private boolean isDfuServiceRunning() { ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (DfuService.class.getName().equals(service.service.getClassName())) { return true; } } return false; } /************************************************************************************************/ /* Loader Callbacks */ /************************************************************************************************/ @Override public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { final Uri uri = args.getParcelable(EXTRA_URI); /* * Some apps, f.e. Google Drive allow to select file that is not on the device. There is no "_data" column handled by that provider. Let's try to obtain * all columns and than check which columns are present. */ // final String[] projection = new String[] { MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DATA }; return new CursorLoader(this, uri, null /* all columns, instead of projection */, null, null, null); } @Override public void onLoaderReset(final Loader<Cursor> loader) { mFwFilePath = null; mCfgFilePath = null; mTstFilePath = null; //mFileUri = null; } @Override public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) { if (data != null && data.moveToNext()) { /* * Here we have to check the column indexes by name as we have requested for all. The order may be different. */ final String fileName = data .getString(data.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)/* 0 DISPLAY_NAME */); final int fileSize = data.getInt(data.getColumnIndex(MediaStore.MediaColumns.SIZE) /* 1 SIZE */); String filePath = null; final int dataIndex = data.getColumnIndex(MediaStore.MediaColumns.DATA); if (dataIndex != -1) { filePath = data.getString(dataIndex /* 2 DATA */); } if (!TextUtils.isEmpty(filePath)) { switch (mFileType) { case FILE_TYPE_ZIP: mFwFilePath = filePath; break; case FILE_TYPE_CFG: mCfgFilePath = filePath; break; case FILE_TYPE_TST: mTstFilePath = filePath; break; case FILE_TYPE_NONE: default: break; } } updateFileInfo(fileName, fileSize, filePath, mFileType); } else { mFwFilePath = null; mCfgFilePath = null; mTstFilePath = null; //mFileUri = null; } } private void updateFileInfo(String aFileName, long aFileSize, String aFilePath, int aFileType) { String mType; switch (aFileType) { case FILE_TYPE_ZIP: mType = "ZIP"; break; case FILE_TYPE_CFG: mType = "CFG"; break; case FILE_TYPE_TST: mType = "TST"; break; case FILE_TYPE_NONE: default: mType = "NONE"; break; } printMessage("- Path = " + aFilePath, false); printMessage("- Name = " + aFileName, false); printMessage("- Size = " + aFileSize + " Bytes", false); printMessage("- Type = " + mType, false); //final String extension = mFileType == DfuService.TYPE_AUTO ? "(?i)ZIP" : "(?i)HEX|BIN"; // (?i) = case insensitive //final boolean statusOk = mStatusOk = MimeTypeMap.getFileExtensionFromUrl(fileName).matches(extension); //mFileStatusView.setText(statusOk ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid); //mUploadButton.setEnabled(mSelectedDevice != null && statusOk); // Ask the user for the Init packet file if HEX or BIN files are selected. In case of a ZIP file the Init packets should be included in the ZIP. //if (statusOk && fileType != DfuService.TYPE_AUTO) { // new AlertDialog.Builder(this).setTitle(R.string.dfu_file_init_title).setMessage(R.string.dfu_file_init_message) // .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { // mInitFilePath = null; // mInitFileStreamUri = null; // } // }).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { // final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); // intent.setType(DfuService.MIME_TYPE_OCTET_STREAM); // intent.addCategory(Intent.CATEGORY_OPENABLE); // startActivityForResult(intent, SELECT_INIT_FILE_REQ); // } // }).show(); //} } /************************************************************************************************/ /* Set File Functions */ /************************************************************************************************/ /** * Called when Select File was pressed * * @param view a button that was pressed */ public void onSetFwFileBtnClicked(final View view) { printMessage("Set FirmWare File Action Performed", true); //printMessage(" Path = " + mFilePath, false); //mFileTypeTmp = mFileType; //int index = 0; //switch (mFileType) { // case DfuService.TYPE_AUTO: // index = 0; // break; // case DfuService.TYPE_SOFT_DEVICE: // index = 1; // break; // case DfuService.TYPE_BOOTLOADER: // index = 2; // break; // case DfuService.TYPE_APPLICATION: // index = 3; // break; //} // Show a dialog with file types // new AlertDialog.Builder(this) // .setTitle(R.string.dfu_title) // .setSingleChoiceItems(R.array.dfu_file_type, index, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { // switch (which) { // case 0: // mFileTypeTmp = DfuService.TYPE_AUTO; // break; // case 1: // mFileTypeTmp = DfuService.TYPE_SOFT_DEVICE; // break; // case 2: // mFileTypeTmp = DfuService.TYPE_BOOTLOADER; // break; // case 3: // mFileTypeTmp = DfuService.TYPE_APPLICATION; // break; // } // } // }).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { //openFileChooser(mFileType); // } //}).setNeutralButton(R.string.dfu_file_info, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { // final ZipInfoFragment fragment = new ZipInfoFragment(); // fragment.show(getSupportFragmentManager(), "help_fragment"); // } //}).setNegativeButton(R.string.cancel, null).show(); mFileType = FILE_TYPE_ZIP; OpenFileDialog mFileDialog = new OpenFileDialog(this).setFilter(".*\\.zip") .setOpenDialogListener(new OpenFileListener()); mFileDialog.show(); } private void openFileChooser(int aFileType) { final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType(aFileType == FILE_TYPE_ZIP ? DfuService.MIME_TYPE_ZIP : MIME_TYPE_TEXT); //intent.setType(DfuService.MIME_TYPE_ZIP); intent.addCategory(Intent.CATEGORY_OPENABLE); if (intent.resolveActivity(getPackageManager()) != null) { // file browser has been found on the device startActivityForResult(intent, REQUEST_SELECT_FILE); } //else //{ // there is no any file browser app, let's try to download one // final View customView = getLayoutInflater().inflate(R.layout.app_file_browser, null); // final ListView appsList = (ListView) customView.findViewById(android.R.id.list); // appsList.setAdapter(new FileBrowserAppsAdapter(this)); // appsList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); // appsList.setItemChecked(0, true); // new AlertDialog.Builder(this).setTitle(R.string.dfu_alert_no_filebrowser_title).setView(customView) // .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { // dialog.dismiss(); // } // }).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { // @Override // public void onClick(final DialogInterface dialog, final int which) { // final int pos = appsList.getCheckedItemPosition(); // if (pos >= 0) { // final String query = getResources().getStringArray(R.array.dfu_app_file_browser_action)[pos]; // final Intent storeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(query)); // startActivity(storeIntent); // } // } // }).show(); //} } public void onSetCfgFileBtnClicked(final View view) { printMessage("Set Config File Action Performed", true); mFileType = FILE_TYPE_CFG; OpenFileDialog mFileDialog = new OpenFileDialog(this).setFilter(".*\\.cfg") .setOpenDialogListener(new OpenFileListener()); mFileDialog.show(); } public void onSetTstFileBtnClicked(final View view) { printMessage("Set Testing File Action Performed :", true); mFileType = FILE_TYPE_TST; OpenFileDialog mFileDialog = new OpenFileDialog(this).setFilter(".*\\.tst") .setOpenDialogListener(new OpenFileListener()); mFileDialog.show(); } /************************************************************************************************/ /* Configuration/Testing Task */ /************************************************************************************************/ public class aScriptTask extends AsyncTask<String, String, String> { private final int MODE_IDLE = 0; private final int MODE_CONFIG = 1; private final int MODE_TEST = 2; private String cTag = "ScriptTask"; private String cRxData = null; private String cRxMsg; private byte[] cTxBuffer; private int cMode = MODE_IDLE; private FileParser cParser = null; private int cCmdCount = 0; private int cCmdIndex = 0; public synchronized void putRxData(byte[] aData) { try { cRxData = new String(aData, "UTF-8"); Log.d(cTag, "Data Received -> " + cRxData); } catch (UnsupportedEncodingException e) { cRxData = null; Log.d(cTag, "Exception occured while data receiving: " + e.getMessage()); } } private synchronized boolean sendMessage(String aMessage) { try { cTxBuffer = aMessage.getBytes("UTF-8"); mUartService.writeRXCharacteristic(cTxBuffer); publishProgress("TX: " + aMessage); return true; } catch (UnsupportedEncodingException e) { Log.d(cTag, "Error while data send" + e.getMessage()); return false; } } private String readMessage(int aTimeout) { cRxData = null; try { this.wait(aTimeout); if (cRxData != null) { publishProgress("RX: " + cRxData); Log.d(cTag, "Data Received: " + cRxData); } return cRxData; } catch (Exception e) { Log.d(cTag, "Read Message Exception Occured" + e.getMessage()); return null; } } private void delay(int aTimeout, boolean aLog) { if (aTimeout == 0) return; try { if (aLog) publishProgress("P: " + aTimeout + " ms"); Thread.sleep(aTimeout); } catch (InterruptedException e) { return; } } @Override protected void onPreExecute() { super.onPreExecute(); switch (mFileType) { case FILE_TYPE_CFG: cMode = MODE_CONFIG; printMessage("Device configuration started...", true); break; case FILE_TYPE_TST: cMode = MODE_TEST; printMessage("Device testing started...", true); break; default: cMode = MODE_IDLE; printMessage("Wrong file!", true); break; } setUIState(TTC_BUSY); mProgressBar.setIndeterminate(true); mProgressBar.setProgress(0); Log.d(cTag, "Do Pre Execute : Server = "); } @Override protected synchronized String doInBackground(String... message) { String mFileVer, mHWVer, mSWVer; int mFileType; Log.d(cTag, "Do In Background..."); publishProgress(" - File = " + message[0]); switch (cMode) { case MODE_CONFIG: cParser = new ConfigFileParser(message[0]); mFileType = CompatTable.CONFIG; break; case MODE_TEST: cParser = new TestFileParser(message[0]); mFileType = CompatTable.TEST; break; case MODE_IDLE: default: return null; } if (!cParser.isValid()) return null; publishProgress(" - File Version = " + cParser.getFileVersion()); mFileVer = cParser.getFileVersion(); /********************************************/ publishProgress("SoftWare Version Request..."); if (!sendMessage("VS")) return null; cRxMsg = readMessage(3000); if ((cRxMsg == null) || (!cRxMsg.contains("VS"))) { publishProgress("Wrong SoftWare Version!"); return null; } mSWVer = cRxMsg.substring(cRxMsg.indexOf("VS") + 2); delay(10, false); /********************************************/ publishProgress("HardWare Version Request..."); if (!sendMessage("VH")) return null; cRxMsg = readMessage(3000); if ((cRxMsg == null) || (!cRxMsg.contains("VH"))) { publishProgress("Wrong HardWare Version!"); return null; } mHWVer = cRxMsg.substring(cRxMsg.indexOf("VH") + 2); delay(10, false); /********************************************/ publishProgress("Checking versions compatibility"); publishProgress(" HW = " + mHWVer + " : SW = " + mSWVer + " : File = " + mFileVer); if (mCompatTable.checkValidity(mHWVer, mSWVer, mFileVer, mFileType)) { publishProgress(" Success"); } else { publishProgress(" ERROR!"); return null; } /********************************************/ publishProgress("Performing command sequence..."); FileParser.Command aCmd; cParser.selectFirstCommand(); cCmdCount = cParser.getCommandsCount(); cCmdIndex = 0; while ((aCmd = cParser.getNextCommand()) != null) { sendMessage(aCmd.getCommand()); readMessage(100); delay(aCmd.getPause(), true); cCmdIndex++; } return "Good!"; } @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); printMessage(values[0], true); if (cCmdCount == 0) { mProgressBar.setIndeterminate(true); mProgressBar.setProgress(0); } else { mProgressBar.setIndeterminate(false); mProgressBar.setProgress(100 * cCmdIndex / cCmdCount); } Log.d(cTag, "Do On Progress"); } @Override protected void onCancelled() { super.onCancelled(); Log.d(cTag, "Do On Cancelled"); } @Override protected void onPostExecute(String aResult) { super.onPostExecute(aResult); Log.d(cTag, "Do Post Execute"); setUIState(TTC_READY); mProgressBar.setIndeterminate(false); mProgressBar.setProgress(0); if (aResult == null) printMessage("ERROR!", true); printMessage("Done!", true); mScriptTask = null; } } /************************************************************************************************/ /* Alternate Open File Chooser */ /************************************************************************************************/ private class OpenFileListener implements OpenFileDialog.OpenDialogListener { @Override public void OnSelectedFile(String aFileName) { final File file = new File(aFileName); switch (mFileType) { case FILE_TYPE_ZIP: mFwFilePath = aFileName; break; case FILE_TYPE_CFG: mCfgFilePath = aFileName; break; case FILE_TYPE_TST: mTstFilePath = aFileName; break; case FILE_TYPE_NONE: default: break; } updateFileInfo(file.getName(), file.length(), aFileName, mFileType); } } /************************************************************************************************/ /* Alternate Open File Chooser */ /************************************************************************************************/ public void onConfigDeviceBtnClicked(final View view) { if (mCfgFilePath != null) { mScriptTask = new aScriptTask(); mScriptTask.execute(mCfgFilePath); } else { printMessage("Select configuration file first...", false); } } public void onTestDeviceBtnClicked(final View view) { if (mTstFilePath != null) { mScriptTask = new aScriptTask(); mScriptTask.execute(mTstFilePath); } else { printMessage("Select test file first...", false); } } }