com.buddi.client.dfu.DfuActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.buddi.client.dfu.DfuActivity.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA. Terms and conditions of usage are described in detail in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 * Licensees are granted free, non-transferable use of the information. NO WARRANTY of ANY KIND is provided. This heading must NOT be removed from the file.
 ******************************************************************************/
package com.buddi.client.dfu;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/*
import java.net.URI;
import java.net.URISyntaxException;
    
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
*/
import com.buddi.client.ModuleActivity;
import com.buddi.blueband.client.R;

import com.buddi.client.dfu.AppHelpFragment;
import com.buddi.client.dfu.adapter.FileBrowserAppsAdapter;
import com.buddi.client.dfu.fragment.UploadCancelFragment;
import com.buddi.client.dfu.fragment.ZipInfoFragment;
import com.buddi.client.dfu.settings.SettingsActivity;
import com.buddi.client.scanner.ScannerFragment;
import com.buddi.client.util.GattError;
import com.buddi.service.BuddiBLEService;

import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
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.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
//import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
//import android.support.v4.app.FragmentManager;
//import android.support.v4.app.LoaderManager.LoaderCallbacks;
//import android.support.v4.app.FragmentActivity;
//import android.support.v4.content.Loader;
import android.support.v4.content.LocalBroadcastManager;
//import android.support.v4.content.CursorLoader;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

/**
 * DfuActivity is the main DFU activity It implements DFUManagerCallbacks to receive callbacks from DFUManager class It implements DeviceScannerFragment.OnDeviceSelectedListener callback to receive
 * callback when device is selected from scanning dialog The activity supports portrait and landscape orientations
 */
