Storage permission no longer used

This commit is contained in:
Aleksander Nowakowski
2020-02-03 12:06:15 +01:00
parent 26d218e551
commit 1dec23f5ca
23 changed files with 129 additions and 7260 deletions

View File

@@ -26,14 +26,12 @@
package="no.nordicsemi.android.nrftoolbox" package="no.nordicsemi.android.nrftoolbox"
android:installLocation="auto"> android:installLocation="auto">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="no.nordicsemi.android.LOG" /> <uses-permission android:name="no.nordicsemi.android.LOG" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-feature <uses-feature
android:name="android.hardware.bluetooth_le" android:name="android.hardware.bluetooth_le"

View File

@@ -1,78 +0,0 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.nrftoolbox;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AlertDialog;
public class PermissionRationaleFragment extends DialogFragment {
private static final String ARG_PERMISSION = "ARG_PERMISSION";
private static final String ARG_TEXT = "ARG_TEXT";
private PermissionDialogListener listener;
public interface PermissionDialogListener {
void onRequestPermission(final String permission);
}
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
if (context instanceof PermissionDialogListener) {
listener = (PermissionDialogListener) context;
} else {
throw new IllegalArgumentException("The parent activity must implement PermissionDialogListener");
}
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
public static PermissionRationaleFragment getInstance(final int aboutResId, final String permission) {
final PermissionRationaleFragment fragment = new PermissionRationaleFragment();
final Bundle args = new Bundle();
args.putInt(ARG_TEXT, aboutResId);
args.putString(ARG_PERMISSION, permission);
fragment.setArguments(args);
return fragment;
}
@Override
@NonNull
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = requireArguments();
final StringBuilder text = new StringBuilder(getString(args.getInt(ARG_TEXT)));
return new AlertDialog.Builder(requireContext()).setTitle(R.string.permission_title).setMessage(text)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, (dialog, which) -> listener.onRequestPermission(args.getString(ARG_PERMISSION))).create();
}
}

View File

