From f9f50262b5563f593e5ab8c3adb1613433e27645 Mon Sep 17 00:00:00 2001 From: Schoumi Date: Thu, 16 Jun 2016 13:05:18 +0200 Subject: [PATCH] Flash LPC management --- .../lpcprog/activity/DeviceActivity.java | 103 ++- .../lpcprog/adapters/BinariesAdapter.java | 289 ++++++++ .../lpcprog/listener/DownloadListener.java | 13 + .../lpcprog/listener/FlashListener.java | 8 + .../lpcprog/listener/NetworkListener.java | 5 - .../lpcprog/managers/DatabaseManager.java | 107 ++- .../mobdev/lpcprog/managers/IspManager.java | 676 ++++++++++++++---- .../lpcprog/managers/NetworkManager.java | 55 +- .../fr/mobdev/lpcprog/objects/Binary.java | 31 + .../java/fr/mobdev/lpcprog/objects/Parts.java | 16 + .../fr/mobdev/lpcprog/objects/Server.java | 9 +- app/src/main/res/drawable-hdpi/cancel.png | Bin 0 -> 931 bytes app/src/main/res/drawable-hdpi/chip.png | Bin 0 -> 1146 bytes app/src/main/res/drawable-hdpi/delete.png | Bin 0 -> 640 bytes app/src/main/res/drawable-hdpi/download.png | Bin 0 -> 749 bytes app/src/main/res/drawable-hdpi/stop.png | Bin 0 -> 402 bytes app/src/main/res/drawable-mdpi/cancel.png | Bin 0 -> 641 bytes app/src/main/res/drawable-mdpi/chip.png | Bin 0 -> 946 bytes app/src/main/res/drawable-mdpi/delete.png | Bin 0 -> 586 bytes app/src/main/res/drawable-mdpi/download.png | Bin 0 -> 617 bytes app/src/main/res/drawable-mdpi/stop.png | Bin 0 -> 360 bytes app/src/main/res/drawable-xhdpi/cancel.png | Bin 0 -> 1069 bytes app/src/main/res/drawable-xhdpi/chip.png | Bin 0 -> 1027 bytes app/src/main/res/drawable-xhdpi/delete.png | Bin 0 -> 760 bytes app/src/main/res/drawable-xhdpi/download.png | Bin 0 -> 912 bytes app/src/main/res/drawable-xhdpi/stop.png | Bin 0 -> 441 bytes app/src/main/res/drawable-xxhdpi/cancel.png | Bin 0 -> 4719 bytes app/src/main/res/drawable-xxhdpi/chip.png | Bin 0 -> 1568 bytes app/src/main/res/drawable-xxhdpi/delete.png | Bin 0 -> 1484 bytes app/src/main/res/drawable-xxhdpi/download.png | Bin 0 -> 2247 bytes app/src/main/res/drawable-xxhdpi/stop.png | Bin 0 -> 683 bytes app/src/main/res/drawable-xxxhdpi/cancel.png | Bin 0 -> 1069 bytes .../main/res/drawable-xxxhdpi/download.png | Bin 0 -> 912 bytes app/src/main/res/drawable-xxxhdpi/stop.png | Bin 0 -> 441 bytes app/src/main/res/drawable/progbar.xml | 45 ++ app/src/main/res/layout/binary_item.xml | 84 ++- app/src/main/res/layout/device.xml | 21 +- app/src/main/res/values/strings.xml | 17 +- build.gradle | 2 +- 39 files changed, 1314 insertions(+), 167 deletions(-) create mode 100644 app/src/main/java/fr/mobdev/lpcprog/adapters/BinariesAdapter.java create mode 100644 app/src/main/java/fr/mobdev/lpcprog/listener/DownloadListener.java create mode 100644 app/src/main/java/fr/mobdev/lpcprog/listener/FlashListener.java create mode 100644 app/src/main/java/fr/mobdev/lpcprog/objects/Parts.java create mode 100644 app/src/main/res/drawable-hdpi/cancel.png create mode 100644 app/src/main/res/drawable-hdpi/chip.png create mode 100644 app/src/main/res/drawable-hdpi/delete.png create mode 100644 app/src/main/res/drawable-hdpi/download.png create mode 100644 app/src/main/res/drawable-hdpi/stop.png create mode 100644 app/src/main/res/drawable-mdpi/cancel.png create mode 100644 app/src/main/res/drawable-mdpi/chip.png create mode 100644 app/src/main/res/drawable-mdpi/delete.png create mode 100644 app/src/main/res/drawable-mdpi/download.png create mode 100644 app/src/main/res/drawable-mdpi/stop.png create mode 100644 app/src/main/res/drawable-xhdpi/cancel.png create mode 100644 app/src/main/res/drawable-xhdpi/chip.png create mode 100644 app/src/main/res/drawable-xhdpi/delete.png create mode 100644 app/src/main/res/drawable-xhdpi/download.png create mode 100644 app/src/main/res/drawable-xhdpi/stop.png create mode 100644 app/src/main/res/drawable-xxhdpi/cancel.png create mode 100644 app/src/main/res/drawable-xxhdpi/chip.png create mode 100644 app/src/main/res/drawable-xxhdpi/delete.png create mode 100644 app/src/main/res/drawable-xxhdpi/download.png create mode 100644 app/src/main/res/drawable-xxhdpi/stop.png create mode 100644 app/src/main/res/drawable-xxxhdpi/cancel.png create mode 100644 app/src/main/res/drawable-xxxhdpi/download.png create mode 100644 app/src/main/res/drawable-xxxhdpi/stop.png create mode 100644 app/src/main/res/drawable/progbar.xml diff --git a/app/src/main/java/fr/mobdev/lpcprog/activity/DeviceActivity.java b/app/src/main/java/fr/mobdev/lpcprog/activity/DeviceActivity.java index fe143a6..3c8446d 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/activity/DeviceActivity.java +++ b/app/src/main/java/fr/mobdev/lpcprog/activity/DeviceActivity.java @@ -1,13 +1,25 @@ package fr.mobdev.lpcprog.activity; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.ProgressBar; import android.widget.TextView; +import java.util.ArrayList; import java.util.List; +import fr.mobdev.lpcprog.adapters.BinariesAdapter; +import fr.mobdev.lpcprog.listener.NetworkListener; +import fr.mobdev.lpcprog.managers.DatabaseManager; import fr.mobdev.lpcprog.managers.IspManager; import fr.mobdev.lpcprog.R; +import fr.mobdev.lpcprog.managers.NetworkManager; +import fr.mobdev.lpcprog.objects.Server; import fr.mobdev.lpcprog.objects.USBDevice; import fr.mobdev.lpcprog.managers.UsbCommManager; @@ -15,12 +27,18 @@ public class DeviceActivity extends AppCompatActivity { private UsbCommManager comm; private USBDevice dev; + private List servers; + private long part_id; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.device); + Toolbar toolbar = (Toolbar) findViewById(R.id.device_toolbar); + setSupportActionBar(toolbar); + servers = new ArrayList<>(); comm = UsbCommManager.getInstance(this); + part_id = 0; List devices = comm.getDevices(); int pid = getIntent().getIntExtra("PID",-1); int vid = getIntent().getIntExtra("VID",-1); @@ -40,6 +58,12 @@ public class DeviceActivity extends AppCompatActivity { product.setText(String.format("Product id: %04x", dev.PID)); } doUsb(); + ProgressBar bar = (ProgressBar) findViewById(R.id.progress_browse); + bar.setVisibility(View.GONE); + + RecyclerView list = (RecyclerView) findViewById(R.id.bin_list); + list.setLayoutManager(new LinearLayoutManager(this)); + updateRepositories(); } private void doUsb(){ @@ -48,7 +72,7 @@ public class DeviceActivity extends AppCompatActivity { @Override public void run() { boolean conn = comm.openConnection(dev); - IspManager manager = IspManager.getInstance(); + IspManager manager = IspManager.getInstance(DeviceActivity.this); String uidStr = "No UID Found or error"; String bootStr = "No Boot Version Found or error"; String partidStr = "No Part ID Found or error"; @@ -71,6 +95,8 @@ public class DeviceActivity extends AppCompatActivity { } if(partid != null){ partidStr = String.format("Part Id %08x",Long.parseLong(partid)); + part_id = Long.parseLong(partid); + IspManager.getInstance(DeviceActivity.this).setPartId(part_id); } } updateIDS(uidStr,partidStr,bootStr); @@ -94,4 +120,79 @@ public class DeviceActivity extends AppCompatActivity { } }); } + + private void updateRepositories(){ + System.out.println("Update Repo"); + NetworkListener listener = new NetworkListener() { + @Override + public void startBinaries() { + runOnUiThread(new Runnable() { + @Override + public void run() { + ProgressBar bar = (ProgressBar) findViewById(R.id.progress_browse); + bar.setVisibility(View.VISIBLE); + RecyclerView list = (RecyclerView) findViewById(R.id.bin_list); + list.setVisibility(View.GONE); + + } + }); + } + + @Override + public void startServer(Server server) { + } + + @Override + public void endServer(Server server) { + if(!server.binaries.isEmpty()) + servers.add(server); + } + + @Override + public void endBinaries() { + runOnUiThread(new Runnable() { + @Override + public void run() { + ProgressBar bar = (ProgressBar) findViewById(R.id.progress_browse); + bar.setVisibility(View.GONE); + RecyclerView list = (RecyclerView) findViewById(R.id.bin_list); + list.setVisibility(View.VISIBLE); + BinariesAdapter adapter = new BinariesAdapter(servers, DeviceActivity.this); + list.setAdapter(adapter); + } + }); + } + + @Override + public void onError(final String error) { + runOnUiThread(new Runnable() { + @Override + public void run() { + ProgressBar bar = (ProgressBar) findViewById(R.id.progress_browse); + bar.setVisibility(View.GONE); + final Snackbar msg = Snackbar.make(findViewById(R.id.bin_list), error,Snackbar.LENGTH_INDEFINITE); + msg.setAction(R.string.retry_browse, new View.OnClickListener() { + @Override + public void onClick(View v) { + msg.dismiss(); + updateRepositories(); + } + }); + msg.show(); + List> localServers = DatabaseManager.getInstance(DeviceActivity.this).getServers(); + servers.addAll(localServers.get(0)); + servers.addAll(localServers.get(1)); + servers.addAll(localServers.get(2)); + RecyclerView list = (RecyclerView) findViewById(R.id.bin_list); + list.setVisibility(View.VISIBLE); + BinariesAdapter adapter = new BinariesAdapter(servers,DeviceActivity.this); + list.setAdapter(adapter); + + } + }); + } + }; + NetworkManager.getInstance(listener,this).browseBinaries(); + + } } diff --git a/app/src/main/java/fr/mobdev/lpcprog/adapters/BinariesAdapter.java b/app/src/main/java/fr/mobdev/lpcprog/adapters/BinariesAdapter.java new file mode 100644 index 0000000..c205e55 --- /dev/null +++ b/app/src/main/java/fr/mobdev/lpcprog/adapters/BinariesAdapter.java @@ -0,0 +1,289 @@ +package fr.mobdev.lpcprog.adapters; + +import android.app.Activity; +import android.content.DialogInterface; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.io.File; +import java.util.List; + +import fr.mobdev.lpcprog.R; +import fr.mobdev.lpcprog.listener.DownloadListener; +import fr.mobdev.lpcprog.listener.FlashListener; +import fr.mobdev.lpcprog.managers.DatabaseManager; +import fr.mobdev.lpcprog.managers.IspManager; +import fr.mobdev.lpcprog.managers.NetworkManager; +import fr.mobdev.lpcprog.objects.Binary; +import fr.mobdev.lpcprog.objects.Server; + +public class BinariesAdapter extends RecyclerView.Adapter { + + private static final int SECTION = 0; + private static final int FIELD = 1; + + private List servers; + private int count; + private Activity activity; + + public BinariesAdapter(List servers, Activity activity) { + this.servers = servers; + this.activity = activity; + countElements(); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + if (viewType == SECTION) { + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.server_section, parent, false); + return new SectionHolder(view); + } else { + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.binary_item, parent, false); + return new BinaryHolder(view); + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder instanceof SectionHolder) { + SectionHolder sectionHolder = (SectionHolder) holder; + int section = getSection(position); + System.out.println("pos " + position + " section " + section); + String sectionName = servers.get(section).url.toString(); + sectionHolder.setupSection(sectionName); + } else if (holder instanceof BinaryHolder) { + BinaryHolder binaryHolder = (BinaryHolder) holder; + + int section = getSection(position); + int pos = getRealPosition(position); + Server server = servers.get(section); + Binary binary = servers.get(section).binaries.get(pos); + binaryHolder.setupBinary(server,binary,activity); + } + } + + private void countElements() { + int size = 0; + for (int i = 0; i < servers.size(); i++) { + if (servers.get(i).binaries.size() > 0) { + size++; + size += servers.get(i).binaries.size(); + } + } + count = size; + } + + private int getRealPosition(int fakePosition) { + System.out.println("get real " + fakePosition); + fakePosition -= 1; + for (int i = 0; i < servers.size(); i++) { + int serverSize = servers.get(i).binaries.size(); + if (fakePosition - serverSize < 0) + return fakePosition; + if (serverSize > 0) { + fakePosition -= 1; + fakePosition -= serverSize; + } + } + return -1; + } + + private int getSection(int fakePosition) { + int prev_size = 1; + for (int i = 0; i < servers.size(); i++) { + int serverSize = servers.get(i).binaries.size(); + if (fakePosition < prev_size + serverSize) + return i; + if (servers.get(i).binaries.size() > 0) { + prev_size += 1; + prev_size += serverSize; + } + } + return -1;//error + } + + @Override + public int getItemCount() { + return count; + } + + @Override + public int getItemViewType(int position) { + int nbValues = 0; + for (int i = 0; i < servers.size(); i++) { + if (position == i + nbValues) + return SECTION; + else if (position < i + nbValues) + break; + nbValues += servers.get(i).binaries.size(); + } + return FIELD; + } +} + +class BinaryHolder extends RecyclerView.ViewHolder{ + DownloadListener listener; + public BinaryHolder(View itemView) { + super(itemView); + } + + public void setupBinary(final Server server, final Binary binary, final Activity activity){ + + TextView name = (TextView) itemView.findViewById(R.id.binary_name); + TextView version = (TextView) itemView.findViewById(R.id.binary_version); + + final LinearLayout downloadedLayout = (LinearLayout) itemView.findViewById(R.id.layout_downloaded); + final ImageView deleteView = (ImageView) itemView.findViewById(R.id.delete_download); + final ImageView flashView = (ImageView) itemView.findViewById(R.id.flash_download); + final ImageView downloadView = (ImageView) itemView.findViewById(R.id.download); + final ImageView stopView = (ImageView) itemView.findViewById(R.id.cancel_download); + final ProgressBar progressBar = (ProgressBar) itemView.findViewById(R.id.progress_download); + + name.setText(binary.name); + version.setText("V "+binary.version); + if(binary.isDownloaded) { + downloadView.setVisibility(View.GONE); + downloadedLayout.setVisibility(View.VISIBLE); + stopView.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + } else if(binary.isDownloading){ + downloadView.setVisibility(View.GONE); + downloadedLayout.setVisibility(View.GONE); + stopView.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.VISIBLE); + } else { + downloadView.setVisibility(View.VISIBLE); + downloadedLayout.setVisibility(View.GONE); + stopView.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + } + + listener = new DownloadListener() { + + @Override + public void downloadCanceled(Server server, Binary binary) { + binary.isDownloading = false; + binary.progress = 0; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + downloadView.setVisibility(View.VISIBLE); + downloadedLayout.setVisibility(View.GONE); + stopView.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + } + }); + } + + @Override + public void downloadSuccessful(Server server, Binary binary) { + binary.isDownloading = false; + binary.progress = 0; + binary.isDownloaded = true; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + downloadView.setVisibility(View.GONE); + downloadedLayout.setVisibility(View.VISIBLE); + stopView.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + } + }); + } + + @Override + public void downloadError(Server server, Binary binary, final String error) { + binary.isDownloading = false; + binary.progress = 0; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + downloadView.setVisibility(View.VISIBLE); + downloadedLayout.setVisibility(View.GONE); + stopView.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + Snackbar.make(activity.findViewById(R.id.bin_list), error,Snackbar.LENGTH_LONG); + } + }); + } + + @Override + public void progress(Server server, Binary binary, final int progress) { + binary.progress = progress; + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + progressBar.setProgress(progress); + } + }); + } + }; + + downloadView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + binary.isDownloading = true; + binary.progress = 0; + NetworkManager.getInstance(null,itemView.getContext()).retrieveBinary(server,binary,listener); + } + }); + + + deleteView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + AlertDialog.Builder builder = new AlertDialog.Builder(itemView.getContext()); + builder.setMessage(itemView.getContext().getString(R.string.delete_binary_message)+" "+binary.name+" "+ + itemView.getContext().getString(R.string.version)+" "+binary.version+" ?") + .setCancelable(false) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + //delete server from database and update the view + File file = new File(itemView.getContext().getApplicationInfo().dataDir+"/"+server.id+"/"+binary.path+binary.filename); + if(file.exists()) + file.delete(); + binary.isDownloaded = false; + DatabaseManager.getInstance(itemView.getContext()).deleteBinary(binary.id); + //file and reset all downloaded items + downloadView.setVisibility(View.VISIBLE); + downloadedLayout.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + stopView.setVisibility(View.GONE); + } + }) + .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + }); + + final FlashListener flashListener = new FlashListener() { + @Override + public void onError(String string) { + System.out.println("flash_error "+string); + } + }; + + flashView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + IspManager.getInstance(itemView.getContext()).flash(server,binary,flashListener); + } + }); + } +} + diff --git a/app/src/main/java/fr/mobdev/lpcprog/listener/DownloadListener.java b/app/src/main/java/fr/mobdev/lpcprog/listener/DownloadListener.java new file mode 100644 index 0000000..ef068da --- /dev/null +++ b/app/src/main/java/fr/mobdev/lpcprog/listener/DownloadListener.java @@ -0,0 +1,13 @@ +package fr.mobdev.lpcprog.listener; + +import java.util.EventListener; + +import fr.mobdev.lpcprog.objects.Binary; +import fr.mobdev.lpcprog.objects.Server; + +public interface DownloadListener extends EventListener { + void downloadCanceled(Server server, Binary binary); + void downloadSuccessful(Server server, Binary binary); + void downloadError(Server server, Binary binary, String string); + void progress(Server server, Binary binary, int progress); +} diff --git a/app/src/main/java/fr/mobdev/lpcprog/listener/FlashListener.java b/app/src/main/java/fr/mobdev/lpcprog/listener/FlashListener.java new file mode 100644 index 0000000..7f6f95e --- /dev/null +++ b/app/src/main/java/fr/mobdev/lpcprog/listener/FlashListener.java @@ -0,0 +1,8 @@ +package fr.mobdev.lpcprog.listener; + +import java.util.EventListener; + +public interface FlashListener extends EventListener{ + + void onError(String string); +} diff --git a/app/src/main/java/fr/mobdev/lpcprog/listener/NetworkListener.java b/app/src/main/java/fr/mobdev/lpcprog/listener/NetworkListener.java index f850117..db899b9 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/listener/NetworkListener.java +++ b/app/src/main/java/fr/mobdev/lpcprog/listener/NetworkListener.java @@ -29,9 +29,4 @@ public interface NetworkListener extends EventListener{ void endServer(Server server); void endBinaries(); void onError(String string); - void downloadCanceled(Server server, Binary binary); - void downloadSuccessful(Server server, Binary binary); - void downloadFailed(Server server, Binary binary); - void downloadError(Server server, Binary binary, String string); - void progress(Server server, Binary binary, int progress); } diff --git a/app/src/main/java/fr/mobdev/lpcprog/managers/DatabaseManager.java b/app/src/main/java/fr/mobdev/lpcprog/managers/DatabaseManager.java index 35f6644..76c818c 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/managers/DatabaseManager.java +++ b/app/src/main/java/fr/mobdev/lpcprog/managers/DatabaseManager.java @@ -28,6 +28,8 @@ import java.net.URL; import java.util.ArrayList; import java.util.List; +import fr.mobdev.lpcprog.objects.Binary; +import fr.mobdev.lpcprog.objects.Parts; import fr.mobdev.lpcprog.objects.Server; public class DatabaseManager extends SQLiteOpenHelper { @@ -47,14 +49,31 @@ public class DatabaseManager extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { db.execSQL("Create table if not exists binaries (" + - "id integer primary key autoincrement, name varchar(1024), short_hash varchar(1024), real_short_hash varchar(1024), date INTEGER, storage_duration INTEGER ,thumb TEXT, token varchar(1024));"); + "id integer primary key autoincrement, server_id INTEGER, name varchar(1024), filename varchar(1024), version INTEGER, path varchar(1024), sha1 varchar(1024));"); db.execSQL("Create table if not exists servers (" + "id integer primary key autoincrement, url varchar(1024), isActive INTEGER, attempted INTEGER);"); + db.execSQL("Create table if not exists definitions (" + + "id integer primary key autoincrement, part_id INTEGER, part_name varchar(1024), fl_base_addr INTEGER, fl_size INTEGER, fl_nb_sect INTEGER," + + "reset_vector_offset INTEGER, ram_base_addr INTEGER, ram_size INTEGER, ram_buf_off INTEGER, ram_buf_size INTEGER, UU_encode INTEGER);"); ContentValues values = new ContentValues(); values.put("url","https://wiki.mob-dev.fr/files/"); values.put("isActive",1); values.put("attempted",0); db.insert("servers",null,values); + + values.clear(); + values.put("part_id",0x3640C02B); + values.put("part_name","LPC1224FBD48/101"); + values.put("fl_base_addr",0x0); + values.put("fl_size",0x8000); + values.put("fl_nb_sect",8); + values.put("reset_vector_offset",0x04); + values.put("ram_base_addr",0x10000000); + values.put("ram_size",0x1000); + values.put("ram_buf_off",0x800); + values.put("ram_buf_size",0x400); + values.put("UU_encode",true); + db.insert("definitions",null,values); } @Override @@ -106,6 +125,7 @@ public class DatabaseManager extends SQLiteOpenHelper { int isActive = cursor.getInt(col++); server.isActive = isActive != 0; server.attempted = cursor.getInt(col); + server.binaries = getBinaries(server.id); if (server.isActive && server.attempted == 0) active.add(server); else if (server.isActive && server.attempted != 0) @@ -120,6 +140,91 @@ public class DatabaseManager extends SQLiteOpenHelper { return list; } + private List getBinaries(long id) { + List binaries = new ArrayList<>(); + String whereClause = "server_id = ?"; + String[] whereArgs = new String[1]; + whereArgs[0] = String.valueOf(id); + Cursor cursor = getReadableDatabase().query("binaries", null, whereClause, whereArgs, null, null, null); + while (cursor.moveToNext()){ + System.out.println("Found a binary in db"); + int col = 0; + Binary b = new Binary(); + b.id = cursor.getLong(col++); + col++;//ignore server id + b.name = cursor.getString(col++); + b.filename = cursor.getString(col++); + b.version = cursor.getInt(col++); + b.path = cursor.getString(col++); + b.sha1 = cursor.getString(col); + b.isDownloaded = true; + b.progress = 0; + b.isDownloading = false; + binaries.add(b); + } + cursor.close(); + return binaries; + } + public void serverFail(Server server) { + server.attempted++; + if(server.attempted == 5){ + server.attempted = 0; + server.isActive = false; + } + ContentValues values = new ContentValues(); + values.put("attempted",server.attempted); + values.put("isActive",server.isActive); + String whereClause = "id = ?"; + String[] whereArgs = new String[1]; + whereArgs[0] = String.valueOf(server.id); + getWritableDatabase().update("servers",values,whereClause,whereArgs); + } + + public void addBinary(Server server, Binary binary) { + System.out.println("add binary"); + ContentValues values = new ContentValues(); + values.put("server_id",server.id); + values.put("name",binary.name); + values.put("filename",binary.filename); + values.put("version",binary.version); + values.put("path",binary.path); + values.put("sha1",binary.sha1); + values.put("name",binary.name); + getWritableDatabase().insert("binaries",null,values); + } + + public void deleteBinary(long id) { + String whereClause = "id = ?"; + String[] whereArgs = new String[1]; + whereArgs[0] = String.valueOf(id); + getWritableDatabase().delete("binaries",whereClause,whereArgs); + } + + public Parts getParts(long part_id) { + Parts parts = null; + String whereClause = "part_id = ?"; + String[] whereArgs = new String[1]; + whereArgs[0] = String.valueOf(part_id); + System.out.println("part_id "+part_id); + Cursor cursor = getReadableDatabase().query("definitions", null, whereClause, whereArgs, null, null, null); + if (cursor.moveToNext()) { + parts = new Parts(); + int col = 0; + parts.id = cursor.getLong(col++); + parts.part_id = cursor.getInt(col++); + parts.part_name = cursor.getString(col++); + parts.flash_base_addr = cursor.getInt(col++); + parts.flash_size = cursor.getInt(col++); + parts.flash_nb_sectors = cursor.getInt(col++); + parts.reset_vector_offset = cursor.getInt(col++); + parts.ram_base_addr = cursor.getInt(col++); + parts.ram_size = cursor.getInt(col++); + parts.ram_buffer_offset = cursor.getInt(col++); + parts.ram_buffer_size = cursor.getInt(col++); + parts.uuencode = cursor.getInt(col) == 1; + } + + return parts; } } diff --git a/app/src/main/java/fr/mobdev/lpcprog/managers/IspManager.java b/app/src/main/java/fr/mobdev/lpcprog/managers/IspManager.java index 60aa576..041fd08 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/managers/IspManager.java +++ b/app/src/main/java/fr/mobdev/lpcprog/managers/IspManager.java @@ -1,54 +1,77 @@ package fr.mobdev.lpcprog.managers; +import android.content.Context; + import com.ftdi.j2xx.D2xxManager; import com.ftdi.j2xx.FT_Device; +import java.io.File; +import java.io.FileInputStream; import java.nio.ByteBuffer; import java.util.Locale; +import fr.mobdev.lpcprog.R; +import fr.mobdev.lpcprog.listener.FlashListener; +import fr.mobdev.lpcprog.objects.Binary; +import fr.mobdev.lpcprog.objects.Parts; +import fr.mobdev.lpcprog.objects.Server; import fr.mobdev.lpcprog.objects.USBDevice; public class IspManager { //defines private static final int REP_BUF = 100; - private static final byte[] SYNC_START = "?".getBytes(); - private static final byte[] SYNC = "Synchronized\r\n".getBytes(); - private static final byte[] SYNC_OK = "OK\r\n".getBytes(); - private static final byte[] DATA_BLOCK = "OK\r\n".getBytes(); - private static final byte[] DATA_BLOCK_RESEND = "RESEND\r\n".getBytes(); - private static final byte[] SYNC_ECHO_OFF = "A 0\r\n".getBytes(); - private static final byte[] READ_UID = "N\r\n".getBytes(); + private static final int SERIAL_BUF_SIZE = 1300; + private static final int LINE_DATA_LENGTH = 45; + private static final int LINES_PER_BLOCK = 20; + private static final int MAX_DATA_BLOCK_SIZE = LINES_PER_BLOCK * LINE_DATA_LENGTH; + private static final int UUENCODE_ADDED_VAL = 32; + private static final int LINE_DATA_LENGTH_MAX = 45; + private static final byte[] SYNC_START = "?".getBytes(); + private static final byte[] SYNC = "Synchronized\r\n".getBytes(); + private static final byte[] SYNC_OK = "OK\r\n".getBytes(); + private static final byte[] DATA_BLOCK_OK = "OK\r\n".getBytes(); + //private static final byte[] DATA_BLOCK_RESEND = "RESEND\r\n".getBytes(); + private static final byte[] SYNC_ECHO_OFF = "A 0\r\n".getBytes(); + private static final byte[] READ_UID = "N\r\n".getBytes(); private static final byte[] READ_PART_ID = "J\r\n".getBytes(); private static final byte[] READ_BOOT_VERSION = "K\r\n".getBytes(); + private static final byte[] UNLOCK = "U 23130\r\n".getBytes(); //members private static IspManager instance = null; private FT_Device serialPort = null; + private Context context; + private long part_id = 0; - private IspManager(){ + private IspManager(Context context) { + this.context = context; } - public static IspManager getInstance(){ - if(instance == null) - instance = new IspManager(); + public static IspManager getInstance(Context context) { + if (instance == null) + instance = new IspManager(context); return instance; } - public boolean setupDevice(USBDevice device, int baudRate){ + public void setPartId(long part){ + part_id = part; + } + + public boolean setupDevice(USBDevice device, int baudRate) { serialPort = device.device; - if(serialPort != null) + if (serialPort != null) serialPort.resetDevice(); else System.out.println("device is null fuck"); - if(serialPort!=null && serialPort.isOpen()){ + if (serialPort != null && serialPort.isOpen()) { serialPort.setBaudRate(baudRate); - byte dc1=0x11; - byte dc3=0x13; - serialPort.setFlowControl(D2xxManager.FT_FLOW_XON_XOFF,dc1,dc3); - serialPort.setDataCharacteristics(D2xxManager.FT_DATA_BITS_8,D2xxManager.FT_STOP_BITS_1,D2xxManager.FT_PARITY_NONE); + byte dc1 = 0x11; + byte dc3 = 0x13; + serialPort.setFlowControl(D2xxManager.FT_FLOW_XON_XOFF, dc1, dc3); + serialPort.setDataCharacteristics(D2xxManager.FT_DATA_BITS_8, D2xxManager.FT_STOP_BITS_1, D2xxManager.FT_PARITY_NONE); byte l = 0x2; serialPort.setLatencyTimer(l); return true; @@ -56,174 +79,164 @@ public class IspManager { return false; } - public boolean synchronize(int crystal_freq){ - if(serialPort == null) + public boolean synchronize(int crystal_freq) { + if (serialPort == null) return false; serialPort.purge(D2xxManager.FT_PURGE_RX); serialPort.purge(D2xxManager.FT_PURGE_TX); byte[] buf; - if(serialPort.write(SYNC_START) != SYNC_START.length){ + if (serialPort.write(SYNC_START) != SYNC_START.length) { System.out.println("Start"); return false; } buf = new byte[SYNC.length]; - serialPort.read(buf,buf.length,500); + serialPort.read(buf, buf.length, 500); String result = new String(buf); String expected = new String(SYNC); - if(result.compareTo(expected) != 0) { - printbuffer(buf); + if (result.compareTo(expected) != 0) { serialPort.write("\r\n".getBytes()); - System.out.println("Start answer "+result); + System.out.println("Start answer " + result); return false; } - if(serialPort.write(SYNC) != SYNC.length) { + if (serialPort.write(SYNC) != SYNC.length) { System.out.println("SYNC write"); return false; } clearBuffer(SYNC.length); buf = new byte[SYNC_OK.length]; - serialPort.read(buf,buf.length,500); + serialPort.read(buf, buf.length, 500); result = new String(buf); expected = new String(SYNC_OK); - if(result.compareTo(expected) != 0) { - printbuffer(buf); - System.out.println("SYNC OK "+result); + if (result.compareTo(expected) != 0) { + System.out.println("SYNC OK " + result); return false; } - String freq = String.valueOf(crystal_freq)+"\r\n"; - if(serialPort.write(freq.getBytes()) != freq.length()) { + String freq = String.valueOf(crystal_freq) + "\r\n"; + if (serialPort.write(freq.getBytes()) != freq.length()) { System.out.println("freq write"); return false; } clearBuffer(freq.length()); buf = new byte[SYNC_OK.length]; - serialPort.read(buf,buf.length,500); + serialPort.read(buf, buf.length, 500); result = new String(buf); expected = new String(SYNC_OK); - if(result.compareTo(expected) != 0) { - System.out.println("freq answer "+result); - printbuffer(buf); + if (result.compareTo(expected) != 0) { + System.out.println("freq answer " + result); return false; } - if(serialPort.write(SYNC_ECHO_OFF) != SYNC_ECHO_OFF.length) { + if (serialPort.write(SYNC_ECHO_OFF) != SYNC_ECHO_OFF.length) { System.out.println("Sync Echo Off write"); return false; } clearBuffer(SYNC_ECHO_OFF.length); buf = new byte[3]; - int ret = serialPort.read(buf,buf.length,500); - System.out.println(String.format(Locale.getDefault(),"%d %02x %02x %02x",ret,buf[0],buf[1],buf[2])); + int ret = serialPort.read(buf, buf.length, 500); + System.out.println(String.format(Locale.getDefault(), "%d %02x %02x %02x", ret, buf[0], buf[1], buf[2])); return true; - } - private void printbuffer(byte[] buffer){ - for(byte b : buffer){ - System.out.println(String.format("%02x",b)); - } - } - - private void clearBuffer(int size){ - if(serialPort == null) + private void clearBuffer(int size) { + if (serialPort == null) return; byte[] buf = new byte[size]; - int readed = read(buf,size,500); - System.out.println("end "+(size-readed)); + int readed = read(buf, size, 500); + System.out.println("end " + (size - readed)); } - public String[] readUid(){ - if(serialPort == null) + public String[] readUid() { + if (serialPort == null) return null; - int ret = sendCommand(READ_UID,null); + int ret = sendCommand(READ_UID, null); - if(ret != 0){ - System.out.println("Send Command "+ret); + if (ret != 0) { + System.out.println("Send Command " + ret); return null; } byte[] buf = new byte[REP_BUF]; - int size = read(buf,50,500); - for(int i = 0; i < size; i++){ + int size = read(buf, 50, 500); + for (int i = 0; i < size; i++) { System.out.println(String.format("%02x", buf[i])); } - if(size<=0){ - System.out.println("Send size "+size); + if (size <= 0) { + System.out.println("Send size " + size); return null; } String[] uids = new String[4]; String buffer = new String(buf); - if(buffer.contains("\r") && buffer.contains("\n")) - buffer = buffer.replace("\n",""); - else if(!buffer.contains("\r") && buffer.contains("\n")) - buffer = buffer.replace("\n","\r"); + if (buffer.contains("\r") && buffer.contains("\n")) + buffer = buffer.replace("\n", ""); + else if (!buffer.contains("\r") && buffer.contains("\n")) + buffer = buffer.replace("\n", "\r"); - for(int i = 0; i < 4; i++){ - if(buffer.contains("\r")) { + for (int i = 0; i < 4; i++) { + if (buffer.contains("\r")) { uids[i] = buffer.substring(0, buffer.indexOf("\r")); - buffer = buffer.substring(buffer.indexOf("\r")+1); + buffer = buffer.substring(buffer.indexOf("\r") + 1); } } System.out.println("uids ok"); return uids; } - public String readPartId(){ - if(serialPort == null) + public String readPartId() { + if (serialPort == null) return null; - int ret = sendCommand(READ_PART_ID,null); - if(ret != 0) + int ret = sendCommand(READ_PART_ID, null); + if (ret != 0) return null; byte[] buf = new byte[REP_BUF]; - int size = read(buf,20,500); - if(size <= 0) + int size = read(buf, 20, 500); + if (size <= 0) return null; String partId = new String(buf); - partId = partId.substring(0,partId.indexOf("\r\n")); - if(partId.contains("\r")) - partId = partId.replace("\r",""); - if(partId.contains("\n")) - partId = partId.replace("\n",""); + partId = partId.substring(0, partId.indexOf("\r\n")); + if (partId.contains("\r")) + partId = partId.replace("\r", ""); + if (partId.contains("\n")) + partId = partId.replace("\n", ""); return partId; } - public String[] readBootVersion(){ - if(serialPort == null) + public String[] readBootVersion() { + if (serialPort == null) return null; - int ret = sendCommand(READ_BOOT_VERSION,null); - if(ret != 0){ - System.out.println("Send Command "+ret); + int ret = sendCommand(READ_BOOT_VERSION, null); + if (ret != 0) { + System.out.println("Send Command " + ret); return null; } byte[] buf = new byte[REP_BUF]; - int size = read(buf,50,500); + int size = read(buf, 50, 500); - if(size <= 0){ - System.out.println("Receive "+size); + if (size <= 0) { + System.out.println("Receive " + size); return null; } String[] version = new String[2]; String buffer = new String(buf); - if(buffer.contains("\r") && buffer.contains("\n")) - buffer = buffer.replace("\n",""); - else if(!buffer.contains("\r") && buffer.contains("\n")) - buffer = buffer.replace("\n","\r"); + if (buffer.contains("\r") && buffer.contains("\n")) + buffer = buffer.replace("\n", ""); + else if (!buffer.contains("\r") && buffer.contains("\n")) + buffer = buffer.replace("\n", "\r"); - for(int i = 0; i < 2; i++){ - if(buffer.contains("\r")) { + for (int i = 0; i < 2; i++) { + if (buffer.contains("\r")) { version[i] = buffer.substring(0, buffer.indexOf("\r")); - buffer = buffer.substring(buffer.indexOf("\r")+1); + buffer = buffer.substring(buffer.indexOf("\r") + 1); } } @@ -231,33 +244,58 @@ public class IspManager { return version; } - public int sendCommand(byte[] cmd, String[] args){ + private int sendCommand(byte[] cmd, String[] args) { + if(args != null)//FIXME + return -1; byte[] buf = new byte[3]; - if(serialPort.write(cmd) != cmd.length) + if (serialPort.write(cmd) != cmd.length) return -5; - int len = read(buf, buf.length,500); - System.out.println("Len "+len); - for(int i = 0; i < 3; i++){ + int len = read(buf, buf.length, 500); + System.out.println("Len " + len); + for (int i = 0; i < 3; i++) { System.out.println(String.format("%02x", buf[i])); } - if(len <= 0) + if (len <= 0) return -4; return parseRetCode(buf); } - public int read(byte[] buffer, int size, int timeout){ + private int sendCommand(byte[] cmd, char c, int addr, int count) { + int ret = 0; + int len = 0; + + byte[] buf = String.format(Locale.getDefault(),"%c %d %d\r\n",c,addr,count).getBytes(); + len = buf.length; + if(len > REP_BUF) { + len = REP_BUF; + } + int sent = serialPort.write(buf,len); + if(len != sent) { + return -5; + } + buf = new byte[3]; + len = read(buf,3,500); + if(len <= 0) { + return -4; + } + ret = parseRetCode(buf); + + return ret; + } + + private int read(byte[] buffer, int size, int timeout) { long startTime = System.nanoTime(); long timeoutNano = timeout * 1000000; int sizeRead = 0; - ByteBuffer output = ByteBuffer.wrap(buffer,0,size); + ByteBuffer output = ByteBuffer.wrap(buffer, 0, size); - while(sizeRead < size){ + while (sizeRead < size) { int sizeToRead = serialPort.getQueueStatus(); - if(sizeRead + sizeToRead > size) + if (sizeRead + sizeToRead > size) sizeToRead = size - sizeRead; byte[] buf = new byte[sizeToRead]; - if(sizeToRead > 0) { + if (sizeToRead > 0) { int sizeReceived = serialPort.read(buf, sizeToRead, 50); if (sizeReceived < 0) return sizeReceived; @@ -266,21 +304,22 @@ public class IspManager { output.put(buf, 0, sizeReceived); } long time = System.nanoTime(); - if(time - startTime >= timeoutNano) + if (time - startTime >= timeoutNano) break; } return sizeRead; } - private int parseRetCode(byte[] data){ + private int parseRetCode(byte[] data) { String str = new String(data); - str = str.replace("\r\n",""); - + str = str.replace("\r\n", ""); + if (!str.matches("[0-9 -+]*")) + return -1; return Integer.parseInt(str); } public boolean synchronizeIfPossible(int crystal_freq) { - if(!synchronize(crystal_freq)) { + if (!synchronize(crystal_freq)) { serialPort.purge(D2xxManager.FT_PURGE_TX); serialPort.purge(D2xxManager.FT_PURGE_RX); String[] uids = readUid(); @@ -293,26 +332,413 @@ public class IspManager { return true; } - /*private int byteArrayToInt(byte[] array, int offset){ + private int eraseFlash(Parts parts) { + int ret = unlock(); + if (ret != 0) { + System.out.println("unlock fail"); + return -1; + } + for (int i = 0; i < parts.flash_nb_sectors; i++) { + //blank-check + ret = send_cmd_sectors('I', i, i); + if (ret == 0) { + continue; + } + + if (ret < 0) { + System.out.println("blank "+i+" fail"); + return ret; + } else { + byte buf[] = new byte[REP_BUF]; + read(buf, 40, 500); + } + //prepare-for-write + ret = send_cmd_sectors('P', i, i); + if (ret != 0) { + System.out.println("prepare-for-write "+i+" fail"); + return ret; + } + //erase + ret = send_cmd_sectors('E', i, i); + if (ret != 0) { + System.out.println("erase "+i+" fail"); + return ret; + } + } + return 0; + } + + private int send_cmd_sectors(char cmd, int first_sector, int last_sector) { + byte[] buf = new byte[3]; + int ret; + int len; + + if(last_sector < first_sector){ + return -6; + } + + String request = String.format(Locale.getDefault(),"%c %d %d\r\n",cmd, first_sector, last_sector); + len = serialPort.write(request.getBytes()); + if(len != request.getBytes().length){ + return -5; + } + len = read(buf,3,500); + if(len <= 0){ + return -4; + } + + ret = parseRetCode(buf); + + return ret; + } + + private int unlock() { + int ret = sendCommand(UNLOCK,null); + if(ret != 0) + return -1; + return 0; + } + + public void flash(final Server server, final Binary binary, final FlashListener listener) { + new Thread(new Runnable() { + @Override + public void run() { + flashBinary(server,binary,listener); + } + }).start(); + } + + private int flashBinary(Server server, Binary binary, FlashListener listener) { + Parts parts = DatabaseManager.getInstance(context).getParts(part_id); + if(parts == null) { + listener.onError(context.getString(R.string.parts_missing)); + return -1; + } + int sector_size = parts.flash_size / parts.flash_nb_sectors; + long ram_addr = parts.ram_base_addr + parts.ram_buffer_offset; + boolean uuencode = parts.uuencode; + byte data[]; + + //Sanity Checks + if (ram_addr > parts.ram_base_addr + parts.ram_size) { + listener.onError(context.getString(R.string.buffer_out_ram)); + return -2; + } + + long write_size = calcWriteSize(sector_size, parts.ram_buffer_size); + if (write_size == 0) { + listener.onError(context.getString(R.string.block_size_null)); + return -3; + } + + int ret = eraseFlash(parts); + if (ret != 0) { + listener.onError(context.getString(R.string.cant_erase_flash)); + return -4; + } + + + data = new byte[parts.flash_size]; + //copy file buffer to data array + File file = new File(context.getApplicationInfo().dataDir + "/" + server.id + "/" + binary.path + binary.filename); + int size = copy_buffer(file, data, parts.flash_size); + if (size <= 0) { + System.out.println("Size " + size); + listener.onError(context.getString(R.string.copy_file)); + return -5; + } + + fill_data_with_0(data, size, parts.flash_size); + int cksum = calc_binary_checksum(data); + setChecksum(data, 28, cksum); + if(!verifyChecksum(data,cksum)) { + listener.onError(context.getString(R.string.checksum_failed)); + return -6; + } + long blocks = (size / write_size) + ((size % write_size == 0) ? 0 : 1); + if (blocks * write_size > parts.flash_size) { + listener.onError(context.getString(R.string.flash_outside_end)); + } + + for(int i = 0; i < blocks; i++){ + int current_sector = (int)(i*write_size)/sector_size; + int flash_addr = (int)(parts.flash_base_addr + (i*write_size)); + //prepare-for-write + ret = send_cmd_sectors('P',current_sector,current_sector); + if(ret != 0){ + listener.onError(context.getString(R.string.prepare_write_error)+" "+i); + return ret; + } + + ret = send_buf_to_ram(data,(int)(i*write_size),(int)ram_addr,(int)write_size, uuencode); + if(ret != 0) { + listener.onError(context.getString(R.string.write_ram_error)+" "+i); + return ret; + } + + //write-to-ram + ret = send_cmd_address('C', flash_addr, (int)ram_addr, (int) write_size); + if(ret != 0){ + listener.onError(context.getString(R.string.copy_to_flash_error)+" "+i); + return ret; + } + + } + + return ret; + } + + private int send_cmd_address(char c, int flash_addr, int ram_addr, int write_size) { + int ret; + int len; + byte[] buf = new byte[3]; + String request = String.format(Locale.getDefault(),"%c %d %d %d\r\n",c,flash_addr,ram_addr,write_size); + len = serialPort.write(request.getBytes()); + if(len != request.getBytes().length){ + System.out.println("cmd addr write"); + return -5; + } + len = read(buf,3,500); + if (len <= 0) { + System.out.println("cmd addr read"); + return -4; + } + ret = parseRetCode(buf); + + System.out.println("cmd addr ret "+ret); + return ret; + } + + private int send_buf_to_ram(byte[] data, int offset, int ram_addr, int write_size, boolean uuencode) { + int ret; + int len; + int blocks; + int total_sent =0; + + byte[] dataToSend = new byte[write_size]; + System.arraycopy(data,offset,dataToSend,0,write_size); + + ret = sendCommand("write-to-ram".getBytes(),'W',ram_addr,write_size); + if(ret != 0){ + System.out.println("ask for write to ram"); + return -8; + } + if(!uuencode) { + len = serialPort.write(dataToSend); + if(len != write_size){ + return -7; + } + return 0; + } + + blocks = get_nb_blocks(write_size); + + int resend_requested_for_block = 0; + for(int i = 0; i < blocks; i++){ + byte[] buf = new byte[SERIAL_BUF_SIZE]; + byte[] repbuf = new byte[REP_BUF]; + int data_size; + int encoded_size; + int computed_checksum; + data_size = (write_size - total_sent); + if( data_size >= MAX_DATA_BLOCK_SIZE) + data_size = MAX_DATA_BLOCK_SIZE; + encoded_size = uu_encode(buf,dataToSend,total_sent,data_size); + computed_checksum = calc_checksum(dataToSend,total_sent,data_size); + + byte[] checksum = String.format(Locale.getDefault(),"%d\r\n", computed_checksum).getBytes(); + System.out.println(String.format(Locale.getDefault(),"%d %08x",i,computed_checksum)); + System.arraycopy(checksum,0,buf,encoded_size,checksum.length); + encoded_size+=checksum.length; + //buf[encoded_size]='\0'; + //encoded_size++; + for(int j = 0; j < encoded_size; j++) { + System.out.print(String.format(Locale.getDefault(),"%02x",buf[j])); + if(j%10==0) + System.out.println(""); + } + len = serialPort.write(buf,encoded_size); + if(len != encoded_size) { + System.out.println("write fail "+i); + return -8; + } + len = read(repbuf,REP_BUF,500); + if(len <= 0) { + System.out.println("read answer fail "+i); + return -9; + } + repbuf[len]='\0'; + System.out.println("Length "+len); + for(int j = 0; j < len; j++) { + System.out.println(String.format(Locale.getDefault(),"%02x",repbuf[j])); + } + String result = new String(repbuf,0,len); + String expected = new String(DATA_BLOCK_OK); + System.out.println("result "+result+"."); + if(result.compareTo(expected)==0){ + total_sent += data_size; + resend_requested_for_block = 0; + } else { + resend_requested_for_block++; + if(resend_requested_for_block >= 3) { + System.out.println("resend fail "+i); + return -10; + } + i--; + } + } + + return ret; + } + + + private int uu_encode(byte[] data_out, byte[] data, int offset, int orig_size) { + //TODO + System.out.println("uu "+offset+" "+orig_size); + int new_size = 0; + int pos = offset; + while(pos < offset+orig_size) { + int line_length = offset + orig_size - pos; + int i = 0; + if(line_length > LINE_DATA_LENGTH_MAX) { + line_length = LINE_DATA_LENGTH_MAX; + } + data_out[new_size] = (byte) (line_length + UUENCODE_ADDED_VAL); + new_size++; + while (i < line_length) { + int triplet = 0; + for(int j = 0; j < 3; j++) { + System.out.println(String.format(Locale.getDefault(),"pos %d i %d j %d line_length %d",pos,i,j,line_length)); + triplet |= ((data[pos+i+j] & 0xFF) << (8 * (2-j))); + if(i+j >= line_length-1) + break; + } + for(int j = 0; j < 4; j++) { + data_out[new_size+j] = (byte)((triplet >> (6 * (3 - j))) & 0x3F); + data_out[new_size+j] += UUENCODE_ADDED_VAL; + } + i+=3; + new_size += 4; + } + pos += line_length; + data_out[new_size++] = '\r'; + data_out[new_size++] = '\n'; + } + return new_size; + } + + private int get_nb_blocks(int count) { + int lines; + int blocks; + lines = count / LINE_DATA_LENGTH; + if(count % LINE_DATA_LENGTH != 0) { + lines += 1; + } + blocks = lines / LINES_PER_BLOCK; + if(lines % LINES_PER_BLOCK != 0) { + blocks += 1; + } + return blocks; + } + + private boolean verifyChecksum(byte[] data, int cksum) { + int verif = byteArrayToInt(data,28); + return verif == cksum; + } + + private void setChecksum(byte[] data, int offset, int cksum) { + byte[] check = intToByteArray(cksum); + System.arraycopy(check,0,data,offset,4); + } + + private int calc_checksum(byte[] data, int offset, int datasize) { + int sum = 0; + for(int i = offset; i < offset+datasize; i++) { + int b = 0; + b |= (data[i] & 0xFF); + sum = sum + b; + } + return sum; + } + + private int calc_binary_checksum(byte[] data){ + int[] val = new int[7]; + val[0] = byteArrayToInt(data, 0); + val[1] = byteArrayToInt(data, 4); + val[2] = byteArrayToInt(data, 8); + val[3] = byteArrayToInt(data, 12); + val[4] = byteArrayToInt(data, 16); + val[5] = byteArrayToInt(data, 20); + val[6] = byteArrayToInt(data, 24); + + int sum = 0 - val[0] - val[1] - val[2] - val[3] - val[4] - val[5] - val[6]; + System.out.println("sum " + String.format("%08x", sum)); + return sum; + } + + private void fill_data_with_0(byte[] data, int offset, int flash_size) { + for (int i = offset; i < flash_size; i++) + data[i] = 0; + } + + private int copy_buffer(File file, byte[] data, int max_size) { + int sizeReaded; + int moreSize = 0; + try { + FileInputStream stream = new FileInputStream(file); + int count = stream.read(data, 0, max_size); + sizeReaded = count; + if (count == max_size) { + byte[] b = new byte[1]; + while (count > 0) { + count = stream.read(b, 0, 1); + if (count > 0) + moreSize += count; + } + } + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + if (sizeReaded == max_size && moreSize != 0) + return -moreSize; + return sizeReaded; + } + + private long calcWriteSize(int sector_size, int ram_buffer_size) { + long write_size = (sector_size < ram_buffer_size) ? sector_size : ram_buffer_size; + if (write_size >= 4096) { + write_size = 4096; + } else if (write_size >= 1024) { + write_size = 1024; + } else if (write_size >= 512) { + write_size = 512; + } else if (write_size >= 256) { + write_size = 256; + } else if (write_size >= 64) { + write_size = 64; + } else { + write_size = 0; + } + return write_size; + } + + private int byteArrayToInt(byte[] array, int offset) { int value = 0; - value |= (array[offset] & 0xff) << 24; - value |= (array[offset+1] & 0xff) << 16; - value |= (array[offset+2] & 0xff) << 8; - value |= (array[offset+3] & 0xff); + value |= (array[offset] & 0xff); + value |= (array[offset + 1] & 0xff) << 8; + value |= (array[offset + 2] & 0xff) << 16; + value |= (array[offset + 3] & 0xff) << 24; return value; } - private long byteArrayToLong(byte[] array, int offset){ - long value = 0; - value |= (array[offset] & 0xff) << 56; - value |= (array[offset+1] & 0xff) << 48; - value |= (array[offset+2] & 0xff) << 40; - value |= (array[offset+3] & 0xff) << 32; - value |= (array[offset+4] & 0xff) << 24; - value |= (array[offset+5] & 0xff) << 16; - value |= (array[offset+6] & 0xff) << 8; - value |= (array[offset+7] & 0xff); - return value; - }*/ + private byte[] intToByteArray(int value){ + byte[] output = new byte[4]; + output[0] = (byte)(value & 0xFF); + output[1] = (byte)((value >> 8) & 0xFF); + output[2] = (byte)((value >> 16) & 0xFF); + output[3] = (byte)((value >> 24) & 0xFF); + return output; + } } diff --git a/app/src/main/java/fr/mobdev/lpcprog/managers/NetworkManager.java b/app/src/main/java/fr/mobdev/lpcprog/managers/NetworkManager.java index 7477284..44dcd80 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/managers/NetworkManager.java +++ b/app/src/main/java/fr/mobdev/lpcprog/managers/NetworkManager.java @@ -7,7 +7,6 @@ import android.net.NetworkInfo; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -15,11 +14,11 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import fr.mobdev.lpcprog.R; +import fr.mobdev.lpcprog.listener.DownloadListener; import fr.mobdev.lpcprog.listener.NetworkListener; import fr.mobdev.lpcprog.objects.Binary; import fr.mobdev.lpcprog.objects.Server; @@ -29,14 +28,14 @@ public class NetworkManager { private NetworkListener listener; private static NetworkManager instance; private Context context; - private boolean isCanceled; private boolean downloadInProgress; + private List cancelList; private NetworkManager(NetworkListener listener, Context context) { this.listener = listener; this.context = context; - this.isCanceled = false; + cancelList = new ArrayList<>(); } public static NetworkManager getInstance(NetworkListener listener, Context context){ @@ -70,17 +69,17 @@ public class NetworkManager { listener.onError(context.getString(R.string.network_error)); } - public void retrieveBinary(final Server server, final Binary binary){ + public void retrieveBinary(final Server server, final Binary binary, final DownloadListener downloadListener){ if(isConnectedToInternet(context)){ new Thread(new Runnable() { @Override public void run() { - getBinary(server, binary); + getBinary(server, binary,downloadListener); } }).start(); } else - listener.onError(context.getString(R.string.network_error)); + this.listener.onError(context.getString(R.string.network_error)); } private void getBinariesList(){ @@ -94,7 +93,7 @@ public class NetworkManager { } listener.startBinaries(); - + List serverInError = new ArrayList<>(); for(Server server : serversAvailable) { listener.startServer(server); try { @@ -106,20 +105,27 @@ public class NetworkManager { InputStreamReader isr = new InputStreamReader(stream); BufferedReader reader = new BufferedReader(isr); String line = reader.readLine(); + System.out.println("Browse binaries"); while(line != null){ Binary b = parseLine(line); - if(b != null) + System.out.println("Found a binary "+b.name); + if(b != null && !server.contains(b)) { server.addBinary(b); + DatabaseManager.getInstance(context).addBinary(server,b); + } line = reader.readLine(); } } } catch (IOException e) { e.printStackTrace(); DatabaseManager.getInstance(context).serverFail(server); + serverInError.add(server); } finally { listener.endServer(server); } } + if(serverInError.containsAll(servers)) + listener.onError(context.getString(R.string.all_server_error)); listener.endBinaries(); } @@ -138,10 +144,13 @@ public class NetworkManager { b.path = line.substring(0,line.indexOf(";")); line = line.substring(line.indexOf(";")+1); b.sha1 = line.substring(0,line.indexOf(";")); + b.isDownloaded = false; + b.isDownloading = false; + b.progress = 0; return b; } - private void getBinary(Server server, Binary binary){ + private void getBinary(Server server, Binary binary, DownloadListener downloadListener){ try { URL url = new URL(server.url.toString() + binary.path + binary.filename); downloadInProgress = true; @@ -149,9 +158,8 @@ public class NetworkManager { connection.setDoInput(true); InputStream stream = connection.getInputStream(); File file = new File(context.getApplicationInfo().dataDir+"/"+server.id+"/"+binary.path+binary.filename); - file.getParentFile().mkdirs(); - if (!file.createNewFile() && !file.canWrite()){ - listener.downloadError(server,binary,context.getString(R.string.cant_create_file)); + if ((!file.getParentFile().exists() && !file.getParentFile().mkdirs()) || !file.createNewFile() && !file.canWrite()){ + downloadListener.downloadError(server,binary,context.getString(R.string.cant_create_file)); return; } FileOutputStream output = new FileOutputStream(file); @@ -161,34 +169,35 @@ public class NetworkManager { long totalSizeReaded = 0; int sizeReaded ; while((sizeReaded = stream.read(data)) != -1){ - if(isCanceled) { - isCanceled = false; + if(cancelList.contains(binary)) { downloadInProgress = false; - listener.downloadCanceled(server,binary); + downloadListener.downloadCanceled(server,binary); stream.close(); output.close(); cleanupFile(server,binary); + cancelList.remove(binary); return; } totalSizeReaded += sizeReaded; if(fileLength > 0){ - listener.progress(server,binary, (int) totalSizeReaded * 100 / fileLength); + downloadListener.progress(server,binary, (int) totalSizeReaded * 100 / fileLength); } output.write(data,0,sizeReaded); } output.close(); if(checkFileSha1(server,binary)) - listener.downloadSuccessful(server,binary); + downloadListener.downloadSuccessful(server,binary); else - listener.downloadError(server,binary,context.getString(R.string.sha1_error)); + downloadListener.downloadError(server,binary,context.getString(R.string.sha1_error)); } }catch (IOException e) { e.printStackTrace(); cleanupFile(server,binary); - listener.downloadFailed(server,binary); + DatabaseManager.getInstance(context).serverFail(server); + downloadListener.downloadError(server,binary, context.getString(R.string.unknown_error)); } downloadInProgress = false; - isCanceled = false; + cancelList.remove(binary); } public boolean checkFileSha1(Server server, Binary binary){ @@ -218,9 +227,9 @@ public class NetworkManager { return f.delete(); } - public void cancelDownload(){ + public void cancelDownload(Binary binary){ if(downloadInProgress) - isCanceled = true; + cancelList.add(binary); } private boolean isConnectedToInternet(Context context) diff --git a/app/src/main/java/fr/mobdev/lpcprog/objects/Binary.java b/app/src/main/java/fr/mobdev/lpcprog/objects/Binary.java index dfa20c7..5a5bb8e 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/objects/Binary.java +++ b/app/src/main/java/fr/mobdev/lpcprog/objects/Binary.java @@ -7,4 +7,35 @@ public class Binary { public int version; public String path; public String sha1; + public boolean isDownloaded; + public boolean isDownloading; + public int progress = 0; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Binary binary = (Binary) o; + + if (version != binary.version) { + System.out.println("version"); + return false; + } + if (!name.equals(binary.name)){ + System.out.println("name"); + return false; + } + if (!filename.equals(binary.filename)) { + System.out.println("filename"); + return false; + } + if (!path.equals(binary.path)) { + System.out.println("path"); + return false; + } + System.out.println("sha1 "+sha1.equals(binary.sha1)); + return sha1.equals(binary.sha1); + + } } diff --git a/app/src/main/java/fr/mobdev/lpcprog/objects/Parts.java b/app/src/main/java/fr/mobdev/lpcprog/objects/Parts.java new file mode 100644 index 0000000..b857a3f --- /dev/null +++ b/app/src/main/java/fr/mobdev/lpcprog/objects/Parts.java @@ -0,0 +1,16 @@ +package fr.mobdev.lpcprog.objects; + +public class Parts { + public long id; + public long part_id; + public String part_name; + public int flash_base_addr; + public int flash_size; + public int flash_nb_sectors; + public int reset_vector_offset; + public int ram_base_addr; + public int ram_size; + public int ram_buffer_offset; + public int ram_buffer_size; + public boolean uuencode; +} diff --git a/app/src/main/java/fr/mobdev/lpcprog/objects/Server.java b/app/src/main/java/fr/mobdev/lpcprog/objects/Server.java index 6e54ecf..1993d73 100644 --- a/app/src/main/java/fr/mobdev/lpcprog/objects/Server.java +++ b/app/src/main/java/fr/mobdev/lpcprog/objects/Server.java @@ -9,9 +9,16 @@ public class Server { public URL url; public boolean isActive; public int attempted; - public List binaries = new ArrayList<>(); + public List binaries; public void addBinary(Binary b) { binaries.add(b); } + + public boolean contains(Binary b) { + for(Binary binary : binaries){ + System.out.println("Binary equals?"+b.name+" "+b.equals(binary)); + } + return binaries.contains(b); + } } diff --git a/app/src/main/res/drawable-hdpi/cancel.png b/app/src/main/res/drawable-hdpi/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..60f86de1ad911b42ad07f96d983439673a9edf78 GIT binary patch literal 931 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|a~99A-3SHc-`Ze9DGLE@!9dNX(hjG)vh#u8!|)MDe193zsSJv!uKGIv?(g?+={yaklZH04ulaE5TZTCKFXwLX9$I;Go7N28 zwharH6?nY2T$=Z>-1Wudpobb>mHJcP7Zkm2*L~>G{m#-sven~#X5ge1HX4SX`1~h& z&0Kou%q7VU&x6dI*bA@Kr0712nUo%~!C3y`BuSN-)~9Bi*JQh1VmQewl8skHZ*h^q z#3;7Xh0~T6)jXb~9c{O1U(J(TXUQwMcMSIGEA3sI62QK4Q$pibo>yk)LbTLRE)bhE z&wFwzP&B0IWG7G7tR))LZ~GpY31t1*IBCk2r9g##i@rBDKj)6qUy^u;ue|=H$ft?l z6q>C()B-=vpQJ4RmLcR_`<7rA%{gnEb*9Rt1YCY5qw7WC@OU{#om*XQ9CQOFEk0-i6LmKN`2! zYxj~Hv%@pzi&THqTCRHZ+}=|!JvRogzvLVA=FIAn=e$-QweD)2Oj&gO*Wi5Dq0_TLF!R?b?# zNNa0Fd&|?UMJIZJo?O>|PkmZ!tq;#rtLN`seU0z^t9HEnEAGM-r><2`xEE=6Wh=S{ znEl{Cxbd9Kl6{d5z(lKB;u=wsl30>zm0Xkxq!^4049#>6OmvM*LX3>9j7+Tz473f5 qfaFTnV+|-8a`RI%(<;$5m{^%wLNvU36t@+qfx*+&&t;ucLK6VF*_Ipt literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/chip.png b/app/src/main/res/drawable-hdpi/chip.png new file mode 100644 index 0000000000000000000000000000000000000000..4f3f58640db31e8d6eb7a332fca6aaf7f41f5588 GIT binary patch literal 1146 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4O z;1OBOz`!jG!i)^F=12eq*-JcqUD+S73JdYe8NHk^k%58P!_&nvB;(%OS?9Bb9Yv1Y z&-Trgj*b@2>D_Wgt1&3*!~PE{qOSaLdnz`vub11?5%5KaP+(XdBI43ynDUx~QL`@`}U%A$GNy=bJU}2rmnin))J&+ zsB@^Q&Ao9+U!j->mn>Ux%_n7%)QB#@Du$C+-KLkwBwhGwmy*vhbK@W zQ{vv13X9U1$#bd{CS2Kgl6QLWZ=qG6BBjoj&GD;Um|a)1n@4e>u=|PESCa3P-zsI( zZVZtXOzMl9%{5Jaq2RNntCCF@T=_UfaN`xD&+lxnA5y%3DDT&V`w6yYwJ{S{_09PG zT8v}wqrFa&OStqG+N`(KJybO>Xz`Ve&&03aYO7y2>#1xfU-qA)rFsSmJ$ue?+I{~1 zq4;atIK9@${4KqHbm4>mj}@^$-WyG}nI*!SD_AAH{lwi%$BIoq{Y#8{nsqR(LuEl= z>SfD(`O>WhUNX|XN|NW5YS)WhDVS}NxoMA}?GmeHk*dyZq03ZXCU07D@?(r|Yg9r{ z=aPzZsW;`$6^p$n{krj-0h2;#g6~35B$vossmYLMzM#3A&qd5t$>CzD#M({Go*{4T z0>8R8u?RDSL`o=I&2$Y+bqy^;j0~&{ sjjc>9wGE7{3=Cv0=Pg0ekei>9nO2EgLvG(SP;O`NboFyt=akR{09UZj2><{9 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/delete.png b/app/src/main/res/drawable-hdpi/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..989fc24ae7a0cb4fa0cb72f741cacf7c81096749 GIT binary patch literal 640 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|a~F`axiMCIbUwv8Rh;NXEUlH|@O-J4hV= zm_PZNy#|M#(-Bv7*82^4zxZTo*|+5%ym@roNdvdpDh)niuuGtw6%~*RiK(8wxl=|HV#{JIf_K z;g`8`zKq<>#rd1IgkDl#d^Ti~x!tzv$(i@#zsm_tXaE|rN?C!C)59Uu-GK=xu&NIz zrob2~3ld{mWmV55GOc9i1^1baRxC>!-c8nfH_5?{U$sDF`kvX1Rx&E4*A48JKkK$V zr+a^D=}n!od8+4rY&cfA%yV%@x9zr%FBftJI?c04;Wb|yGwpQ&dw*)0grVIOr3Y=< z_qxj5ndWa&ad2PPYF`435!Djch?11Vl2ohYqEsNoU}RuurfXoLYh)5)WNc+(YGq)k oZD3?&VDS7ndpU}R-29Zxv`X9>rp?-a8mNK6)78&qol`;+0P2hJ1ONa4 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/download.png b/app/src/main/res/drawable-hdpi/download.png new file mode 100644 index 0000000000000000000000000000000000000000..c5561348dc4884e67818b8778a2c88ee4f1098fc GIT binary patch literal 749 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|a~9AK!9g0|Nu&15X#nkc@k8Z|?Uy6d-c^ zqkdN>&!_Oky9>)p4Gq=odN%VX{^$?-Vt8jx4U2I3W9E!UKKY>q839uk**^Ve`0U?} zSw+8JTCxY}eKm&K+aA1OpOz;2(}h(fKUED+6xf_- z2BMhbAkyYUsf~wyM$U(vN%Eh}EteRiuN16aG~bV18lnuOU2S_DrZ?68Fv$StnWKhYbv**5tWMnI7Mun6VJkrv=wPV7yM`vgGWiC9XX;o!e z__#{avuobIG~eZ3{T^pJeF`6Gm9~Zkm7FbPIJM}Q=B_Hc7xv*VZB#uA)3#Yn4tcqJ z#?lVEP-&S4sptDAh@^kB_z?Ygjp=Lc%(%x&zrI;An6hy$>0mS!mudJa8FZwfGdxE}kx(%P^EMZ=I;{U(%Gp62j{+|$iqgh5hbH(ukvs<(E)oXXE zG_I>mN@3h`WNqu}A3t`Sv%Wp|;2D9q^=p99uUg_7QIe8al4_M)lnSI6j0_CTbPY^& zjZ8v}46O{ztc*>x4UDV|3>Xdt{Y24_o1c=IR*73f;rv&wKn)C@u6{1-oD!M@K zKXOykdk}F=Fa3}Qi+IBkZ9Vso|5aIQ7S;+03a*{&d;V-`|NeFVMKO)N;7#NwR$SOEAFr>0`2q-w*WMpFD2q=RKFOq(r8XKxwabWd4 zSHr?bDoTs4{$_Zn#9wJ=6!H(~Ak`Arh?11Vl2ohYqEsNoU}RuurfXoLYh)5)WNc+* rWMyKYZD3?&U~qo&Wo8r&x%nxXX_dG&>^qkY3K|AaS3j3^P6NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`q0KcVYP7-hXC4kjGiz z5n0T@z%2~Ij105pNB{-dOFVsD*&nb-h-xv18BLkZz`$7I>Eaj?aro>E?@3JtBCh_b z(HFF0<}e=Lp#IWvvw4D&?KMCCEfd!N3^zUF@P7CEjHh>5=3Vb>6Y}iw4!T${%g!q3 zv-fF9K^^^o5}O@G6{qVzIxKz}&=~7cWMwjo-PFCIXO{J^(()AzdPg+YU%az(lB4lN zer?4QFVmySr8F|r`D-0d&iwuSZcvlU+PEF%ie^u&&-pJ_+HpkcoKxcZ7Fms*FY6Ku zq(ky9w%(XH{Wbrp(Aj$hrwH~<7dN-~x8M%1Wn)oO^0%q_HI|1B>npiVardqKTc`7o z_c+^>8>R2}IOH{J?Pxh@*eE5DwBtXE)}lXhD>w>#7AWnkpT6V6=1KAzIZqZ_{J7pB z^#4TX|7Fnyd3Tbg-iX%fvhY6oZ<3f?k%8`sgQ{mPYiYRO^woYZlWM^cDASUi`Nu|M4U5xw&KH_&xYK3ygm{`ahQ7*uW1bRoIqyiYoNCW< z(e^FviW5FqJm!C8<`)MX5lF!N|bSOxM6f*T^Kq$k@ur x)XKm>+rS7&u4FydfTAHcKP5A*5?zCdm8m5}!>dPeTY(xFJYD@<);T3K0RU97^KSqE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/chip.png b/app/src/main/res/drawable-mdpi/chip.png new file mode 100644 index 0000000000000000000000000000000000000000..5365405c3f28120d7be576d5b96b4c2022bbea11 GIT binary patch literal 946 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`q0KcVS>y)vIg-4nJa0`PlBg3pY5H=O_6MxOLi}<@FDFa{YHILwaSVw#{Pz06>=1Vu_7CT0 z=d4=puxp!W%LHeBwrty|E6vk|R?B^PbkzG`G+&g>SN{)FlJ)-bvs_%{c_e6-^OU$y z6D}?96%)FoJ}fz#7RT>b7H>9t`^VN59rsgj{yl5+%=+`(_kZr?|LEcGUE^LK;2iu$ z=%W7Q=v!x4{C4G?%INBwZT7aJi_K?8;vt8d3|r+`4!ad6fjBe*FFBC&Cgga%CQ$-wsp+go%||p#+RtJWtIPPTOLG**UX(G zklPe< zc+RqnjT!eGpTCVNzf?JKLA#50oo}_llN{B~UuSmdb38M>F7!d`Z(VR^g%Q8)i=01G z&N&ub*`V=j``2St<}S*7+)ZsOx0R0bQas8-SGt;!F$i%6>=eOoW>Bj0? zKbx{3?byz#RqMkare3V@+%-?LZKq>3tI4gOJ2Ecc|D)M8Pb~M>r5|qL6Cz8(11@Wb zS8ivmY(3vp%Xal@xA!~Ei`EZ&kDgoR|59el#V;`)l3OEW%BJ=0eCi}(lb^o8>{QqN zbDzpeKT7vnsC?dT-MJ|HV|3rH+eO>22HU7jm-fCW8TfAc*|(0%-pGaD+pXB-yZDcc z&djY30$EZzkxv|`NEM_g1t?{e3|7HlWMF8fYhbEtXc=N; uU}b1*Wn!sqU}R-rAagly35tf?{FKbJO57T9`>ug<34^DrpUXO@geCw)zmt*x literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/delete.png b/app/src/main/res/drawable-mdpi/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..30f9c71b93b74043efa9feb5b418bd206b2f2112 GIT binary patch literal 586 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`q0KcVYP7-hXC4kjGiz z5n0T@z%2~Ij105pNB{-dOFVsD*&nb-i0ZO_5Llkcz`$th>Eaj?aro_w-Cjo=MB4V> zWJx-;wIGpIKPUaEu+Fz%Dq?2)8qPn^?r7S&cWT1U6YHXHWGE_ih-t6hw6o`F+N6_K zGbLPRd=8iN`&_$rQ4!%nx8<{Dy3e>M#8`Xm zM9|VXo4h9M_I}xQYmqHq@!1y}w-tDCI^Q$WYYOM9n5F*1t7`h(F5WLU&h^>|r|CzV zh8@?CVqc*<>!V-PY5ym(S6ts+xcu&iR)eJSzFF_QGg%oFcW+tyN}y-QKg--!!%0V+ zCOuv>cfI454R>Q_ncx0j&nI($5rH0@XP9*3maY+_PvsW2JF^+=c5GPlu+e+-k<@dZ z;(zL1n_eR~c zsF)X1=L5r5wZt`|BqgyV)hf9t6-Y4{85o-B8kp!BnS>Y_TbYbP0l+XkKpA6V> literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/download.png b/app/src/main/res/drawable-mdpi/download.png new file mode 100644 index 0000000000000000000000000000000000000000..4aab51ddc50d39405fec41def5c12f0edb4635e9 GIT binary patch literal 617 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`q0KcVYP7-hXC4kjGiz z5n0T@z%2~Ij105pNB{-dOFVsD*&nb-h-&f2x7^skz`z*e>Eaj?aro^FTff5wA`SZ; zR;~Kd&TOzrLD5jbu!u?R2v_<8i6v+KEt!P0h1wI+8yNKthz7h7YgG(6BDzudxMaf~ zpL5;&&%Zx8aZbgIMeXZP>P5a-{(HuwImUKgMYHb|UJluCzEkaY(yV=nA|^e47dWjP z)mP{iEDqL~H_7TjlU?LPzhj2&Qa6EN@Qr2kadpKnE`g2Om zva(Rxu*NCm;PbAPuA-X3ZlT{DYh86~*3Gz@F(o04f4=srcN*F?rL78E4m0<3PKes0 zvg!DG5vR?+JpM<81|L!7a=armUwe|glxpllMm3e}P!6H;A5)#g!sZ(kcAgjgtlygQ zPHw*Tx`}TeGH&zixP6$JM`BCo|LF_oX>EI9oxpW(Kl>~92dc|;q#xD3+o>h|rs&Cn zrsalWD;UzXk}n#Wo)8tU}R-rz;Gz&CyIvL{FKbJO57R> T=f83VYGCkm^>bP0l+XkKvi9Ls literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/stop.png b/app/src/main/res/drawable-mdpi/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..f0d82847119047d1c50f213e336269dc6a777e42 GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`q0KcVYP7-hXC4kjGiz z5n0T@z%2~Ij105pNB{-dOFVsD*&nb-h-z`^ztgb?3PpRmIEF+VetX@J>wtm)>&5vq zs#TxFh28UhbdV)_^V@X^hL<%T3GbfTvF*LVYxniL9`9SSD*xV&GmX(Ve?Ixges1c0 zW}qohATV<-|E#WJhRoITeMIgtIEix{+cwSi0#H`9#5JNMC9x#cD!C{XNHG{07@FxC znCKdrgcuoH85vob7-$<9Ss56dpL`i)B0@uMeoAIqC2kG-&Sir<%;4$j=d#Wzp$P!> CJZmQa literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/cancel.png b/app/src/main/res/drawable-xhdpi/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..fa8742e0c42b6c5bc7fa5cf34b383f68edae0473 GIT binary patch literal 1069 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|a~99A-3SHUk5*f~SjPNX4zIcLIxU83;5y zl#gFNVdj#(4w*dsp6??27&!MbPuPB8vBdX1fdlK${Z1=A>2Dhdzu-v!t zQ72RO;s>pw{IT2bZd{mlTv_<7x>)j|CR@|&W!v*+fAVtmJv;Axo0GVx3^+tE)30z`({@1VT%Kfc#=i@7zx?HwP>hnIACLLZ=d0Vo-`lYkgnPQkMAu}^t34wlku2dk>jxI$YrjV+Ox%MeoeUb(L~Yqz$>?J=O>&xGGX20iJLbx zrI*b$zxGB$_}rmfn|Hysj*d4CL+4L;*6H-(*ySGwd}dT1oy|5$e%`U!mJ3aoPRjc~ zzMa7wly75Hmg~{{;e>#RBJVNf;svakB62g?c|8_?JR#tG8y!oxGY{ax>@8n6T*KM8zXbBBK3gf_XeHemoJ=+BSuy zpGQ$;NlHb^Ij{9|N}avB+@GE0zx3PJ<0R1ZV@^Rplg-&CNy*JTyl_GYP^irz=(uw6 zP4P*bKu`a2Flu&hd%&G}@)Dn1`41qIl5iGS^0+nC+*IP&;=?DLEH z%7w=^xH=jC^*Aif>FXf1-D3q`<{z%jT1yPH&ty$FwANs?16TAsk9++h`)np|k=OLA zREo3@+H)&R$fGbj`l8~|^|`LCQ@doWWlp*4g$-VfX;?ni2*jtwbhw@+RUlJb5 zf2n`T?Ma4Glj^*WX?U1L8L>HUx_sW4W0IX*`Ioj7=KeXYaTDTt9!ymH;Z*hQF3+qg z(fj6OhSx|t&B{q3=FgljDX}y)?*DQ8glbfGSe#2 bHJDhLT0%6udK9-6sDZ)L)z4*}Q$iB}o*Bfq literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/chip.png b/app/src/main/res/drawable-xhdpi/chip.png new file mode 100644 index 0000000000000000000000000000000000000000..433b810765de6002e044d48be8a94d03bb384637 GIT binary patch literal 1027 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4O z;1OBOz`!jG!i)^F=12eq*-JcqUD+S73JdYe8NHk^5vb{+r;B4q#jUrq{j-G~CEDk| z&C5D*Q0$<6hY0^$*M;u%Yu-Law@uHz%PB8=SX(q}&&(%(eT_cy<3Q z{j%?+q&V-5XWRXfcHKW9^L|EG&&P`oKQzD2Nz**=)FRk&DZjw6y8DJx>V&!(Zg+su zk?W0KDdkr;&P@wqCdjx=bJN^!GeT}{?5-|+yXCm@I*mx1WY2I1!8cnDAN3HEe-sz?%TfUtL^0N~ zn~rj-b}!r4pmgJmtXE zY9o3dlP8~jh#h!}}|uzBQmJLZI~v9h)7@BEN+5;tEaDU|IJfduN5xQ0AgjvL2M ze!TH?-@5b0)<0(b%XnRIUi{cJ?YGVA)wVB?dCd5^`SIcJmKXY}bc#9|W+cq6{$q6F zP{SAVnIS9qlcarSs|5b?)PW@eHEW~!s$p!~g@17_vW?qtZ#{E7_l8aiAhqkfIcz zlvOfV1%r`+p_#6Msji`Ah>?Mnp|O>TrM7{Qm4SiG<-8>*8glbfGSez?Ysl@p2Fi8} Mp00i_>zopr09&f1(EtDd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/delete.png b/app/src/main/res/drawable-xhdpi/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..e154951f52f00c356835b3a0d57b5cd960d978d0 GIT binary patch literal 760 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|a~F`axiMCIbWGYfl%)kcwMxXK(b936yX< zzvAK%2dTsBa#@nsYpO&<{$`jY?lIkb!-h-l0iILM)^cQC5fIzxp|q&AwL{VIsF&;Y zyQS$t9=9I$RnO%=Tb^fmX72kt_2uu+7}-l)7WAAF$u@JDQ`m!^>}fw&PW$iP+HZ1# zt9MHNo{Azz#tIG2e>~0>#=X@oT zCZ)^9+CR3QowCzjjrWxFU7MAq>fMD>)>nTlZ zCq0_~VV?R&R-t2&3ro*G3@)p5kFQvxbk=r%!iEBT7;dOH!?pi&B9UgOP!u znXZ9}u8~QIk+GGDsg;4Dwtq$qWRIr9dq^n%4nj4R(H{^>c+nJAyb%q3vGV8NW}u09VHd~?*cJ-;{e zzS#f5*)wa7TNN&u&8e|zO3(WX4|u2cTxY9!w0z3}ZoA?+A8*C)d9?cGc718?DHRib z>ZN`*|8O88A+Lr#kufpEK}vLj8|#ul#!T$Y9FC58XP3^;vU?;sb?f72Hl`Nwx}PU4 z-uis8D$~A)`Pu=GO!HS3Y<~8wT_#nm;!MZ=?0wG~8W`_yzO&D(y<_JG?M2R}udPdZ zoE5C>51jmSy*;{>Z{LlY`F%J4xO&7coS?Mp=3~#ICT|Ua{?nbkKe<_#KbTOn>)SKt zD+OFUnuivq727#XjdN6N{qknZ{#6geJ}i9oS#kbPhSEE8oVyC%9-qAAn8NW1PQQNc z{awHE(rL{l3hTd3UwK)5o1OhK_q`oI8BE)z)r&c`{oJ;HmB9vyAcy@oelqZ~O>^p! zyr5BK=P-9;>jb4^N4ElHO?WgDG|c4}oIIhhWQL;eNuWA4N$0K|6Ef>V6X!hKUVOmA zY@Ukmu`}Cd*(dABpO0nD@1CHv=Wd6(XLC2NGgtZ2zo}6^W*nKvTBd!uQqp?bRDPA= z<-1w+Gu7_dDz^HRRogj8>#Hu2l*@ftIs3w+$M#NLJ8#|n7B0HX8z}uf-R^*}p0MKC z8SmU}Ja5I^ZxborTmM;{E8NB9_mzJ}%PT78c%3&`721^JNY1UiRX2C(*(>VXAaOfuulSDl6FndPziKA>RdP`(kYX@0Ff`LOFwr$K2{AIZ tGBUCXS6dnZv9RjTIWe_M(0R&og27wS+ zAdtZQ+*S(>K)~Q)Y@i4F_bhR!6QEe{8`}GWKP z(A3_kWFH27Z+<5)ASQNY_ZXe$ju@=Yra>#MUv%tlz`C!6bRjeB>O)`7+$j`O98JuY zFpBXp(h;*A_@w{h<584_@>ToB$6lZ2S_ElB{`ssfy^}OKb1M5G^?Hf8$^E$cA&bJi z)9*A&$Cmr>qn>z-oZkyrk+!_jygg?759@s6C6mqbnc3R9WtlpNAiWL>Sy=d(QEN_9 z5?!zjSxW%hZ>2reBAvZVQWn@Z&_`c;O&JEQy-|Kq`I|X0|4x2=!pEldTCF*~fx5uu zrPZsF>SUN1ecQY&o)?mcDF>y~Z zYJ}k$%W=8Kjznf~V!*d00=!42?paV3L19=(%l$3kKZvHp$|9?9qq%6v=Inh!FiG9= zkrLwDj+hG->l(*C)Ttl!G;R!;aysWtR)K=BsB4OUu4`SyFbIN5X>*C5ewm|9P#A>C z-RB|xz!vQ&=*6y6r`8iEm$~JXMy)?4Dl+Wek@(l3fyc`@GNu}@ERf|f zwdr+POIDIXb+#EA7Pt~IVgx~1w%z$H8{ICLdXx~K>vv)uF=OvBB&OkH| z6qWn@(~aZaAH>$WFC+<%tfi7Pr5p1X{|y!d+#I-ZC&p|LoSKk|!#a<0j(xU@<@h&Z zdVbYx<**D@d!*Zzo9$TK0>;~-iMpVj~v`H7f=c#E~J33Nkk)CAp z3k=IHo1#sd%k^>+UDmHiBv>4nY~Lf^?n1k@LyQ1h4bcjXUQzjWb6CbxaT+wyU~$M7I0Y*&Zk6u6t-9r@rx`y_Ib+h z2K4G+p`w1-e2f)GBZ%IYHSeT#$Lv8a!|X;d-||p}ZwZ3>(>+7rWsD{sX6BCqk3Df^ zM$|*{Y8iHSm(yd~i#d2WW$BHIeaI2GoTlpR64$g_Ipw$n|4g7p0E%q>WTq!rm}z+# zvwk`?_a-Rd6#v`dz{;;Lh*x-Pn#m#t(EkW$k|g^bj=%n6u!@4sEbv&R(9#AsV9j~>E$Bb6ntZyQ?Ztk0@T*cx zb-X&7`3w&7v27Hp599`B`<7gkxA(f;-#SF)hJ=pM-Tq4fDQx?dU~qtk_cvEh;-4c5 z+wxG|HKDYDWax*pPUAIS43g8s0l20P`RjwnG#6i~jAgscHo%4N1P`*dN?@uBU=Q9f zg8;0SLKC$?-+ZuzO60*wn6q!rMHKa;r$;24eL;0ZZ`Pv5za2@`0-EbUwZpmmprETF z*Qc(RpS-*?F2#y#@1;CxKLN$k-4yG4){9{+!^4Z(wzz>2YnMC@zVY$foF#%7vMTi) zsv=A)spLTg!|1-I>i*Q=B*zGzd7##Wpv*d$_sb>2sZOg49R(ZNkU6E@+{@SDOgR|* zLGlFSpmRVp$Z?jFyRKlnBmPe(Hn8C5bgfZ{YQ{U$%z@;K9~1$P1q%xz%W9-jte0d{ ztsh!DQ-sE{7bYaZxNAeG9`x+bs7%$G=Kmn_#cZSdy(hB2A;6LA#(~Rq$2>hmG$Puk zJlk+j`aH}cMy_OwzV1d>e-aY{<5p=$zl%115w=ICf5cc7R%#lyIN3?*W_uw@FuvA` zbd@;LHJjx1x2w#{Ln%*;bqIV9OpJQaQuS=Kqnnf<4~GEu0QW&*S?B62oH&FN$5|_Q zgmOITYbMj!=kxh(MjBG_BQ-mwov0K#swY3svrUvQs5`K#{<3d9q!<8neUHeu6me)4 zCZ3O#S}%Fv(iU^>32rGu*%r99(s`+?1wMyAQmNKiAp!WlpCBAUOj)&oa5C&}C47`o zH(jVa6$@U2TBp8Q$@qyqHw+qF%j8~aR*e|YqYbx?n%=7fWQ>+Xp3%WV zr6SO-C4DMxo2*acG632-l0g?#W%am%rPEMWkjJDR8|y9ANn5vaOfM!`2f*y{GA zy_$78oN>{ojSJCE-{SP9AVORMSYxViZvDwa}sh(|* zwkABqf0QaoXK#!f!r%I?NhSh{gVo4Ow7sU2o3Q+c&b-3LRY&%NzkgK;N1lkHOs2e5w?hCk= zl%4;&wUofjJ!a>Y!#$`L7A2_Y^%SB zv%DkVA@8RGiP{@WXL`o5s*~x&6a5dKzO<8bKe4^3cL%P5z60;gM09@aP^-8%j{U9tLZOXzO-v zX!UHfKk30H6?mJNeH$t~Lyn963pOk}WZoOuD0kFaib#z*jIjqYV^37m3GiZtk#$QQ z2vH6)OBZ~%!qr-%qE>8!q^%kD9^9_wxkc2yp+7K}kO{YKhyHQTOg_E(2bWn|UVn{qWJ_#;MsJ8v%T# zx{LV8x(xjwxT~UQvyR8_Z)Vfn(TDj03P2(s!U|DnGnKicj^WRtLV#Cc1vy7tq8vte zm)?UXKR34eJsTPGDxZy;Xe6!gdY;RgWQ$r@Zj>0G#tdZ5O?k#JNHi1u4%Sz=7fnP%*6guI z*m4b;53gN@&3+;`@4RtYC6G&O<0PEdPcgDN z`|=JSY9*2MpS@K4^wA040NX<)i;W28cRUCDHDEw5A~n5si12g zyh-x7)mqb-D#V88LH|zRc!F(niT$Ik*KMr-SuHG&b-plNb_`N|3!0y*2!xd;h-Yb``rfXub@qn5%822JF z%9g9WmxKDz>-|JfB9sS>C{AIO$4fjVO_?IN$B7e=^%iNM@)?8azZLq=kiA#idRA^? z@q0RVX-AOYJg$A*-(Ph3dmb#O%q~@XuztEN_+t|Q|0U2Xz zlD{3d+f`;%Z3b#TTonhdmrLx^^N$c%Z_9Z>1E=Bfhz8Q1*LS(Etuqcg555sjojazHi=qKVaZ-?^rpQMoaPIWH%u+RdW2Tn#E(AfXzMF9n+U z_jA66*x)Q!ozwew6ts(0n0W4ELoV>t?0vYI+d0Irw;vU~s=GKl!p=_-@@B(c)l&nDi03m#MDx_?B4IOXN(CJ32WXWZoW(c<8*hdoFlMD z1dn_7zDC1;df&J(a_(2K2;LVN8Ft0}u*nrdM^{Ir9GjXwm<; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/chip.png b/app/src/main/res/drawable-xxhdpi/chip.png new file mode 100644 index 0000000000000000000000000000000000000000..983a92a070856f154529667d3ec4ad1930d0dc7c GIT binary patch literal 1568 zcmeAS@N?(olHy`uVBq!ia0vp^TR@nD1xQXma&9M(Vo7)Ob!1@J*w6hZkrl{SNcITw zWnidMV_;}#VPN%5ePS z`49Y%}v9KAx= zj97xUmaGa`>GjWii=Di%bIrNx{x6@ZxBdQ|a{A}HpS7vh-|qfoN<#+BD^D1`%1nFt z?M{Db-J`mMxsuPazi&%wjGnl0ndRY#+-u=G=cPVNiVwPY_jB;ZGbIIcxl5|9y}b0$ zsbtONoG+4ZnZHgsE>|ba9uQEkx721k-?u;7e0$QGqjtVOu=vnISDC0I*ojYXLT){k zmwWTmced=R2Ue=Lx3;@ZH?j&lY36!<+ily$+)r+aHt3x}e0TO9U~gs^zK0b0%;354Pn+{;3<5 zw%MIrdLVJG?zF4!Q`>##eYR?IpB`!V=*7O%+IkzOY*K9JTU{}$+)^x}&Qf>Fe~GS? zIv4-Xb8^;9%D!{j?DCm~_aAJ2=EugRb>o3=-C2;p@yZypuuyAO|C8%40^Ky}*QJYz z+8-KItC#rY*@&!Mxc);{LgvZ$k?{=e4p}dD-|4-R6ykh8xwW%)dRWeq++*{34&Pey zA?m}EyKA@bT9){<@1K36=YDC2#g-1|Zk)uDcY9|)3;`PK^s4TrVzA-Snu7S>S6?hW z)cEDX=bFv$H#O;=+c;zQ$%QYBj$fDIj%j<5yU+J#K-LSTinG%$)-h(WJ_}zOcQJX3 zFt0$nSYd`BoS1m!`^AOXQeumO=M=yEw)fMM`c+$cm$bz_SbN~oq^p9pd0Qf$&OPD& zL1pE_d{_I6{m*umvu4NSB{?ttX(8i)KT=j!zdy!2eRpHm*(-lH^{={eA^oRG!KxE{ z;*sZUryiUp^@}r(E3WVD#yi56CX@FF+__$7`%Aa-Kzv}IrsY9?pLe_WJhI*AeRG2I z@hvlX;`($qE&vCV$Fu2uzjIFM9p5(dYn97P=l>@pZ$_wIH#%oh{Njgbi(6~_V%H$~ zi{?MIfblZjdged*&lfy+_a6B@F}mm3Ot0RL?9(=gng5)i+!+05(l%fc(B5%Y+&AY$ zJrC|2fR;68Ssx18=uy4oUwYW=qtDL$%KLPqR68^Kul`0M`z^QY_uiQCS1&V2#lC;_ zGrz@`=Bs?rIe%R({*(0WiC>q^c>Vcy=ryL-Js*{XZ5NCFIm-KUjq#2Xe6y?Tw*8nq z`Qq1eo9}JDr}lad|GLj2-CHk~{j@p0<*WO_{x3hv98T41<{C%t4wZ~tpRnkBhWp6_ z@2y+i+mmZ7t=+O;p{mz^_+-@RRw`{3)S z{^Dus)o$5^&8k1woIQgC*skvXAM#cDNPxp}U|}d(;u=xnoS&PUnpeW$T$GwvlA5AW zo>`Ki;O^-g5Z=fq4pgKHQj`LevPuT4U@$T;G}ARO)ityXF*2|+G`2Fa)HX1(GBA+2 goVNr;LvDUbW?Cg~4Y_^SKxHz6r>mdKI;Vst01Cs|od5s; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/delete.png b/app/src/main/res/drawable-xxhdpi/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..4c55c644f76343cdcb8afe2d462a2a84d6d736b5 GIT binary patch literal 1484 zcmeAS@N?(olHy`uVBq!ia0vp^TR@nD1xQXma&9M(Vo7)Ob!1@J*w6hZkrl{SNcITw zWnidMV_;}#VPNj#15nLrEod%8G=RNQ)d>uk16D#P)Q z@83LI>$!6Fu_bD~y$b@ChVnbvRtO625s401&lTsog+9& zJNd_?C0jFvgC?6~n$Mnockb6mv1Q+9-Z$R;x3*|r`m>+s-t1vJ0|X+IZb&;!47NG0 z(d*;p|8utXnd9?PYHH^^34V9s#EbREOwSn#{%_E7i>*FXX!peA@yxXg4`@sl*?BJR z%1k%DzfA87XKnQ9-`9KAtIW;eddxwvhUnyY!H>07=>EC{F^qNZ{Zm~>E|!&>YnLdn;pAm`AgBSMu!5V z7e2QC#&3Az*d^As=%2PG@>UBuCe7ZoMkV*%t7*^fojhpO<=kztr2`LP@_$xIdvxyJ zAMZ03@ z2leU>tqI~Z^yzT#KfLE;!4sKC&!5fjS8lZr=(wPI??K@ti~r?wR<=y(jyd7|qHbQ2 zR@vk;XWA1?2K39QXjg|E;t^3Q=`H=X_}K}+nP>mVT>P!m zdh7kp%?G{eoZf%1=2v1rd5X*YlW^7S%y+JQlcvs&;V)juFIY9*GOzsM(+!R@EAyVI zmz=T+kL;PFy2tABnIK-{h#BnDti)&b%}|jJ)%)PR;^3hcznKq>xMRQG2zsbxzfmS@ zN791AtT%=SJbx*ta^_DwzthL^O2I;>!&=ccXEUZRiF?Ry_bhJ*jnHcm&jjbacyUE@cFn=cXDeD|%yK4aZNI_bCG+M&zPV`H&spn# z=zb}7e388VSiH`K!;HUPzFncb`=H)`gR|x}$C7@SzlmHD@tDi_il(8<f&OEPGIU7&$ru~>&Ic>-BI5X{2 zpFCbKJR&08Q_#U!Ra6nO{LSXWV&##K%%-lZdSGO1yt)0#{w>a&^&EHZp97X|swJ)w zB`Jv|saDBFsX&Us$iUD{*T6*A$Rxzb*viDz%D_UftDnm{r-UW|__3A3 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/download.png b/app/src/main/res/drawable-xxhdpi/download.png new file mode 100644 index 0000000000000000000000000000000000000000..ebc6ff47aed7d175582667a60d9296c55c0bea6f GIT binary patch literal 2247 zcmc&#c{J2*8~#O+ZFt8RBOxzC4aV38gR;zEgbzhCB3Z^Dnue)pCR?(WC3|`K4AJ7X zrG&;dvSlrArXpi$RJO7cdZ%-~f8Ia7bH4w+bME`O&V4=Sy3c*?^E~HDa&okh5IrOc z0DuJE7VE;tx?g#4KmW|_7--r=0PyuZ0ATU}K=x8Wqq8ahLcr&w4Ho#Bkk;42uS71{62kyMO!`;u1MU{U_@pom z?|>8L?uW@BB)#G|)qJKAkF_`*{(j+)@l*1natTV4+;jj(h?b~nGcsg-UMMagdsR*My77~f^VIuS50r_!}hz<*9*KOEleth*4(R!ToG5j zm)HCINHK2lTLyALKJam_&R}ZcXK3S=h@5Hh+k!Sag&-2c# zQscw#(GEWPuz9S@>S$dNJt_f>h#7p-E~e;fqtSR%e`z_)CFVp)4l~6Wh5Tgvo1dzNNxCuY_tztvsgmcru7S!nmxi8^Cf&|L8AmmkVbBKrhnpZ8enEil5E zX1#>0z;dr0`Ju9-)J!Um6O5!9{P;$P^wjoCsi(#T-K&CmD?WZV0xr#dTGOr5njR>Y zFZWXyfgVu&TFkf|fz%tcPWN_44I|M|(Dec-#ZNuXGZYUWkOn8f zDBN7br>5KY0yBQi^^N?@6?6OPUso1Tx0c-#JNQTfG{ztp;f%0UjCCUyk0x*g-0r$CTP0f&gI zHJ`1hZ6yrx+vVALB+pzj!d+#u&t+&gbZB1iUc3gmGOlsHrU$i~q|iP>m@?xL#5U?C zPt1UfmuaDnw)UJct`(0cN$)E8hFiMHLT-a|&F#kg3*pYS{@@^BeR~QYIFR(w&pGPUyK5j3H31)2saU~qpf1h8tl&Ry-mOHR$Lj!w= z&K%WCkFF-KNLuHU;Ef@gC4Yu|AefR9V+fS8+1ie!e3C(L3U-%ZLV$dp2@ZCpkNIU0 z-c;7~x5qRPUUuR|i=BcEW6G%RSe%jcsb=(`1?97d{C3)nAgk~9AVW5I5U`ZG$ zeyMaFo_p9nIFppp28%OGgAeGjlgHpBn-CBbtspMvy0C0>-2ZOD=@6m7;kD{|tN2?r zLLEHCY5OOLH|Qm0Gs(#e^^+Oiy4F1NE8!gn-d zWnF?*sshFserO#r#uGg?oF=fr?t_$_EIbUl5$j#mVP&1~PplPVBsDZlnL;B5zU2(9 zHT%UKE6hh!_TVEDG(igD){5&MdmW^**vf+vvH0P&%STLBtzV>9bWF&RlVzksRuuic z^depyIhhf*ihTwu?X>zxzC+q7{f^*G%)awGmY$?JKR#)t#&&7-_^=&6eQVEwOovMky4Uhxc&>r-|;qXY7<{>w4iNjCzbO)o%<`ppw(J*EVtc>jq{;6Ge+=g zioxPHk}uIgOpnv^=gCwX$C-Y8Z%cJ2u=x;WP~jGyJy~dMs>X1Jc06N3^{`rJ@UrHknGi z_F_<~YGP#?)bOE>`Dhfokgd{rXDDC}+jgH~+Gg})Du{Ml)kdFF;iTLj z$VKKh99rW4^E=ok2(fEgBB!C(ps>?~|F*6zu%aUSOj^CRI#+LRszfl;-UwyA)48sa z%sl#!0H4@#+$j&&iqRHp?<(O@w2~(7e>B@k9#E|)NzC$vX;^*a+H@*``kK83B~LQ<-MQjnZGAh(b%2!F{Kx$GK~HwbDF$*ccerJ^L=Rp zmlHL7;Nl7amwBJNB-J9#`P0v+j6&d$R=Up^;+**w`k#OY?FoX`utA2xalgDDPQwvs ze%>?^#y6D22S694gVsXnYw7Br*44qF&=@^^4U{ehg#y}Lw*Daqq4)**NBnmIwdgC3 PF97g3M{K3#`Pjb!rMmWN literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/stop.png b/app/src/main/res/drawable-xxhdpi/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..cf271e00e23de6182f15785639fcf9117535c6fc GIT binary patch literal 683 zcmeAS@N?(olHy`uVBq!ia0vp^TR@nD1xQXma&9M(Vo7)Ob!1@J*w6hZkrl{SNcITw zWnidMV_;}#VPN~)y|B@j*+Ibd z;MUf{7j7r+$f#bBk*rl{Hxs&WnDxENjFbEG-k$}U00AG|WyH#l?>zJQ&l@}YvKhzk zJgZLqwdKc?)O*jYzTdU)pZmNv?s;+QE~#H8`o(wuzUO^c93?GR9{(?%LsrmAsl??) z#|6QK%1-VreIrZ2M)%#mXUXS^@7LD7v6270)y!7Mu5!+4oAc-2%|FifdB*LU_jb&% zP;OXT$7q@$%%=QyZ9Py-wZt`|BqgyV)hf9t6-Y4{85o-B8kp!BnS>Y_TNxQynHXpr n7+Dz@oS%FdWC%h-ZhlH;S|x4``_5&9(hP&AtDnm{r-UW|w-xG! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/cancel.png b/app/src/main/res/drawable-xxxhdpi/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..49b244cb4db4d1d63ce505aedc70ce105ef8ac79 GIT binary patch literal 1069 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|WaxtEyQx6n7L%HLnaTu=ex*02F|_A6SiMiEb)Dz??tKR)aXm=o`m}!+x_c}!L6waEcb1E z)X9{+_(7{Ef9&?V8yBV>R~CM&E|z?#$<{P`+4j8IpS)as&(3?_=A`lCVB@S=U8eEt z?wUOoSASK1z0qBH0+-mH|Mly-a)0aG`S{AFE|=|+`n=DjNr%@|-j?jIe(7xWxNv<} z?;O_7<9kaKJ#C7_WIU!<1A`xuf5R_K6fbB=3TI@qvK7((D@UdbvnH`cKOEvpBdFhXR}R`pLcAwd>4&)Zvx1qIj`wTMh;dOUGwC$A=#+|2niCM=W)A5X-zwoPH_ z=TTHyl2Va!&TIXgQfIF&_h)DMFa7rQI0-cUm{SnYWOKGjQgSm7FPsnp6l!w_I<8!N zQ+yI9(9^#hjGEos9&l%#yu>G0{=>9 zANkB))#$(B^q=Qn7FJwQ{Q2nTgTvfGkLpzZm(H8iI?+sM;$OShHfFaxjy(Pz`}|_Q za^bNJu1>~(Jr0X=`Z`E$_gKM~`G;$>))E8lGg%W3tu& zl_Kqf_S^~+@+i!XzNmO~eXeWklw}4|yg|DTWr%oWaxXrpxODw0_SPlAq5RkSmxPD% zU+Q0Sdy=8lq&n|o8Xjg*Mr_WTE}u8%m}Dnc{-rI2xqnV;+=RHE2NM;4I8}YS%QLG= z^gjQk&iMuBZ#^ly^R8}5m+5x~W3$M-jr}1YGCkm^>bP0l+XkKTr9*F literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/download.png b/app/src/main/res/drawable-xxxhdpi/download.png new file mode 100644 index 0000000000000000000000000000000000000000..0f1afc380995031e4d13c552941f4ae76881628a GIT binary patch literal 912 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{XiaP zfk$L90|U1(2s1Lwnj--eWH0gbb!C6RA|WcMb1={iXdF|sr;B4q#jUrqt@DHfCEWUj zl@mo~9m&6>q$qWRIr9dq^n%4nj4R(H{^>c+nJAyb%q3vGV8NW}u09VHd~?*cJ-;{e zzS#f5*)wa7TNN&u&8e|zO3(WX4|u2cTxY9!w0z3}ZoA?+A8*C)d9?cGc718?DHRib z>ZN`*|8O88A+Lr#kufpEK}vLj8|#ul#!T$Y9FC58XP3^;vU?;sb?f72Hl`Nwx}PU4 z-uis8D$~A)`Pu=GO!HS3Y<~8wT_#nm;!MZ=?0wG~8W`_yzO&D(y<_JG?M2R}udPdZ zoE5C>51jmSy*;{>Z{LlY`F%J4xO&7coS?Mp=3~#ICT|Ua{?nbkKe<_#KbTOn>)SKt zD+OFUnuivq727#XjdN6N{qknZ{#6geJ}i9oS#kbPhSEE8oVyC%9-qAAn8NW1PQQNc z{awHE(rL{l3hTd3UwK)5o1OhK_q`oI8BE)z)r&c`{oJ;HmB9vyAcy@oelqZ~O>^p! zyr5BK=P-9;>jb4^N4ElHO?WgDG|c4}oIIhhWQL;eNuWA4N$0K|6Ef>V6X!hKUVOmA zY@Ukmu`}Cd*(dABpO0nD@1CHv=Wd6(XLC2NGgtZ2zo}6^W*nKvTBd!uQqp?bRDPA= z<-1w+Gu7_dDz^HRRogj8>#Hu2l*@ftIs3w+$M#NLJ8#|n7B0HX8z}uf-R^*}p0MKC z8SmU}Ja5I^ZxborTmM;{E8NB9_mzJ}%PT78c%3&`721^JNY1UiRX2C(*(>VXAaOfuulSDl6FndPziKA>PZ!6Kid%1QALKmbAi{9b zb3@aLw-I~3s!ZFkk?H$_cE*|Ie|7#e?yd8fq~fV_x@6a;ji;pf;(E?MKKGfv|?P4AG3+NENvKr!Jvj!wGhQ z<8SI7^ZNw=Ef+d3&5$S1TanUm6X + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/binary_item.xml b/app/src/main/res/layout/binary_item.xml index 3509b84..fd8364d 100644 --- a/app/src/main/res/layout/binary_item.xml +++ b/app/src/main/res/layout/binary_item.xml @@ -1,6 +1,84 @@ - + android:layout_height="60dp"> - \ No newline at end of file + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/device.xml b/app/src/main/res/layout/device.xml index 069d7d0..4576ed8 100644 --- a/app/src/main/res/layout/device.xml +++ b/app/src/main/res/layout/device.xml @@ -6,10 +6,6 @@ android:fitsSystemWindows="true" android:layout_height="match_parent" android:layout_width="match_parent" - android:paddingBottom="@dimen/activity_vertical_margin" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" - android:paddingTop="@dimen/activity_vertical_margin" tools:context=".activity.DeviceActivity" > @@ -19,7 +15,7 @@ android:theme="@style/AppTheme.PopupOverlay"> + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4019401..5c8b53e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,7 +14,22 @@ Manage Servers Network Unavailable Verification on file Failed - Can\\\'t create file + Can\'t create file + Would you delete + version + Unknown Error + Retry + Can\'t read any server + Invalid Configuration, buffer out of RAM + Can\'t flash using block size null + Unable to load file + Can\'t erase flash + Checksum on binary file fail + Can\'t flash outside of flash + Can\'t flash this LPC, parts unknown + Prepare for write fail + write data in ram fail + Copy to flash fail http:// https:// diff --git a/build.gradle b/build.gradle index cb98401..e220f0b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files