public class DfuActivity extends Activity implements LoaderCallbacks<Cursor>,
        ScannerFragment.OnDeviceSelectedListener, UploadCancelFragment.CancelFragmentListener {
    private static final String TAG = "DfuActivity";

    private static final String PREFS_DEVICE_NAME = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_DEVICE_NAME";
    private static final String PREFS_FILE_NAME = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_NAME";
    private static final String PREFS_FILE_TYPE = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_TYPE";
    private static final String PREFS_FILE_SIZE = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_SIZE";

    private static final String DATA_DEVICE = "device";
    private static final String DATA_FILE_TYPE = "file_type";
    private static final String DATA_FILE_TYPE_TMP = "file_type_tmp";
    private static final String DATA_FILE_PATH = "file_path";
    private static final String DATA_FILE_STREAM = "file_stream";
    private static final String DATA_STATUS = "status";

    //public static final String EXTRA_DEVICE_ADDRESS = "EXTRA_DEVICE_ADDRESS";
    //public static final String EXTRA_DEVICE_NAME = "EXTRA_DEVICE_NAME";
    //public static final String EXTRA_PROGRESS = "EXTRA_PROGRESS";

    private static final String EXTRA_URI = "uri";

    private static final int SELECT_FILE_REQ = 1;
    static final int REQUEST_ENABLE_BT = 2;

    private TextView mDeviceNameView;
    private TextView mFileNameView;
    private TextView mFileTypeView;
    private TextView mFileSizeView;
    private TextView mFileStatusView;
    private TextView mTextPercentage;
    private TextView mTextUploading;
    private ProgressBar mProgressBar;

    private Button mSelectFileButton, mUploadButton, mConnectButton;

    private BluetoothDevice mSelectedDevice;
    private String mFilePath;
    private Uri mFileStreamUri;
    private int mFileType;
    private int mFileTypeTmp; // This value is being used when user is selecting a file not to overwrite the old value (in case he/she will cancel selecting file)
    private boolean mStatusOk;

    private final BroadcastReceiver mDfuUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            // DFU is in progress or an error occurred 
            final String action = intent.getAction();

            if (DfuService.BROADCAST_PROGRESS.equals(action)) {
                final int progress = intent.getIntExtra(DfuService.EXTRA_DATA, 0);
                final int currentPart = intent.getIntExtra(DfuService.EXTRA_PART_CURRENT, 1);
                final int totalParts = intent.getIntExtra(DfuService.EXTRA_PARTS_TOTAL, 1);
                updateProgressBar(progress, currentPart, totalParts, false);
            } else if (DfuService.BROADCAST_ERROR.equals(action)) {
                final int error = intent.getIntExtra(DfuService.EXTRA_DATA, 0);
                updateProgressBar(error, 0, 0, true);

                // 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() {
                        // 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
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_feature_dfu);
        isBLESupported();
        if (!isBLEEnabled()) {
            showBLEDialog();
        }
        setGUI();

        ensureSamplesExist();

        // restore saved state
        mFileType = DfuService.TYPE_APPLICATION; // Default
        if (savedInstanceState != null) {
            mFileType = savedInstanceState.getInt(DATA_FILE_TYPE);
            mFileTypeTmp = savedInstanceState.getInt(DATA_FILE_TYPE_TMP);
            mFilePath = savedInstanceState.getString(DATA_FILE_PATH);
            mFileStreamUri = savedInstanceState.getParcelable(DATA_FILE_STREAM);
            mSelectedDevice = savedInstanceState.getParcelable(DATA_DEVICE);
            mStatusOk = mStatusOk || savedInstanceState.getBoolean(DATA_STATUS);
            mUploadButton.setEnabled(mSelectedDevice != null && mStatusOk);
        }
        //mSelectedDevice= getIntent().getParcelableExtra(ModuleActivity.EXTRA_BLE_DEVICE);
    }

    @Override
    protected void onSaveInstanceState(final Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(DATA_FILE_TYPE, mFileType);
        outState.putInt(DATA_FILE_TYPE_TMP, mFileTypeTmp);
        outState.putString(DATA_FILE_PATH, mFilePath);
        outState.putParcelable(DATA_FILE_STREAM, mFileStreamUri);
        outState.putParcelable(DATA_DEVICE, mSelectedDevice);
        outState.putBoolean(DATA_STATUS, mStatusOk);
    }

    private void setGUI() {
        final ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);

        mDeviceNameView = (TextView) findViewById(R.id.device_name);
        mFileNameView = (TextView) findViewById(R.id.file_name);
        mFileTypeView = (TextView) findViewById(R.id.file_type);
        mFileSizeView = (TextView) findViewById(R.id.file_size);
        mFileStatusView = (TextView) findViewById(R.id.file_status);
        mSelectFileButton = (Button) findViewById(R.id.action_select_file);

        mUploadButton = (Button) findViewById(R.id.action_upload);
        mConnectButton = (Button) findViewById(R.id.action_connect);
        mTextPercentage = (TextView) findViewById(R.id.textviewProgress);
        mTextUploading = (TextView) findViewById(R.id.textviewUploading);
        mProgressBar = (ProgressBar) findViewById(R.id.progressbar_file);

        final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        final boolean uploadInProgress = preferences.getBoolean(DfuService.DFU_IN_PROGRESS, false);
        if (uploadInProgress) {
            // Restore image file information
            mDeviceNameView.setText(preferences.getString(PREFS_DEVICE_NAME, ""));
            mFileNameView.setText(preferences.getString(PREFS_FILE_NAME, ""));
            mFileTypeView.setText(preferences.getString(PREFS_FILE_TYPE, ""));
            mFileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, ""));
            mFileStatusView.setText(R.string.dfu_file_status_ok);
            mStatusOk = true;
            showProgressBar();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        // We are using LocalBroadcastReceiver instead of normal BroadcastReceiver for optimization purposes
        final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
        broadcastManager.registerReceiver(mDfuUpdateReceiver, makeDfuUpdateIntentFilter());
    }

    @Override
    protected void onPause() {
        super.onPause();

        final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
        broadcastManager.unregisterReceiver(mDfuUpdateReceiver);
    }

    private static IntentFilter makeDfuUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(DfuService.BROADCAST_PROGRESS);
        intentFilter.addAction(DfuService.BROADCAST_ERROR);
        intentFilter.addAction(DfuService.BROADCAST_LOG);
        return intentFilter;
    }

    private void isBLESupported() {
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            showToast(R.string.no_ble);
            finish();
        }
    }

    private boolean isBLEEnabled() {
        final BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        final BluetoothAdapter adapter = manager.getAdapter();
        return adapter != null && adapter.isEnabled();
    }

    private void showBLEDialog() {
        final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
    }

    private void showDeviceScanningDialog() {
        final FragmentManager fm = getFragmentManager();
        final ScannerFragment dialog = ScannerFragment.getInstance(DfuActivity.this, null, true);
        dialog.show(fm, "scan_fragment");
    }

    private void ensureSamplesExist() {
        /*
         * copy example HEX files to the external storage.
         * Files will be copied if the DFU Applications folder is missing
         */
        final File folder = new File(Environment.getExternalStorageDirectory(), "Nordic Semiconductor");
        if (!folder.exists()) {
            folder.mkdir();
        }

        boolean oldCopied = false;
        boolean newCopied = false;
        File f = new File(folder, "ble_app_hrs_s110_v6_0_0.hex");
        if (!f.exists()) {
            copyRawResource(R.raw.ble_app_hrs_s110_v6_0_0, f);
            oldCopied = true;
        }
        f = new File(folder, "ble_app_rscs_s110_v6_0_0.hex");
        if (!f.exists()) {
            copyRawResource(R.raw.ble_app_rscs_s110_v6_0_0, f);
            oldCopied = true;
        }
        f = new File(folder, "ble_app_hrs_s110_v7_0_0.hex");
        if (!f.exists()) {
            copyRawResource(R.raw.ble_app_hrs_s110_v7_0_0, f);
            newCopied = true;
        }
        f = new File(folder, "ble_app_rscs_s110_v7_0_0.hex");
        if (!f.exists()) {
            copyRawResource(R.raw.ble_app_rscs_s110_v7_0_0, f);
            newCopied = true;
        }
        f = new File(folder, "blinky_arm_s110_v7_0_0.hex");
        if (!f.exists()) {
            copyRawResource(R.raw.blinky_arm_s110_v7_0_0, f);
            newCopied = true;
        }

        if (oldCopied)
            Toast.makeText(this, R.string.dfu_example_files_created, Toast.LENGTH_LONG).show();
        else if (newCopied)
            Toast.makeText(this, R.string.dfu_example_new_files_created, Toast.LENGTH_LONG).show();

        // Scripts
        newCopied = false;
        f = new File(folder, "dfu_2_0.bat");
        if (!f.exists()) {
            copyRawResource(R.raw.dfu_win_2_0, f);
            newCopied = true;
        }
        f = new File(folder, "dfu_2_0.sh");
        if (!f.exists()) {
            copyRawResource(R.raw.dfu_mac_2_0, f);
            newCopied = true;
        }
        f = new File(folder, "README.txt");
        if (newCopied) {
            copyRawResource(R.raw.readme, f);
        }
        if (newCopied)
            Toast.makeText(this, R.string.dfu_scripts_created, Toast.LENGTH_LONG).show();
    }

    /**
     * Copies the file from res/raw with given id to given destination file. If dest does not exist it will be created.
     * 
     * @param rawResId
     *            the resource id
     * @param dest
     *            destination file
     */
    private void copyRawResource(final int rawResId, final File dest) {
        try {
            final InputStream is = getResources().openRawResource(rawResId);
            final FileOutputStream fos = new FileOutputStream(dest);

            final byte[] buf = new byte[1024];
            int read = 0;
            try {
                while ((read = is.read(buf)) > 0)
                    fos.write(buf, 0, read);
            } finally {
                is.close();
                fos.close();
            }
        } catch (final IOException e) {
            Log.e(TAG, "Error while copying HEX file " + e.toString());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        getMenuInflater().inflate(R.menu.dfu_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            break;
        case R.id.action_about:
            final AppHelpFragment fragment = AppHelpFragment.getInstance(R.string.dfu_about_text);
            fragment.show(getFragmentManager(), "help_fragment");
            break;
        case R.id.action_settings:
            final Intent intent = new Intent(this, SettingsActivity.class);
            startActivity(intent);
            break;
        }
        return true;
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        if (resultCode != RESULT_OK)
            return;

        switch (requestCode) {
        case SELECT_FILE_REQ:
            // clear previous data
            mFileType = mFileTypeTmp;
            mFilePath = null;
            mFileStreamUri = null;

            // and 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 if 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);
                mFilePath = path;

                updateFileInfo(file.getName(), file.length(), mFileType);
            } else if (uri.getScheme().equals("content")) {
                // an Uri has been returned
                mFileStreamUri = uri;
                // if application returned Uri for streaming, let's us 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))
                    mFileStreamUri = 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);
                //getSupportLoaderManager().restartLoader(0, bundle, this);
                getLoaderManager().restartLoader(0, bundle, this);
            }
            break;
        default:
            break;
        }
    }

    @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) {
        mFileNameView.setText(null);
        mFileTypeView.setText(null);
        mFileSizeView.setText(null);
        mFilePath = null;
        mFileStreamUri = null;
        mStatusOk = false;
    }

    @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))
                mFilePath = filePath;

            updateFileInfo(fileName, fileSize, mFileType);
        } else {
            mFileNameView.setText(null);
            mFileTypeView.setText(null);
            mFileSizeView.setText(null);
            mFilePath = null;
            mFileStreamUri = null;
            mFileStatusView.setText(R.string.dfu_file_status_error);
            mStatusOk = false;
        }
    }

    /**
      * Updates the file information on UI
      *
      * @param fileName
      *            file name
      * @param fileSize
      *            file length
      */
    private void updateFileInfo(final String fileName, final long fileSize, final int fileType) {
        mFileNameView.setText(fileName);
        switch (fileType) {
        case DfuService.TYPE_SOFT_DEVICE:
            mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[0]);
            break;
        case DfuService.TYPE_BOOTLOADER:
            mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[1]);
            break;
        case DfuService.TYPE_APPLICATION:
            mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[2]);
            break;
        case DfuService.TYPE_AUTO:
            mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[3]);
            break;
        }
        mFileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize));
        final String extension = mFileType == DfuService.TYPE_AUTO ? "ZIP" : "HEX";
        final boolean isHexFile = mStatusOk = MimeTypeMap.getFileExtensionFromUrl(fileName)
                .equalsIgnoreCase(extension);
        mFileStatusView.setText(isHexFile ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid);
        mUploadButton.setEnabled(mSelectedDevice != null && isHexFile);
    }

    /**
    * Called when the question mark was pressed
    * 
    * @param view
    *            a button that was pressed
    */
    public void onSelectFileHelpClicked(final View view) {
        new AlertDialog.Builder(this).setTitle(R.string.dfu_help_title).setMessage(R.string.dfu_help_message)
                .setPositiveButton(android.R.string.ok, null).show();
    }

    /**
     * Called when Select File was pressed
     * 
     * @param view
     *            a button that was pressed
     */
    public void onSelectFileClicked(final View view) {
        mFileTypeTmp = mFileType;
        int index = 2;
        switch (mFileType) {
        case DfuService.TYPE_SOFT_DEVICE:
            index = 0;
            break;
        case DfuService.TYPE_BOOTLOADER:
            index = 1;
            break;
        case DfuService.TYPE_APPLICATION:
            index = 2;
            break;
        case DfuService.TYPE_AUTO:
            index = 3;
            break;
        }
        // Show a dialog with file types
        new AlertDialog.Builder(this).setTitle(R.string.dfu_file_type_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_SOFT_DEVICE;
                            break;
                        case 1:
                            mFileTypeTmp = DfuService.TYPE_BOOTLOADER;
                            break;
                        case 2:
                            mFileTypeTmp = DfuService.TYPE_APPLICATION;
                            break;
                        case 3:
                            mFileTypeTmp = DfuService.TYPE_AUTO;
                            break;
                        }
                    }
                }).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(final DialogInterface dialog, final int which) {
                        openFileChooser();
                    }
                }).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(getFragmentManager(), "help_fragment");
                    }
                }).setNegativeButton(android.R.string.cancel, null).show();
    }

    private void openFileChooser() {
        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType(mFileTypeTmp == DfuService.TYPE_AUTO ? DfuService.MIME_TYPE_ZIP : DfuService.MIME_TYPE_HEX);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        if (intent.resolveActivity(getPackageManager()) != null) {
            // file browser has been found on the device
            startActivityForResult(intent, SELECT_FILE_REQ);
        } 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(android.R.string.no, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(final DialogInterface dialog, final int which) {
                            dialog.dismiss();
                        }
                    }).setPositiveButton(android.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();
        }
    }
    /*
    private class CheckFilesTask extends AsyncTask<Uri, Integer, Long> {
    private Uri uri;
        
    @Override
    protected Long doInBackground(Uri... params) {
        long len;
        HttpResponse response = null;
        uri= params[0];
        try {
            HttpClient httpclient= new DefaultHttpClient();
            HttpGet httpget= new HttpGet(uri.toString());
            response= httpclient.execute(httpget);
            HttpEntity entity= response.getEntity();
            len= entity.getContentLength();
            mStatusOk= true;
        } catch (IOException e) {
            len= -1;
        }
        
        return len;
    }
        
    protected void onPostExecute(final Long result) {
        mFileNameView.setText(uri.toString());
        if (result != -1) {
            mFileSizeView.setText(getString(R.string.dfu_file_size_text, result));
            mFileStatusView.setText(R.string.dfu_file_status_ok);
            mUploadButton.setEnabled(mSelectedDevice != null);
        } else {
            mFileSizeView.setText("N/A");
            mFileStatusView.setText("File unavailable");
            mUploadButton.setEnabled(false);
        }
    }
        
    };
        
    public void onUpdateLatestClicked(final View view) {
    mFileStreamUri= Uri.parse("http://releases.mbientlab.com/metawear/vanilla/latest/firmware.hex");
    new CheckFilesTask().execute(mFileStreamUri);
    }
    */

    /**
     * Callback of UPDATE/CANCEL button on DfuActivity
     */
    public void onUploadClicked(final View view) {
        final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        final boolean dfuInProgress = preferences.getBoolean(DfuService.DFU_IN_PROGRESS, false);
        if (dfuInProgress) {
            showUploadCancelDialog();
            return;
        }

        // check whether the selected file is a HEX file (we are just checking the extension)
        if (!mStatusOk) {
            Toast.makeText(this, R.string.dfu_file_status_invalid_message, Toast.LENGTH_LONG).show();
            return;
        }

        // Save current state in order to restore it if user quit the Activity
        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.commit();

        showProgressBar();

        final Intent service = new Intent(this, DfuService.class);
        service.putExtra(DfuService.EXTRA_DEVICE_ADDRESS, mSelectedDevice.getAddress());
        service.putExtra(DfuService.EXTRA_DEVICE_NAME, mSelectedDevice.getName());
        service.putExtra(DfuService.EXTRA_FILE_MIME_TYPE,
                mFileType == DfuService.TYPE_AUTO ? DfuService.MIME_TYPE_ZIP : DfuService.MIME_TYPE_HEX);
        service.putExtra(DfuService.EXTRA_FILE_TYPE, mFileType);
        service.putExtra(DfuService.EXTRA_FILE_PATH, mFilePath);
        service.putExtra(DfuService.EXTRA_FILE_URI, mFileStreamUri);
        startService(service);
    }

    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(getFragmentManager(), TAG);
    }

    /**
     * Callback of CONNECT/DISCONNECT button on DfuActivity
     */
    public void onConnectClicked(final View view) {
        if (isBLEEnabled()) {
            showDeviceScanningDialog();
        } else {
            showBLEDialog();
        }
    }

    @Override
    public void onDeviceSelected(final BluetoothDevice device, final String name) {
        mSelectedDevice = device;
        mUploadButton.setEnabled(mStatusOk);
        mDeviceNameView.setText(name);
    }

    @Override
    public void onDialogCanceled() {
        // do nothing
    }

    private void updateProgressBar(final int progress, final int part, final int total, final boolean error) {
        switch (progress) {
        case DfuService.PROGRESS_CONNECTING:
            mProgressBar.setIndeterminate(true);
            mTextPercentage.setText(R.string.dfu_status_connecting);
            break;
        case DfuService.PROGRESS_STARTING:
            mProgressBar.setIndeterminate(true);
            mTextPercentage.setText(R.string.dfu_status_starting);
            break;
        case DfuService.PROGRESS_VALIDATING:
            mProgressBar.setIndeterminate(true);
            mTextPercentage.setText(R.string.dfu_status_validating);
            break;
        case DfuService.PROGRESS_DISCONNECTING:
            mProgressBar.setIndeterminate(true);
            mTextPercentage.setText(R.string.dfu_status_disconnecting);
            break;
        case DfuService.PROGRESS_COMPLETED:
            mTextPercentage.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() {
                    onTransferCompleted();

                    // 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);
            break;
        case DfuService.PROGRESS_ABORTED:
            mTextPercentage.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() {
                    onUploadCanceled();

                    // 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);
            break;
        default:
            mProgressBar.setIndeterminate(false);
            if (error) {
                showErrorMessage(progress);
            } else {
                mProgressBar.setProgress(progress);
                mTextPercentage.setText(getString(R.string.progress, progress));
                if (total > 1)
                    mTextUploading.setText(getString(R.string.dfu_status_uploading_part, part, total));
                else
                    mTextUploading.setText(R.string.dfu_status_uploading);
            }
            break;
        }
    }

    private void showProgressBar() {
        mProgressBar.setVisibility(View.VISIBLE);
        mTextPercentage.setVisibility(View.VISIBLE);
        mTextPercentage.setText(null);
        mTextUploading.setText(R.string.dfu_status_uploading);
        mTextUploading.setVisibility(View.VISIBLE);
        mConnectButton.setEnabled(false);
        mSelectFileButton.setEnabled(false);
        mUploadButton.setEnabled(true);
        mUploadButton.setText(R.string.dfu_action_upload_cancel);
    }

    private void onTransferCompleted() {
        clearUI();
        showToast(R.string.dfu_success);
    }

    public void onUploadCanceled() {
        clearUI();
        showToast(R.string.dfu_aborted);
    }

    @Override
    public void onCancelUpload() {
        mProgressBar.setIndeterminate(true);
        mTextUploading.setText(R.string.dfu_status_aborting);
        mTextPercentage.setText(null);
    }

    private void showErrorMessage(final int code) {
        clearUI();
        showToast("Upload failed: " + GattError.parse(code) + " ("
                + (code & ~(DfuService.ERROR_MASK | DfuService.ERROR_REMOTE_MASK)) + ")");
    }

    private void clearUI() {
        mProgressBar.setVisibility(View.INVISIBLE);
        mTextPercentage.setVisibility(View.INVISIBLE);
        mTextUploading.setVisibility(View.INVISIBLE);
        mConnectButton.setEnabled(true);
        mSelectFileButton.setEnabled(true);
        mUploadButton.setEnabled(false);
        mSelectedDevice = null;
        mDeviceNameView.setText(R.string.dfu_default_name);
        mUploadButton.setText(R.string.dfu_action_upload);
    }

    @Override
    public void onDeviceSelected(final BluetoothDevice device, final String name,
            final BuddiBLEService.Bands band) {
        mSelectedDevice = device;
        mUploadButton.setEnabled(mStatusOk);
        mDeviceNameView.setText(name);
    }

    @Override
    public void onDialogCanceled() {
        // do nothing
    }

    @Override
    public void onBackPressed() {
        Intent result = new Intent();
        result.putExtra(ModuleActivity.EXTRA_BLE_DEVICE, mSelectedDevice);
        setResult(RESULT_OK, result);
        super.onBackPressed();
    }

    private void showToast(final int messageResId) {
        Toast.makeText(this, messageResId, Toast.LENGTH_SHORT).show();
    }

    private void showToast(final String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
}