@@ -21,14 +21,12 @@
*/ */
package no.nordicsemi.android.nrftoolbox.dfu; package no.nordicsemi.android.nrftoolbox.dfu;
import android.Manifest;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo; import android.app.ActivityManager.RunningServiceInfo;
import android.app.LoaderManager.LoaderCallbacks; import android.app.LoaderManager.LoaderCallbacks;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context; import android.content.Context;
import android.content.CursorLoader; import android.content.CursorLoader;
import android.content.Intent; import android.content.Intent;
@@ -42,13 +40,6 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.MediaStore; import android.provider.MediaStore;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@@ -62,12 +53,16 @@ import android.widget.Toast;
import java.io.File; import java.io.File;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import no.nordicsemi.android.dfu.DfuProgressListener; import no.nordicsemi.android.dfu.DfuProgressListener;
import no.nordicsemi.android.dfu.DfuProgressListenerAdapter; import no.nordicsemi.android.dfu.DfuProgressListenerAdapter;
import no.nordicsemi.android.dfu.DfuServiceInitiator; import no.nordicsemi.android.dfu.DfuServiceInitiator;
import no.nordicsemi.android.dfu.DfuServiceListenerHelper; import no.nordicsemi.android.dfu.DfuServiceListenerHelper;
import no.nordicsemi.android.nrftoolbox.AppHelpFragment; import no.nordicsemi.android.nrftoolbox.AppHelpFragment;
import no.nordicsemi.android.nrftoolbox.PermissionRationaleFragment;
import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.nrftoolbox.dfu.adapter.FileBrowserAppsAdapter; import no.nordicsemi.android.nrftoolbox.dfu.adapter.FileBrowserAppsAdapter;
import no.nordicsemi.android.nrftoolbox.dfu.fragment.UploadCancelFragment; import no.nordicsemi.android.nrftoolbox.dfu.fragment.UploadCancelFragment;
@@ -75,15 +70,14 @@ import no.nordicsemi.android.nrftoolbox.dfu.fragment.ZipInfoFragment;
import no.nordicsemi.android.nrftoolbox.dfu.settings.SettingsActivity; import no.nordicsemi.android.nrftoolbox.dfu.settings.SettingsActivity;
import no.nordicsemi.android.nrftoolbox.dfu.settings.SettingsFragment; import no.nordicsemi.android.nrftoolbox.dfu.settings.SettingsFragment;
import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment;
import no.nordicsemi.android.nrftoolbox.utility.FileHelper;
/** /**
* DfuActivity is the main DFU activity It implements DFUManagerCallbacks to receive callbacks from DFUManager class It implements * DfuActivity is the main DFU activity It implements DFUManagerCallbacks to receive callbacks from
* DeviceScannerFragment.OnDeviceSelectedListener callback to receive callback when device is selected from scanning dialog The activity supports portrait and * DfuManager class It implements DeviceScannerFragment.OnDeviceSelectedListener callback to receive callback when device is selected from scanning dialog The activity supports portrait and
* landscape orientations * landscape orientations
*/ */
public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cursor>, ScannerFragment.OnDeviceSelectedListener, public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cursor>, ScannerFragment.OnDeviceSelectedListener,
UploadCancelFragment.CancelFragmentListener, PermissionRationaleFragment.PermissionDialogListener { UploadCancelFragment.CancelFragmentListener {
private static final String TAG = "DfuActivity"; 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_DEVICE_NAME = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_DEVICE_NAME";
@@ -106,7 +100,6 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
private static final String EXTRA_URI = "uri"; private static final String EXTRA_URI = "uri";
private static final int PERMISSION_REQ = 25;
private static final int ENABLE_BT_REQ = 0; private static final int ENABLE_BT_REQ = 0;
private static final int SELECT_FILE_REQ = 1; private static final int SELECT_FILE_REQ = 1;
private static final int SELECT_INIT_FILE_REQ = 2; private static final int SELECT_INIT_FILE_REQ = 2;
@@ -248,16 +241,6 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
} }
setGUI(); setGUI();
// Try to create sample files
if (FileHelper.newSamplesAvailable(this)) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
FileHelper.createSamples(this);
} else {
final DialogFragment dialog = PermissionRationaleFragment.getInstance(R.string.permission_sd_text, Manifest.permission.WRITE_EXTERNAL_STORAGE);
dialog.show(getSupportFragmentManager(), null);
}
}
// restore saved state // restore saved state
fileType = DfuService.TYPE_AUTO; // Default fileType = DfuService.TYPE_AUTO; // Default
if (savedInstanceState != null) { if (savedInstanceState != null) {
@@ -355,27 +338,6 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
resumed = false; resumed = false;
} }
@Override
public void onRequestPermission(final String permission) {
ActivityCompat.requestPermissions(this, new String[] { permission }, PERMISSION_REQ);
}
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQ: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// We have been granted the Manifest.permission.WRITE_EXTERNAL_STORAGE permission. Now we may proceed with exporting.
FileHelper.createSamples(this);
} else {
Toast.makeText(this, R.string.no_required_permission, Toast.LENGTH_SHORT).show();
}
break;
}
}
}
private void isBLESupported() { private void isBLESupported() {
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
showToast(R.string.no_ble); showToast(R.string.no_ble);
@@ -384,8 +346,7 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
} }
private boolean isBLEEnabled() { private boolean isBLEEnabled() {
final BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final BluetoothAdapter adapter = manager.getAdapter();
return adapter != null && adapter.isEnabled(); return adapter != null && adapter.isEnabled();
} }
@@ -425,6 +386,7 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
@Override @Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) if (resultCode != RESULT_OK)
return; return;
@@ -437,10 +399,10 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
// and read new one // and read new one
final Uri uri = data.getData(); 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 * 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. * directly. Data from 'Content' schema must be read by Content Provider. To do that we are using a Loader.
*/ */
if (uri.getScheme().equals("file")) { if (uri.getScheme().equals("file")) {
// the direct path to the file has been returned // the direct path to the file has been returned
final String path = uri.getPath(); final String path = uri.getPath();
@@ -470,10 +432,10 @@ public class DfuActivity extends AppCompatActivity implements LoaderCallbacks<Cu
// and read new one // and read new one
final Uri uri = data.getData(); 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 * 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. * directly. Data from 'Content' schema must be read by Content Provider. To do that we are using a Loader.
*/ */
if (uri.getScheme().equals("file")) { if (uri.getScheme().equals("file")) {
// the direct path to the file has been returned // the direct path to the file has been returned
initFilePath = uri.getPath(); initFilePath = uri.getPath();

View File

@@ -82,6 +82,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.UUID; import java.util.UUID;
@@ -113,7 +114,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
private final static String SIS_EDIT_MODE = "sis_edit_mode"; private final static String SIS_EDIT_MODE = "sis_edit_mode";
private final static int SELECT_FILE_REQ = 2678; // random private final static int SELECT_FILE_REQ = 2678; // random
private final static int PERMISSION_REQ = 24; // random, 8-bit private final static int REQUEST_SAVE = 2679;
UARTConfigurationSynchronizer wearableSynchronizer; UARTConfigurationSynchronizer wearableSynchronizer;
@@ -364,11 +365,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
return true; return true;
} }
case R.id.action_export: { case R.id.action_export: {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { exportConfiguration();
exportConfiguration();
} else {
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, PERMISSION_REQ);
}
return true; return true;
} }
case R.id.action_rename: { case R.id.action_rename: {
@@ -405,22 +402,6 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
return false; return false;
} }
@Override
public void onRequestPermissionsResult(final int requestCode, final @NonNull String[] permissions, final @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQ: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// We have been granted the Manifest.permission.WRITE_EXTERNAL_STORAGE permission. Now we may proceed with exporting.
exportConfiguration();
} else {
Toast.makeText(this, R.string.no_required_permission, Toast.LENGTH_SHORT).show();
}
break;
}
}
}
@Override @Override
public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) { public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) {
if (position > 0) { // FIXME this is called twice after rotation. if (position > 0) { // FIXME this is called twice after rotation.
@@ -441,7 +422,14 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
else else
message = "Unknown error"; message = "Unknown error";
final String msg = message; final String msg = message;
Snackbar.make(container, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show(); Snackbar.make(container, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.uart_action_details, v ->
new AlertDialog.Builder(UARTActivity.this)
.setMessage(msg)
.setTitle(R.string.uart_action_details)
.setPositiveButton(R.string.ok, null)
.show())
.show();
return; return;
} }
@@ -484,14 +472,19 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
appsList.setAdapter(new FileBrowserAppsAdapter(this)); appsList.setAdapter(new FileBrowserAppsAdapter(this));
appsList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); appsList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
appsList.setItemChecked(0, true); appsList.setItemChecked(0, true);
new AlertDialog.Builder(this).setTitle(R.string.dfu_alert_no_filebrowser_title).setView(customView).setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss()).setPositiveButton(R.string.yes, (dialog, which) -> { new AlertDialog.Builder(this)
final int pos = appsList.getCheckedItemPosition(); .setTitle(R.string.dfu_alert_no_filebrowser_title)
if (pos >= 0) { .setView(customView)
final String query = getResources().getStringArray(R.array.dfu_app_file_browser_action)[pos]; .setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss())
final Intent storeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(query)); .setPositiveButton(R.string.yes, (dialog, which) -> {
startActivity(storeIntent); final int pos = appsList.getCheckedItemPosition();
} if (pos >= 0) {
}).show(); 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();
} }
} }
@@ -499,17 +492,18 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_CANCELED)
Uri uri = data != null ? data.getData() : null;
if (resultCode == Activity.RESULT_CANCELED || uri == null)
return; return;
switch (requestCode) { switch (requestCode) {
case SELECT_FILE_REQ: { case SELECT_FILE_REQ: {
// clear previous data
final Uri uri = data.getData();
/* /*
* The URI returned from application may be in 'file' or 'content' schema. * 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. * 'File' schema allows us to create a File object and read details from if directly.
* Data from 'Content' schema must be read with use of a Content Provider. To do that we are using a Loader. * Data from 'Content' schema must be read with use of a Content Provider.
* To do that we are using a Loader.
*/ */
if (uri.getScheme().equals("file")) { if (uri.getScheme().equals("file")) {
// The direct path to the file has been returned // The direct path to the file has been returned
@@ -538,6 +532,19 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
} }
break; break;
} }
case REQUEST_SAVE: {
try {
final OutputStream stream = getContentResolver().openOutputStream(uri);
final OutputStreamWriter writer = new OutputStreamWriter(stream);
writer.append(databaseHelper.getConfiguration(configurationSpinner.getSelectedItemId()));
writer.close();
Toast.makeText(this, R.string.uart_configuration_export_succeeded, Toast.LENGTH_SHORT).show();
} catch (final Exception e) {
Log.e(TAG, "Error while exporting server configuration", e);
Toast.makeText(this, R.string.uart_configuration_save_error, Toast.LENGTH_SHORT).show();
}
break;
}
} }
} }
@@ -694,7 +701,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
* Loads the configuration from the given input stream. * Loads the configuration from the given input stream.
* @param is the input stream * @param is the input stream
*/ */
private void loadConfiguration(final InputStream is) { private void loadConfiguration(@NonNull final InputStream is) {
try { try {
final BufferedReader reader = new BufferedReader(new InputStreamReader(is)); final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
@@ -727,40 +734,62 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
else else
message = "Unknown error"; message = "Unknown error";
final String msg = message; final String msg = message;
Snackbar.make(container, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show(); Snackbar.make(container, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.uart_action_details, v ->
new AlertDialog.Builder(UARTActivity.this)
.setMessage(msg)
.setTitle(R.string.uart_action_details)
.setPositiveButton(R.string.ok, null)
.show())
.show();
} }
} }
private void exportConfiguration() { private void exportConfiguration() {
// TODO this may not work if the SD card is not available. (Lenovo A806, email from 11.03.2015)
final File folder = new File(Environment.getExternalStorageDirectory(), FileHelper.NORDIC_FOLDER);
if (!folder.exists())
folder.mkdir();
final File serverFolder = new File(folder, FileHelper.UART_FOLDER);
if (!serverFolder.exists())
serverFolder.mkdir();
final String fileName = configuration.getName() + ".xml"; final String fileName = configuration.getName() + ".xml";
final File file = new File(serverFolder, fileName);
try {
file.createNewFile();
final FileOutputStream fos = new FileOutputStream(file);
final OutputStreamWriter writer = new OutputStreamWriter(fos);
writer.append(databaseHelper.getConfiguration(configurationSpinner.getSelectedItemId()));
writer.close();
// Notify user about the file if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final Intent intent = new Intent(Intent.ACTION_VIEW); final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.setDataAndType(FileHelper.getContentUri(this, file), "text/xml"); intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setType("text/xml");
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 420, intent, 0); intent.putExtra(Intent.EXTRA_TITLE, fileName);
final Notification notification = new NotificationCompat.Builder(this, ToolboxApplication.FILE_SAVED_CHANNEL).setContentIntent(pendingIntent).setContentTitle(fileName).setContentText(getText(R.string.uart_configuration_export_succeeded)) startActivityForResult(intent, REQUEST_SAVE);
.setAutoCancel(true).setShowWhen(true).setTicker(getText(R.string.uart_configuration_export_succeeded_ticker)).setSmallIcon(android.R.drawable.stat_notify_sdcard).build(); } else {
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); final File folder = new File(Environment.getExternalStorageDirectory(), FileHelper.NORDIC_FOLDER);
nm.notify(fileName, 823, notification); if (!folder.exists())
} catch (final Exception e) { folder.mkdir();
Log.e(TAG, "Error while exporting configuration", e); final File serverFolder = new File(folder, FileHelper.UART_FOLDER);
Toast.makeText(this, R.string.uart_configuration_save_error, Toast.LENGTH_SHORT).show(); if (!serverFolder.exists())
serverFolder.mkdir();
final File file = new File(serverFolder, fileName);
try {
file.createNewFile();
final FileOutputStream fos = new FileOutputStream(file);
final OutputStreamWriter writer = new OutputStreamWriter(fos);
writer.append(databaseHelper.getConfiguration(configurationSpinner.getSelectedItemId()));
writer.close();
// Notify user about the file
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(FileHelper.getContentUri(this, file), "text/xml");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 420, intent, 0);
final Notification notification = new NotificationCompat.Builder(this, ToolboxApplication.FILE_SAVED_CHANNEL)
.setContentIntent(pendingIntent)
.setContentTitle(fileName)
.setContentText(getText(R.string.uart_configuration_export_succeeded))
.setAutoCancel(true)
.setShowWhen(true)
.setTicker(getText(R.string.uart_configuration_export_succeeded_ticker))
.setSmallIcon(android.R.drawable.stat_notify_sdcard)
.build();
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(fileName, 823, notification);
} catch (final Exception e) {
Log.e(TAG, "Error while exporting configuration", e);
Toast.makeText(this, R.string.uart_configuration_save_error, Toast.LENGTH_SHORT).show();
}
} }
} }
@@ -768,7 +797,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
* Converts the old configuration, stored in preferences, into the first XML configuration and saves it to the database. * Converts the old configuration, stored in preferences, into the first XML configuration and saves it to the database.
* If there is already any configuration in the database this method does nothing. * If there is already any configuration in the database this method does nothing.
*/ */
private void ensureFirstConfiguration(final DatabaseHelper databaseHelper) { private void ensureFirstConfiguration(@NonNull final DatabaseHelper databaseHelper) {
// This method ensures that the "old", single configuration has been saved to the database. // This method ensures that the "old", single configuration has been saved to the database.
if (databaseHelper.getConfigurationsCount() == 0) { if (databaseHelper.getConfigurationsCount() == 0) {
final UartConfiguration configuration = new UartConfiguration(); final UartConfiguration configuration = new UartConfiguration();
@@ -807,16 +836,16 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
*/ */
private class CommentVisitor implements Visitor { private class CommentVisitor implements Visitor {
@Override @Override
public void read(final Type type, final NodeMap<InputNode> node) throws Exception { public void read(final Type type, final NodeMap<InputNode> node) {
// do nothing // do nothing
} }
@Override @Override
public void write(final Type type, final NodeMap<OutputNode> node) throws Exception { public void write(final Type type, final NodeMap<OutputNode> node) {
if (type.getType().equals(Command[].class)) { if (type.getType().equals(Command[].class)) {
OutputNode element = node.getNode(); final OutputNode element = node.getNode();
StringBuilder builder = new StringBuilder("A configuration must have 9 commands, one for each button.\n Possible icons are:"); final StringBuilder builder = new StringBuilder("A configuration must have 9 commands, one for each button.\n Possible icons are:");
for (Command.Icon icon : Command.Icon.values()) for (Command.Icon icon : Command.Icon.values())
builder.append("\n - ").append(icon.toString()); builder.append("\n - ").append(icon.toString());
element.setComment(builder.toString()); element.setComment(builder.toString());

View File

@@ -24,209 +24,31 @@ package no.nordicsemi.android.nrftoolbox.utility;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.widget.Toast;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import no.nordicsemi.android.nrftoolbox.R; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class FileHelper { public class FileHelper {
private static final String TAG = "FileHelper";
private static final String PREFS_SAMPLES_VERSION = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_SAMPLES_VERSION";
private static final int CURRENT_SAMPLES_VERSION = 4;
public static final String NORDIC_FOLDER = "Nordic Semiconductor"; public static final String NORDIC_FOLDER = "Nordic Semiconductor";
public static final String UART_FOLDER = "UART Configurations"; public static final String UART_FOLDER = "UART Configurations";
public static final String BOARD_FOLDER = "Board";
public static final String BOARD_NRF6310_FOLDER = "nrf6310";
public static final String BOARD_PCA10028_FOLDER = "pca10028";
public static final String BOARD_PCA10036_FOLDER = "pca10036";
public static boolean newSamplesAvailable(final Context context) { @Nullable
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); public static Uri getContentUri(@NonNull final Context context, @NonNull final File file) {
final int version = preferences.getInt(PREFS_SAMPLES_VERSION, 0);
return version < CURRENT_SAMPLES_VERSION;
}
public static void createSamples(final Context context) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
final int version = preferences.getInt(PREFS_SAMPLES_VERSION, 0);
if (version == CURRENT_SAMPLES_VERSION)
return;
/*
* Copy example HEX files to the external storage. Files will be copied if the DFU Applications folder is missing
*/
final File root = new File(Environment.getExternalStorageDirectory(), "Nordic Semiconductor");
if (!root.exists()) {
root.mkdir();
}
final File board = new File(root, "Board");
if (!board.exists()) {
board.mkdir();
}
final File nrf6310 = new File(board, "nrf6310");
if (!nrf6310.exists()) {
nrf6310.mkdir();
}
final File pca10028 = new File(board, "pca10028");
if (!pca10028.exists()) {
pca10028.mkdir();
}
// Remove old files. Those will be moved to a new folder structure
new File(root, "ble_app_hrs_s110_v6_0_0.hex").delete();
new File(root, "ble_app_rscs_s110_v6_0_0.hex").delete();
new File(root, "ble_app_hrs_s110_v7_0_0.hex").delete();
new File(root, "ble_app_rscs_s110_v7_0_0.hex").delete();
new File(root, "blinky_arm_s110_v7_0_0.hex").delete();
new File(root, "dfu_2_0.bat").delete(); // This file has been migrated to 3.0
new File(root, "dfu_3_0.bat").delete(); // This file has been migrated to 3.1
new File(root, "dfu_2_0.sh").delete(); // This file has been migrated to 3.0
new File(root, "dfu_3_0.sh").delete(); // This file has been migrated to 3.1
new File(root, "README.txt").delete(); // This file has been modified to match v.3.0+
boolean oldCopied = false;
boolean newCopied = false;
// nrf6310 files
File f = new File(nrf6310, "ble_app_hrs_s110_v6_0_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_s110_v6_0_0, f);
oldCopied = true;
}
f = new File(nrf6310, "ble_app_rscs_s110_v6_0_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_rscs_s110_v6_0_0, f);
oldCopied = true;
}
f = new File(nrf6310, "ble_app_hrs_s110_v7_0_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_s110_v7_0_0, f);
oldCopied = true;
}
f = new File(nrf6310, "ble_app_rscs_s110_v7_0_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_rscs_s110_v7_0_0, f);
oldCopied = true;
}
f = new File(nrf6310, "blinky_arm_s110_v7_0_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.blinky_arm_s110_v7_0_0, f);
oldCopied = true;
}
// PCA10028 files
f = new File(pca10028, "blinky_s110_v7_1_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.blinky_s110_v7_1_0, f);
oldCopied = true;
}
f = new File(pca10028, "blinky_s110_v7_1_0_ext_init.dat");
if (!f.exists()) {
copyRawResource(context, R.raw.blinky_s110_v7_1_0_ext_init, f);
oldCopied = true;
}
f = new File(pca10028, "ble_app_hrs_dfu_s110_v7_1_0.hex");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_dfu_s110_v7_1_0, f);
oldCopied = true;
}
f = new File(pca10028, "ble_app_hrs_dfu_s110_v7_1_0_ext_init.dat");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_dfu_s110_v7_1_0_ext_init, f);
oldCopied = true;
}
new File(root, "ble_app_hrs_dfu_s110_v8_0_0.zip").delete(); // name changed
f = new File(pca10028, "ble_app_hrs_dfu_s110_v8_0_0_sdk_v8_0.zip");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_dfu_s110_v8_0_0_sdk_v8_0, f);
newCopied = true;
}
f = new File(pca10028, "ble_app_hrs_dfu_s110_v8_0_0_sdk_v9_0.zip");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_dfu_s110_v8_0_0_sdk_v9_0, f);
newCopied = true;
}
f = new File(pca10028, "ble_app_hrs_dfu_all_in_one_sdk_v9_0.zip");
if (!f.exists()) {
copyRawResource(context, R.raw.ble_app_hrs_dfu_all_in_one_sdk_v9_0, f);
newCopied = true;
}
if (oldCopied)
Toast.makeText(context, R.string.dfu_example_files_created, Toast.LENGTH_SHORT).show();
else if (newCopied)
Toast.makeText(context, R.string.dfu_example_new_files_created, Toast.LENGTH_SHORT).show();
// Scripts
newCopied = false;
f = new File(root, "dfu_3_1.bat");
if (!f.exists()) {
copyRawResource(context, R.raw.dfu_win_3_1, f);
newCopied = true;
}
f = new File(root, "dfu_3_1.sh");
if (!f.exists()) {
copyRawResource(context, R.raw.dfu_mac_3_1, f);
newCopied = true;
}
f = new File(root, "README.txt");
if (!f.exists()) {
copyRawResource(context, R.raw.readme, f);
}
if (newCopied)
Toast.makeText(context, R.string.dfu_scripts_created, Toast.LENGTH_SHORT).show();
// Save the current version
preferences.edit().putInt(PREFS_SAMPLES_VERSION, CURRENT_SAMPLES_VERSION).apply();
}
/**
* Copies the file from res/raw with given id to given destination file. If dest does not exist it will be created.
*
* @param context activity context
* @param rawResId the resource id
* @param dest destination file
*/
private static void copyRawResource(final Context context, final int rawResId, final File dest) {
try {
final InputStream is = context.getResources().openRawResource(rawResId);
final FileOutputStream fos = new FileOutputStream(dest);
final byte[] buf = new byte[1024];
int read;
try {
while ((read = is.read(buf)) > 0)
fos.write(buf, 0, read);
} finally {
is.close();
fos.close();
}
} catch (final IOException e) {
DebugLogger.e(TAG, "Error while copying HEX file " + e.toString());
}
}
public static Uri getContentUri(final Context context, final File file) {
final String filePath = file.getAbsolutePath(); final String filePath = file.getAbsolutePath();
final Uri uri = MediaStore.Files.getContentUri("external"); final Uri uri = MediaStore.Files.getContentUri("external");
final Cursor cursor = context.getContentResolver().query( try (final Cursor cursor = context.getContentResolver().query(
uri, uri,
new String[]{BaseColumns._ID}, new String[] { BaseColumns._ID },
MediaStore.Files.FileColumns.DATA + "=? ", MediaStore.Files.FileColumns.DATA + "=? ",
new String[]{filePath}, null); new String[] { filePath },
try { null)) {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
final int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID)); final int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(uri, String.valueOf(id)); return Uri.withAppendedPath(uri, String.valueOf(id));
@@ -239,8 +61,6 @@ public class FileHelper {
return null; return null;
} }
} }
} finally {
cursor.close();
} }
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +0,0 @@
:020000040001F9
:1060000068300020E96101000362010005620100BF
:106010000000000000000000000000000000000080
:106020000000000000000000000000000762010006
:106030000000000000000000096201000B62010086
:106040000D6201000D6201000D6201000D62010090
:106050000D620100000000000D6201000D620100F0
:106060000D6201000D6201000D6201000D62010070
:106070000D6201000D6201000D6201000D62010060
:106080000D6201000D6201000D6201000D62010050
:106090000D6201000D6201000D6201000D62010040
:1060A0000D6201000D620100000000000000000010
:1060B00000000000000000000000000000000000E0
:1060C00000F002F800F031F80CA030C808382418AD
:1060D0002D18A246671EAB4654465D46AC4201D120
:1060E00000F023F87E460F3E0FCCB6460126334221
:1060F00000D0FB1AA246AB4633431847900200007B
:10610000A0020000103A02D378C878C1FAD852072A
:1061100001D330C830C101D504680C6070471FB589
:10612000C046C0461FBD10B510BD00F0FEF81146B8
:10613000FFF7F5FF00F018F800F016F903B4FFF7C9
:10614000F2FF03BC00F01AF9401E00BF00BF00BF01
:1061500000BF00BF00BF00BF00BF00BF00BF00BF47
:1061600000BFF1D170470000082000F019F80920A5
:1061700000F016F813E0082000F020F8092000F0E5
:1061800018F8FF20F53000F021F8092000F016F88B
:10619000082000F00EF8FF20F53000F017F8EAE7CD
:1061A00003210522120707231B02D2188300D150B6
:1061B000704701218140044A91607047012181406C
:1061C000014AD160704700000005005001B505E0AC
:1061D0000098401E00900348FFF7B6FF0098002883
:1061E000F6D108BDE703000003210C4802680A430A
:1061F00002600B4802680A4302600A4880470A4866
:106200000047FEE7FEE7FEE7FEE7FEE7FEE70000E9
:1062100006480749074A084B70470000240500401C
:1062200054050040E1620100C160010068200020C7
:106230006830002068280020682800203248334950
:10624000086070473248008CC0B2012812D1304833
:10625000808C0007000F00280CD12D48806AF021A7
:106260000840402806D12A48C06A0840002801D1C9
:10627000012070470020FCE72548008CC0B20128AF
:106280002CD12348808C0007000F002826D12048FD
:10629000806AF0210840002806D11D48C06A0840E5
:1062A000002801D1012070471948806AF021084078
:1062B000102806D11648C06A0840002801D10120E4
:1062C000F1E71348806AF0210840302806D11048D1
:1062D000C06A0840002801D10120E4E70020E2E77D
:1062E00010B5FFF7C9FF002805D00A480A494860E1
:1062F000C8130A498861FFF7A5FF002802D00120D2
:106300000749886010BD00000024F4000020002030
:10631000C00F00F0DFFF07C000050040006C004028
:1063200000060040704770477047754600F022F83D
:10633000AE46050069465346C008C000854618B001
:1063400020B5FFF765FF60BC00274908B646002668
:10635000C0C5C0C5C0C5C0C5C0C5C0C5C0C5C0C515
:10636000403D49008D4670470446C046C046204621
:10637000FFF7E4FE00487047042000200149182080
:10638000ABBEFEE726000200704700009C630100E0
:106390000020002004000000046101000024F4003B
:04000005000160C1D5
:00000001FF

View File

@@ -1,46 +0,0 @@
:020000040001F9
:1060000008280020F56001000F6101001161010006
:106010000000000000000000000000000000000080
:1060200000000000000000000000000013610100FB
:106030000000000000000000156101001761010070
:106040001961010019610100196101001961010064
:1060500019610100000000001961010019610100CF
:106060001961010019610100196101001961010044
:106070001961010019610100196101001961010034
:106080001961010019610100196101001961010024
:106090001961010019610100196101001961010014
:1060A00019610100196101000000000000000000FA
:1060B00000000000000000000000000000000000E0
:1060C0000348854600F032F8004800470D620100A1
:1060D00008280020401E00BF00BF00BF00BF00BF57
:1060E00000BF00BF00BF00BF00BF00BF00BFF1D1B5
:1060F000704700000321094802680A43026008480B
:1061000002680A4302600748804707480047FEE7E5
:10611000FEE7FEE7FEE7FEE7FEE70000240500409D
:106120005405004051610100C1600100064C012589
:10613000064E05E0E36807CC2B430C3C984710342F
:10614000B442F7D3FFF7C0FF80620100A0620100F4
:1061500010B500F037F8002805D00E490C4848600B
:10616000C8130D4988610D48018CC9B201290ED1AF
:10617000818C09070BD1018D0906090F042906D16D
:10618000808D0006000F02D105490120886010BDF6
:10619000DFFF07C000050040006C0040C00F00F0AA
:1061A0000006004002E008C8121F08C1002AFAD108
:1061B00070477047002001E001C1121F002AFBD187
:1061C000704700001048018CC9B2012917D1818C99
:1061D000090714D1018D09060A0F03D1828D120619
:1061E000120F0ED0090F012903D1828D1206120F52
:1061F00007D0032903D1808D0006000F01D00020B5
:106200007047012070470000C00F00F000200321FC
:10621000104A01252B468340DB011B0F02D083006F
:106220009B181960401C2028F4D30B4E0B4F002400
:106230007268395D2846884001469043B06011403D
:10624000F160FF20F53000F00BF8641C042CEFDB4C
:10625000EDE7000000070050000500507C620100DF
:1062600031B5054C04E0401E00902046FFF732FF98
:1062700000980028F7D138BDE7030000151617185D
:10628000A06201000020002004000000A4610100C1
:10629000A46201000420002004080000B461010091
:0462A0000024F400E2
:04000005000160C1D5
:00000001FF

View File

@@ -1,205 +0,0 @@
#!/bin/sh
# Copyright (c) 2015, Nordic Semiconductor
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Description:
# ------------
# The script allows to perform DFU operation from the computer using Android device as a dongle.
# The script may be run on Linux or Mac.
#
# Requirements:
# -------------
# 1. Android device with Android version 4.3+ connected by USB cable with the PC
# 2. The path to Android platform-tools directory must be added to %PATH% environment variable
# 3. nRF Toolbox (1.11.0+) or nRF Connect (2.1.0+) (formerly known as nRF Master Control Panel) application installed on the Android device
# 4. "Developer options" and "USB debugging" must be enabled on the Android device
#
# Usage:
# ------
# 1. Open command line
# 2. Type "sh dfu.sh -?" and press ENTER
#
# Android Debug Bridge (adb):
# ---------------------------
# You must have Android platform tools installed on the computer or the path to the adb application set in the PATH.
# Go to http://developer.android.com/sdk/index.html for more information how to install it on the computer.
# You do not need the whole ADT Bundle (with Eclipse or Android Studio). Only SDK Tools with Platform Tools are required.
# ==================================================================================
PROGRAM=$0
DEVICE=""
S_DEVICE=""
ADDRESS=""
HEX_FILE=""
HEX_PATH=""
NAME="DfuTarg"
INIT_FILE=""
INIT_PATH=""
E_INIT_FILE=""
TYPE=0
# Modify this in order to keep the bond information after application upgrade
KEEP_BOND=false
# ==================================================================================
# Common methods
intro() {
echo "===================================="
echo "Nordic Semiconductor DFU bash script"
echo "===================================="
}
error() {
exit 1
}
quit() {
exit 0
}
usage() {
echo "Usage: $PROGRAM [options] hex-file"
echo "Options:"
echo " -d device serial number. Use \"adb devices\" to get list of serial numbers"
echo " -a target device address in XX:XX:XX:XX:XX:XX format"
echo " -n name optional device name"
echo " -t firmware_type 1=Soft Device, 2=Bootloader, 4=Application, 0 (default)=Auto or all from ZIP"
echo " -i init the init packet *.dat file"
}
# ==================================================================================
# Write intro
intro
# ==================================================================================
# Check ADB
adb devices > /dev/null 2>&1
if [ ! "$?" = "0" ] ; then
echo "Error: adb is not recognized as an external command."
echo " Add [Android Bundle path]\\\android-sdk-macosx\\\platform-tools" to \$PATH
error
fi
# ==================================================================================
# Parse options
while getopts ":d:a:n:t:i:" VALUE "$@"
do
case $VALUE in
d )
DEVICE="$OPTARG"
S_DEVICE="-s $OPTARG"
;;
a ) ADDRESS="$OPTARG" ;;
n ) NAME="$OPTARG" ;;
t ) TYPE=$OPTARG ;;
i )
INIT_PATH="$OPTARG"
INIT_FILE=$(basename $INIT_PATH)
E_INIT_FILE="-e no.nordicsemi.android.dfu.extra.EXTRA_INIT_FILE_PATH \"/sdcard/Nordic Semiconductor/Upload/$INIT_FILE\""
;;
: ) echo "Error: Option -$OPTARG must have a string value.\n"
usage
error
;;
? ) usage
quit
;;
esac
done
shift $((OPTIND - 1))
# Get the HEX file name or write an error
if [ "$1" = "" ] ; then
echo "Error: HEX file name not specified.\n"
usage
error
else
HEX_PATH=$1
HEX_FILE=$(basename $HEX_PATH)
fi
# ==================================================================================
if [ "$DEVICE" = "" ] ; then
# Check if there is only one device connected
C=$(adb devices | grep -e "device" -e "unauthorized" -e "emulator" | grep -c -v "devices")
if [ "$C" = "0" ] ; then
echo "Error: No device connected.";
error
fi
if [ ! "$C" = "1" ] ; then
echo "Error: More than one device connected."
echo " Specify the device serial number using -d option:"
adb devices
usage
error
fi
else
# Check if specified device is connected
C=$(adb devices | grep -c "$DEVICE")
if [ "$C" = "0" ] ; then
echo "Error: Device with serial number \"$DEVICE\" is not connected."
adb devices
error
fi
fi
# ==================================================================================
# Copy selected file onto the device
printf "Copying \"$HEX_FILE\" to /sdcard/Nordic Semiconductor/Upload/..."
adb push $S_DEVICE $HEX_PATH "/sdcard/Nordic Semiconductor/Upload/$HEX_FILE" > /dev/null 2>&1
if [ "#?" = "1" ] ; then
echo "FAIL"
echo "Error: Device not found."
error
else
echo "OK"
fi
if [ ! "$INIT_FILE" = "" ] ; then
printf "Copying \"$INIT_FILE\" to /sdcard/Nordic Semiconductor/Upload/..."
adb push $S_DEVICE $INIT_PATH "/sdcard/Nordic Semiconductor/Upload/$INIT_FILE" > /dev/null 2>&1
if [ "#?" = "1" ] ; then
echo "FAIL"
echo "Error: Device not found."
error
else
echo "OK"
fi
fi
if [ "$ADDRESS" = "" ] ; then
# Start DFU Initiator activity if no target device specified
printf "Starting DFU Initiator activity..."
adb $S_DEVICE shell am start -a no.nordicsemi.android.action.DFU_UPLOAD --ei no.nordicsemi.android.dfu.extra.EXTRA_FILE_TYPE $TYPE --ez no.nordicsemi.android.dfu.extra.EXTRA_KEEP_BOND $KEEP_BOND -e no.nordicsemi.android.dfu.extra.EXTRA_FILE_PATH "/sdcard/Nordic Semiconductor/Upload/$HEX_FILE" $E_INIT_FILE | grep "Error" > /dev/null 2>&1
else
# Start the DFU service directly
printf "Starting DFU service..."
adb $S_DEVICE shell am startservice -n no.nordicsemi.android.nrftoolbox/.dfu.DfuService -a no.nordicsemi.android.action.DFU_UPLOAD --ei no.nordicsemi.android.dfu.extra.EXTRA_FILE_TYPE --ez no.nordicsemi.android.dfu.extra.EXTRA_KEEP_BOND $KEEP_BOND -e no.nordicsemi.android.dfu.extra.EXTRA_DEVICE_ADDRESS $ADDRESS -e no.nordicsemi.android.dfu.extra.EXTRA_DEVICE_NAME $NAME -e no.nordicsemi.android.dfu.extra.EXTRA_FILE_PATH "/sdcard/Nordic Semiconductor/Upload/$HEX_FILE" $E_INIT_FILE | grep "Error" > /dev/null 2>&1
fi
if [ "$?" = "0" ] ; then
echo "FAIL"
echo "Error: Required application not installed."
error
else
echo "OK"
echo "Select DFU target on your Android device to start upload."
fi

View File

@@ -1,253 +0,0 @@
@echo off
rem Copyright (c) 2015, Nordic Semiconductor
rem All rights reserved.
rem
rem Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
rem
rem 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
rem
rem 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
rem documentation and/or other materials provided with the distribution.
rem
rem 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
rem software without specific prior written permission.
rem
rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
rem HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
rem ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
rem USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rem
rem Description:
rem ------------
rem The script allows to perform DFU operation from the computer using Android device as a dongle.
rem The script may be run on Windows.
rem
rem Requirements:
rem -------------
rem 1. Android device with Android version 4.3+ connected by USB cable with the PC
rem 2. The path to Android platform-tools directory must be added to %PATH% environment variable, f.e: C:\Program Files\Android ADT Bundle\sdk\platform-tools
rem 3. nRF Toolbox (1.6.0+) or nRF Connect (1.8.0+) (formerly known as nRF Master Control Panel) application installed on the Android device
rem 4. "Developer options" and "USB debugging" must be enabled on the Android device
rem
rem Usage:
rem ------
rem 1. Open command line
rem 2. Type "dfu -?" and press ENTER
rem
rem Android Debug Bridge (adb):
rem ---------------------------
rem You must have Android platform tools installed on the computer or the files: adb.exe, AdbWinApi.dll copied to the same directory.
rem Go to http://developer.android.com/sdk/index.html for more information how to install it on the computer.
rem You do not need the whole ADT Bundle (with Eclipse or Android Studio). Only SDK Tools with Platform Tools are required.
rem
rem ==================================================================================
setlocal
set PROGRAM=%~0
set DEVICE=
set S_DEVICE=
set ADDRESS=
set NAME="DfuTarg"
set INIT_FILE=
set INIT_PATH=
set E_INIT_FILE=
set TYPE=0
rem Modify this in order to keep the bond information
set KEEP_BOND=false
rem ==================================================================================
rem Check ADB
call adb devices > nul 2>&1
if errorLevel 1 (
call :info
echo Error: adb is not recognized as an external command.
echo Add [Android Bundle path]/sdk/platform-tools to %%PATH%%
goto error
)
rem ==================================================================================
rem Check help
if "%~1"=="" goto usage
if "%~1"=="-?" goto usage
if "%~1"=="/?" goto usage
rem ==================================================================================
rem Read the target device id
if /I "%~1"=="-d" set TARGET_DEVICE_SET=1
if defined TARGET_DEVICE_SET (
if not "%~1"=="" (
set DEVICE=%~2
set S_DEVICE=-s %~2
shift
shift
) else goto usage
)
rem Read the optional device BLE address. If the address has not been provided user may select the device on the phone/tablet
if /I "%~1"=="-a" set ADDRESS_SET=1
if defined ADDRESS_SET (
if not "%~1"=="" (
set ADDRESS=%~2
shift
shift
) else goto usage
)
rem Read the optional device name. The default name is DfuTarg
if /I "%~1"=="-n" set NAME_SET=1
if defined NAME_SET (
if not "%~1"=="" (
set NAME="%~2"
shift
shift
) else goto usage
)
rem Read the optional firmware type.
if /I "%~1"=="-t" set TYPE_SET=1
if defined TYPE_SET (
if not "%~1"=="" (
set TYPE=%~2
shift
shift
) else goto usage
)
rem Read the optional init file name.
if /I "%~1"=="-i" set INIT_SET=1
if defined INIT_SET (
if not "%~1"=="" (
set INIT_FILE=%~nx2
set INIT_PATH="%~f2"
set E_INIT_FILE=-e no.nordicsemi.android.dfu.extra.EXTRA_INIT_FILE_PATH "/sdcard/Nordic Semiconductor/Upload/%~nx2"
shift
shift
) else goto usage
)
rem If there are some other modifiers, show usage
set OPTION="%~1"
if not defined TARGET_DEVICE_SET (
rem If there is another option -x which is not supported, show usage
if %OPTION:-=% neq %OPTION% goto usage
)
rem ==================================================================================
rem Write intro
call :info
rem Read file name and fully qualified path name to the HEX file
if "%~1"=="" (
echo Error: HEX file name not specified.
goto error
)
set HEX_FILE=%~nx1
set HEX_PATH="%~f1"
if not exist %HEX_PATH% (
echo Error: The given file has not been found.
goto error
)
rem ==================================================================================
if "%DEVICE%"=="" (
rem Check if there is only one device connected
for /f "delims=" %%a in ('call adb devices ^| findstr "device unauthorized emulator" ^| find /c /v "devices"') do (
if "%%a"=="0" (
echo Error: No device connected.
goto error
)
if not "%%a"=="1" (
echo Error: More than one device connected.
echo Specify the device serial number using -d option:
call adb devices
goto usage_only
goto error
)
)
) else (
rem Check if specified device is connected
for /f "delims=" %%a in ('call adb devices ^| find /c "%DEVICE%"') do (
if "%%a"=="0" (
echo Error: Device with serial number "%DEVICE%" is not connected.
call adb devices
goto error
)
)
)
rem ==================================================================================
rem Copy selected file onto the device
echo|set /p=Copying "%HEX_FILE%" to /sdcard/Nordic Semiconductor/Upload...
call adb %S_DEVICE% push %HEX_PATH% "/sdcard/Nordic Semiconductor/Upload/%HEX_FILE%" > nul 2>&1
if errorLevel 1 (
echo FAIL
echo Error: Device not found.
goto error
) else echo OK
if not "%INIT_FILE%"=="" (
echo Copying "%INIT_FILE%" to /sdcard/Nordic Semiconductor/Upload...OK
call adb %S_DEVICE% push %INIT_PATH% "/sdcard/Nordic Semiconductor/Upload/%INIT_FILE%" > nul 2>&1
)
if "%ADDRESS%"=="" (
rem Start DFU Initiator activity if no target device specified
echo|set /p=Starting DFU Initiator activity...
call adb %S_DEVICE% shell am start -a no.nordicsemi.android.action.DFU_UPLOAD^
--ei no.nordicsemi.android.dfu.extra.EXTRA_FILE_TYPE %TYPE%^
--ez no.nordicsemi.android.dfu.extra.EXTRA_KEEP_BOND %KEEP_BOND%^
-e no.nordicsemi.android.dfu.extra.EXTRA_FILE_PATH "/sdcard/Nordic Semiconductor/Upload/%HEX_FILE%" %E_INIT_FILE% | find "Error" > nul 2>&1
) else (
rem Start DFU service on the device
echo|set /p=Starting DFU service...
call adb %S_DEVICE% shell am startservice -n no.nordicsemi.android.nrftoolbox/.dfu.DfuService -a no.nordicsemi.android.action.DFU_UPLOAD^
-e no.nordicsemi.android.dfu.extra.EXTRA_DEVICE_ADDRESS %ADDRESS%^
-e no.nordicsemi.android.dfu.extra.EXTRA_DEVICE_NAME %NAME%^
--ei no.nordicsemi.android.dfu.extra.EXTRA_FILE_TYPE %TYPE%^
--ez no.nordicsemi.android.dfu.extra.EXTRA_KEEP_BOND %KEEP_BOND%^
-e no.nordicsemi.android.dfu.extra.EXTRA_FILE_PATH "/sdcard/Nordic Semiconductor/Upload/%HEX_FILE%" %E_INIT_FILE% | find "Error" > nul 2>&1
)
if %errorLevel%==0 (
echo FAIL
echo Error: Required application not installed.
goto error
) else (
echo OK
echo Select DFU target on your Android device to start upload.
)
goto exit
rem ==================================================================================
:info
echo =====================================
echo Nordic Semiconductor DFU batch script
echo =====================================
goto eof
rem ==================================================================================
:usage
call :info
:usage_only
echo Usage:
echo %PROGRAM% [-D device_id] [-A address] [-N name] [-t firmware_type] [-I init_file.dat] application.hex
echo Info:
echo device_id - Call: "adb devices" to get list of serial numbers
echo address - The target DFU-supported device address in XX:XX:XX:XX:XX:XX format
echo name - The optional device name (will be shown on the phone)
echo firmware_type - 1=Soft Device, 2=Bootloader, 4=Application, 0=Auto (Application or all from ZIP)
echo init_file - The binary file with the Init Packet
goto exit
rem ==================================================================================
:error
set errorLevel=1
rem ==================================================================================
:exit
endlocal
:eof

View File

@@ -1,58 +0,0 @@
-----------------------
R E A D M E
-----------------------
The README file contains information about the following files:
(1) dfu_3_0.bat
(2) dfu_3_0.sh
------------------------
Over-the-air DFU
------------------------
Over-the-air DFU represents a highly desirable feature requirement for today's wireless products.
DFU allows for application bugs to be fixed in the field via updates in a completely transparent
way for the consumer. This brings a large degree of security to product makers safe in the knowledge
any software fixes or indeed new feature introductions can be completed automatically via cellphone
updates that do not require any user interaction.
Nordic's unique software architecture that cleanly separates Application code from protocol stack
plays an important role in how the OTA DFU operates. The protocol stack together with a boot loader
can handle the transportation and verification of a new application firmware update. In competing
systems where application code and protocol stack are compiled as a single entity, the only way to
do this is to reserve enough spare memory to cover both the protocol stack and the application.
This can represent an unacceptable memory resource requirement as the SoC needs to facilitate this
'scratch pad' memory space which is redundant when not in use during an update.
Read more about DFU on http://www.nordicsemi.com
DFU documentation: http://developer.nordicsemi.com/nRF51_SDK/doc/7.1.0/s110/html/a00062.html
-------------------------
Files
-------------------------
1. DFU_3_0.BAT
The dfu_*.bat script allows a developer to upload HEX, BIN or ZIP files directly from the PC to a Dfu Target
without use of a BLE dongle connected to the computer. It transfers file onto the Android
device and starts service that sends the application, soft device or a bootloader Over-the-Air onto the peripheral.
The peripheral must be programmed with DFU bootloader. Since the DFU_3_0 the buttonless update is also supported.
Execute dfu -? in the command line for usage.
Android 4.3+ device with nRF Toolbox (1.11.0+) or nRF Connect (2.1.0+) (formerly known as nRF Master Control Panel) is required.
The script runs on Windows OS.
2. DFU_3_0.SH
Similar script for Linux, Mac or Cygwin. Uses sh shell.
-------------------------
Change log
-------------------------
2.0 - This version contains minor changes to match the modified action names.
3.0 - Option to send the init packet and firmware type
-------------------------
Development kit
-------------------------
Go to http://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822-Development-Kit for more
information about the Development Kit.

View File

@@ -23,8 +23,6 @@
<resources> <resources>
<string name="app_name">nRF Toolbox</string> <string name="app_name">nRF Toolbox</string>
<string name="font_path">fonts/trebucbd.ttf</string>
<string name="normal_font_path">fonts/trebuc.ttf</string>
<string name="shortcut_dfu_short">DFU</string> <string name="shortcut_dfu_short">DFU</string>
<string name="shortcut_dfu_long">Device Firmware Update</string> <string name="shortcut_dfu_long">Device Firmware Update</string>
@@ -70,8 +68,6 @@
<string name="log" formatted="false">%1$tR:%1$tS.%1$tL</string> <string name="log" formatted="false">%1$tR:%1$tS.%1$tL</string>
<string name="permission_title">Permission required</string>
<string name="permission_sd_text">nRF Toolbox would like to copy some sample applications, that may be uploaded onto your nRF51 device using the DFU (Device Firmware Update), to the memory of this device. If you agree, you will be asked to give the application permission to access files on your device.</string>
<string name="about_title">About</string> <string name="about_title">About</string>
<string name="about_version">\n\nVersion: %s</string> <string name="about_version">\n\nVersion: %s</string>
<string name="about_text">The nRF Toolbox is a container application that stores your Nordic Semiconductor apps in one location.</string> <string name="about_text">The nRF Toolbox is a container application that stores your Nordic Semiconductor apps in one location.</string>

View File

@@ -24,15 +24,11 @@
<string name="dfu_feature_title">DFU</string> <string name="dfu_feature_title">DFU</string>
<string name="dfu_service_title">nRF Toolbox DFU Proxy</string> <string name="dfu_service_title">nRF Toolbox DFU Proxy</string>
<string name="dfu_settings_title">DFU Settings</string> <string name="dfu_settings_title">DFU Settings</string>
<string name="dfu_lib_version">DFU Library version 1.9.0</string> <string name="dfu_lib_version">DFU Library version 1.9.1</string>
<string name="dfu_feature_title_long">DEVICE FIRMWARE UPDATE</string> <string name="dfu_feature_title_long">DEVICE FIRMWARE UPDATE</string>
<dimen name="dfu_feature_title_long_margin">-186dp</dimen> <dimen name="dfu_feature_title_long_margin">-186dp</dimen>
<string name="dfu_example_files_created">Example HEX files were copied to /sdcard/Nordic Semiconductor.</string>
<string name="dfu_example_new_files_created">New example HEX files were copied to /sdcard/Nordic Semiconductor.</string>
<string name="dfu_scripts_created">DFU script files were copied to /sdcard/Nordic Semiconductor.</string>
<string name="dfu_section_application_header">APPLICATION</string> <string name="dfu_section_application_header">APPLICATION</string>
<string name="dfu_file_name_label">File name:</string> <string name="dfu_file_name_label">File name:</string>
<string name="dfu_file_type_label">Type:</string> <string name="dfu_file_type_label">Type:</string>
@@ -105,7 +101,6 @@
<item>Application only</item> <item>Application only</item>
</string-array> </string-array>
<string name="dfu_unknown_name">unnamed device</string>
<string name="dfu_uploading_percentage_label">0%</string> <string name="dfu_uploading_percentage_label">0%</string>
<string name="dfu_uploading_percentage">%d%%</string> <string name="dfu_uploading_percentage">%d%%</string>
<string name="dfu_default_name">DEFAULT DFU</string> <string name="dfu_default_name">DEFAULT DFU</string>
@@ -127,8 +122,7 @@
\n\n<b>Backward compatibility</b> \n\n<b>Backward compatibility</b>
\nThe nRF Toolbox also supports all old file formats: HEX and BIN files, separate DAT files and ZIP files without a manifest file but with a fixed naming convention: \nThe nRF Toolbox also supports all old file formats: HEX and BIN files, separate DAT files and ZIP files without a manifest file but with a fixed naming convention:
</string> </string>
<string name="dfu_about_text">The Device Firmware Update (DFU) app allows you to update the firmware of your Bluetooth Smart device over-the-air (OTA). <string name="dfu_about_text">The Device Firmware Update (DFU) app allows you to update the firmware of your Bluetooth LE device over-the-air (OTA).
It is compatible with Nordic Semiconductor nRF51822 or nRF51422 devices with S110 SoftDevice and DFU bootloader enabled. With SoftDevice s110 7.0.0+, It is compatible with Nordic Semiconductor nRF5 devices with DFU bootloader enabled.
the SoftDevice itself and/or a bootloader may also be updated.
\n\nFor more information about the DFU, see the About DFU section in Settings.</string> \n\nFor more information about the DFU, see the About DFU section in Settings.</string>
</resources> </resources>

View File

@@ -53,7 +53,7 @@
<string name="uart_configuration_save_error">Export failed.</string> <string name="uart_configuration_save_error">Export failed.</string>
<string name="uart_configuration_load_error">Import failed.</string> <string name="uart_configuration_load_error">Import failed.</string>
<string name="uart_configuration_export_succeeded_ticker">File saved</string> <string name="uart_configuration_export_succeeded_ticker">File saved</string>
<string name="uart_configuration_export_succeeded">Configuration saved in /sdcard/Nordic Semiconductor</string> <string name="uart_configuration_export_succeeded">Configuration exported.</string>
<string name="uart_edit_title">Configure button</string> <string name="uart_edit_title">Configure button</string>
<string name="uart_edit_command_hint">Enter command</string> <string name="uart_edit_command_hint">Enter command</string>
@@ -68,7 +68,7 @@
<string name="uart_eol_lf">LF</string> <string name="uart_eol_lf">LF</string>
<string name="uart_eol_cr">CR</string> <string name="uart_eol_cr">CR</string>
<string name="uart_about_text">UART profile (Universal Asynchronous Receiver and Transmitter) is a Bluetooth Smart implementation of the UART standard. It allows for bidirectional <string name="uart_about_text">UART profile (Universal Asynchronous Receiver and Transmitter) is a Bluetooth LE implementation of the UART standard. It allows for bidirectional
text based communication that is often used for debugging and control. text based communication that is often used for debugging and control.
\nEach configuration contains 9 programmable buttons that may send commands to the UART TX characteristic. Click on the EDIT menu item to edit buttons actions. \nEach configuration contains 9 programmable buttons that may send commands to the UART TX characteristic. Click on the EDIT menu item to edit buttons actions.
\nScroll the main pane right, or rotate your device to the landscape orientation to see the oncoming and incoming data as well as other connection events.\n\nIf nRF Logger application \nScroll the main pane right, or rotate your device to the landscape orientation to see the oncoming and incoming data as well as other connection events.\n\nIf nRF Logger application