I'm having this issue with Android TV (sampleApp).
I'm inputting streaming channels from a xml file. I'm creating a temp file to be used at the start, and then I have created a button that does all the necessary functions to acquire data from the server and create the NEW xml file from that data. All of this works, but there's one issues:
After pressing the button and file is created, I try to add channels by pressing "add channels" button, but the file that is used is the temp file, not the NEW xml file. So that it uses the NEW xml file, I have to re-run the setup again and then it works flawlesly. It seems like it caches the temp file in memory or something and uses it first when adding channels, because when the app is launched there is no internal storage file (this is where i save my NEW xml file), the file is created only after the button press.
How do I make it so it uses the NEW xml file instead of the temp file(that created during app launch)?, instead of doing a re-setup
This is the method that is used. Basically, on the first launch it creates an xml with no channels or programs(the temp file) and does what it has to. Then using my other class I create a NEW xml file with all the channels and programs. That also works, the file exists and it goes to the else statement after I press the "add Channels" button. But regardless, on the first try after pressing the button it always adds the temp file, rather than the new one. The new one is only runned, if I launch the setup again.
public static XmlTvParser.TvListing getRichTvListings(Context context) {
context1 = context;
FileOutputStream fos;
try {
Boolean exists = context.getFileStreamPath(FILENAME).exists();
if (exists == false){
String string = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n" +
"\n" +
"<tv>\n" +
"</tv>";
Log.d(TAG,"Exists: FALSE");
fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
read = "file:" + context.getFilesDir().toString() + "/" + FILENAME ;
Uri catalogUri =Uri.parse(read);
if (sSampleTvListing != null) {
return sSampleTvListing;
}
try (InputStream inputStream = getInputStream(context, catalogUri)) {
sSampleTvListing = XmlTvParser.parse(inputStream);
} catch (IOException e) {
Log.e(TAG, "Error in fetching " + catalogUri, e);
}
}
else{
Log.d(TAG,"Exists: TRUE");
FileInputStream fis = context.openFileInput(FILENAME2);
StringBuilder builder = new StringBuilder();
int inputChar;
while((inputChar = fis.read()) != -1) {
builder.append((char) inputChar);
}
String readFile = builder.toString();
Log.d(TAG, "FileContent: " + readFile);
read = "file:" + context.getFilesDir().toString() + "/" + FILENAME2 ;
Uri catalogUri =Uri.parse(read);
if (sSampleTvListing != null) {
return sSampleTvListing;
}
try (InputStream inputStream = getInputStream(context, catalogUri)) {
sSampleTvListing = XmlTvParser.parse(inputStream);
} catch (IOException e) {
Log.e(TAG, "Error in fetching " + catalogUri, e);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sSampleTvListing;
}
The the button functionalities are in my richSetupFragment class(I wont post all of it, but these are the part that I think are most important in this case):
#Override
protected Boolean doInBackground(Uri... params) {
mTvListing = RichFeedUtil.getRichTvListings(getActivity());
mPoster = fetchPoster();
return true;
}
#Override
public void onActionClicked(Action action) {
if (action.getId() == ACTION_ADD_CHANNELS) {
setupChannels(mInputId);
} else if (action.getId() == ACTION_CANCEL) {
getActivity().finish();
}
else if (action.getId() == RETRIEVE_DATA) {
getChannelsFromServer();
// Log.d(TAG,"List: " + list);
}
private void setupChannels(String inputId) {
inputIdLocal= inputId;
if (mTvListing == null) {
onError(R.string.feed_error_message);
return;
}
TvContractUtils.updateChannels(getActivity(), inputId, mTvListing.channels);
SyncUtils.setUpPeriodicSync(getActivity(), inputId);
SyncUtils.requestSync(inputId, true);
mSyncRequested = true;
// Watch for sync state changes
if (mSyncObserverHandle == null) {
final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask,
mSyncStatusObserver);
}
}
Related
I'm splitting an encrypted video into 4 parts using this code
public class SplitVideoFile {
private static String result;
static ArrayList<String>update=new ArrayList<>();
public static String main(File file) {
try {
// File file = new File("C:/Documents/Despicable Me 2 - Trailer (HD) - YouTube.mp4");//File read from Source folder to Split.
if (file.exists()) {
String videoFileName = file.getName().substring(0, file.getName().lastIndexOf(".")); // Name of the videoFile without extension
// String path = Environment.getDataDirectory().getAbsolutePath().toString() + "/storage/emulated/0/Videointegrity";
String path = "/storage/emulated/0/Videointegrity";
// File myDir = new File(getFile, "folder");
//myDir.mkdir();
File splitFile = new File(path.concat("/").concat(videoFileName));//Destination folder to save.
if (!splitFile.exists()) {
splitFile.mkdirs();
Log.d("Directory Created -> ", splitFile.getAbsolutePath());
}
int i = 01;// Files count starts from 1
InputStream inputStream = new FileInputStream(file);
String videoFile = splitFile.getAbsolutePath() +"/"+ String.format("%02d", i) +"_"+ file.getName();// Location to save the files which are Split from the original file.
OutputStream outputStream = new FileOutputStream(videoFile);
Log.d("File Created Location: ", videoFile);
update.add("File Created Location: ".concat(videoFile));
int totalPartsToSplit =4 ;// Total files to split.
int splitSize = inputStream.available() / totalPartsToSplit;
int streamSize = 0;
int read = 0;
while ((read = inputStream.read()) != -1) {
if (splitSize == streamSize) {
if (i != totalPartsToSplit) {
i++;
String fileCount = String.format("%02d", i); // output will be 1 is 01, 2 is 02
videoFile = splitFile.getAbsolutePath() +"/"+ fileCount +"_"+ file.getName();
outputStream = new FileOutputStream(videoFile);
Log.d("File Created Location: ", videoFile);
streamSize = 0;
}
}
outputStream.write(read);
streamSize++;
}
inputStream.close();
outputStream.close();
Log.d("Total files Split ->", String.valueOf(totalPartsToSplit));
result="success";
} else {
System.err.println(file.getAbsolutePath() +" File Not Found.");
result="failed";
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public ArrayList<String> getUpdate()
{
return update;
}
And in my activity file i call this using async task's doinbackground method like below
protected String doInBackground(Void...arg0) {
Log.d(TAG + " DoINBackGround", "On doInBackground...");
File encvideo=new File(epath.getText().toString());
SplitVideoFile split=new SplitVideoFile();
String result=split.main(encvideo);
publishProgress(1);
return result;
}
Even though it splits the video, it takes too much of time to do the process.
How can I speed them up. As I'm showing a progress bar in preexecute method it looks like the user sees the progress bar for a long time, which I don't want.
Programming with Android Studio and the osmdroid library.
I downloaded a portion of a map using the cacheManager.downloadAreaAsync() method. This method stores the map piece in a sqlite file in the data/data/<package>/osmdroid/tiles directory, chosen by me.
Now I want to use this map to load it offline in a mobile application.
I've tried to do it through all kinds of classes (MapTileSqlCacheProvider, XYTileSource, OfflineTileProvider, ...) but I can't get the map to appear.
How should I do it?
To download a portion of the map I do this:
map.setTileSource(TileSourceFactory.OpenTopo);
outputPath = "/data/data/<package>/files" + File.separator + "osmdroid" + File.separator + "tiles" + File.separator;
outputName = outputPath + boxE6.name + ".db";
try {
writer=new SqliteArchiveTileWriter(outputName);
} catch (Exception ex) {
ex.printStackTrace();
}
CacheManager cacheManager = new CacheManager(map,writer);
cacheManager.downloadAreaAsync(this, boxE6, 7, 13, new CacheManager.CacheManagerCallback() {
#Override
public void onTaskComplete() {
Toast.makeText(ctx, "Download complete!", Toast.LENGTH_LONG).show();
if (writer!=null)
writer.onDetach();
} ...
To retrieve the stored map (in this case it is in the usa.db file) I try to do this:
map.setUseDataConnection(false);
map.setTileSource(TileSourceFactory.OpenTopo);
File cache = new File(outputName);
Configuration.getInstance().setOsmdroidTileCache(cache);
mapController.setCenter(new GeoPoint((n+s)/2,(e+w)/2));
I will show how I store and load multiple sqlite Tiles, not just one.
The above answer from José Espejo Roig worked only partly for me. It worked almost fine for caching the tiles, but not for reading them. Writing down cache files though is also not complete. I have created my own code using as example: Make a tile archive from OSMDroid Github.
So to store potentially more than 1 tiles in a specific directory I use a code like below. It creates sequentially my_mapX.sqlite, where X are just stepped consecutive integers. So I get my_map1.sqlite, my_map2.sqlite and so on.
private final String MAP_FILE_NAME = "my_map";
private final String MAP_FILE_EXTENSION = ".sqlite";
// ...
Context ctx = getActivity();
mMapView = new MapView(ctx);
((ConstraintLayout) view.findViewById(R.id.osm_fragment)).addView(mMapView);
mMapView.setTileSource(TileSourceFactory.OpenTopo);
ContextWrapper contextWrapper = new ContextWrapper(ctx);
File root_directory = contextWrapper.getDir(ctx.getFilesDir().getName(), Context.MODE_PRIVATE);
File directory_osm = new File(root_directory, "osmdroid");
directory_osm.mkdir();
File directory = new File(directory_osm, "tiles");
directory.mkdir();
File[] nrFiles = directory.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
if (name.endsWith(MAP_FILE_EXTENSION))
return true;
return false;
}
});
String osmdroidTile = directory.getAbsolutePath() + File.separator + MAP_FILE_NAME + (nrFiles.length + 1) + MAP_FILE_EXTENSION;
BoundingBox boxE6 = mMapView.getBoundingBox();
SqliteArchiveTileWriter writer = null;
try {
writer = new SqliteArchiveTileWriter(osmdroidTile);
} catch (Exception ex) {
ex.printStackTrace();
}
CacheManager cacheManager = new CacheManager(mMapView, writer);
SqliteArchiveTileWriter finalWriter = writer;
int currZoom = (int)mMapView.getZoomLevelDouble();
cacheManager.downloadAreaAsync(ctx, boxE6, currZoom, currZoom + 1, new CacheManager.CacheManagerCallback() {
#Override
public void onTaskComplete() {
Toast.makeText(ctx, "Download complete!", Toast.LENGTH_LONG).show();
if (finalWriter != null)
finalWriter.onDetach();
}
#Override
public void updateProgress(int progress, int currentZoomLevel, int zoomMin, int zoomMax) {
}
#Override
public void downloadStarted() {
}
#Override
public void setPossibleTilesInArea(int total) {
}
#Override
public void onTaskFailed(int errors) {
Toast.makeText(getActivity(), "Download complete with " + errors + " errors", Toast.LENGTH_LONG).show();
if (finalWriter != null)
finalWriter.onDetach();
}
});
}
});
This way I can create as many tile files as I want. Important is that they have ".sqlite" extension. ".db" extension didn't work for me.
Now to read these tiles I used again example from OSMDroid Github: Sample SQLITE example. In OSMDroid Github example TileSource is being determined with IArchiveFile. I skipped that, as I assume I know what TileSource I used (in my case it is OpenTopo, as you can see). Then to read multiple offline tiles from the same TileSource (basing on example from OSMDroid) my code looks like this:
//first we'll look at the default location for tiles that we support
Context ctx = getActivity();
mMapView = new MapView(ctx);
((ConstraintLayout) view.findViewById(R.id.osm_fragment)).addView(mMapView);
mMapView.setUseDataConnection(false);
ContextWrapper contextWrapper = new ContextWrapper(ctx);
File root_directory = contextWrapper.getDir(ctx.getFilesDir().getName(), Context.MODE_PRIVATE);
String osmDir = root_directory.getAbsolutePath() + File.separator + "osmdroid" + File.separator + "tiles";
File f = new File(osmDir);
if (f.exists()) {
File[] list = f.listFiles();
ArrayList<File> sqliteArray = new ArrayList<>();
if (list != null) {
for (int i = 0; i < list.length; i++) {
if (list[i].isDirectory()) {
continue;
}
String name = list[i].getName().toLowerCase();
if (!name.contains(".")) {
continue; //skip files without an extension
}
name = name.substring(name.lastIndexOf(".") + 1);
if (name.length() == 0) {
continue;
}
//narrow it down to only sqlite tiles
if (ArchiveFileFactory.isFileExtensionRegistered(name) && name.equals("sqlite")) {
sqliteArray.add(list[i]);
}
}
}
OfflineTileProvider tileProvider;
if (sqliteArray.size() > 0) {
try {
tileProvider = new OfflineTileProvider(new SimpleRegisterReceiver(getActivity()), sqliteArray.toArray(new File[0]));
mMapView.setTileProvider(tileProvider);
mMapView.setTileSource(TileSourceFactory.OpenTopo);
mMapView.invalidate();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
Toast.makeText(getActivity(), f.getAbsolutePath() + " dir not found!", Toast.LENGTH_SHORT).show();
}
I am using android's thread pool executor framework (initialized as below).
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
ExecutorService executorService = new ThreadPoolExecutor(totalCores, totalCores * 3, 10, TimeUnit.SECONDS, taskQueue);
Now, consider the following function onFrameProcessed -
public void onFrameProcessed(RenderedImage renderedImage) {
String timeNow = new SimpleDateFormat("d-M-Y_HH_mm_ss_SSS").format(new Date()).toString();
CustomRunnable3 customRunnable3 = new CustomRunnable3(renderedImage, timeNow);
executorService.execute(customRunnable3);
}
Definition of CustomRunnable3 is as follows:
class CustomRunnable3 implements Runnable {
RenderedImage renderedImageLocal;
String basePath, timeNowCopy;
int hashCode;
CustomRunnable3(RenderedImage renderedImage, String timeNow) {
renderedImageLocal = renderedImage;
this.basePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
this.timeNowCopy = timeNow;
hashCode = renderedImageLocal.hashCode();
}
#Override
public void run() {
if (renderedImageLocal.imageType() == RenderedImage.ImageType.ThermalRadiometricKelvinImage) {
int[] thermalData = renderedImageLocal.thermalPixelValues();
String dataPath = basePath + "/" + this.timeNowCopy + ".csv";
try {
PrintWriter printWriter = new PrintWriter(dataPath);
int dataLen = thermalData.length;
for (int i = 0; i < dataLen; i++) {
printWriter.println(thermalData[i]);
}
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
String imgPath = basePath + "/" + this.timeNowCopy + ".jpg";
try {
if (hashCode != renderedImageLocal.hashCode()) {
Log.e("Checking", "Hash code changed..");
}
renderedImageLocal.getFrame().save(new File(imgPath), frameProcessor);
if (hashCode != renderedImageLocal.hashCode()) {
Log.e("Checking", "Hash code changed after writing..");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Usage Scenario : onFrameReceived is being called multiple times per second(like 4-5 times). In each call to onFrameReceived, I am saving two files from renderedImage object (1 csv file, 1 jpg file). Both of these files must be related to each other because both are created from one parent and have same name(except the extension).
Problem : But that is not happening and somehow I am ending up with jpg file content from 1 renderedImage and csv content from another renderedImage object.
What are the possible reasons for this problem, please share your opinion.
I am storing my data which is coming from hardware device (i.e console), 1st i am creating the file in my device as follows -->>
final String folderName = LOGGING_ROOT_FOLDER;
File folder = new File(folderName);
if (!folder.isDirectory()) {
boolean ret = folder.mkdirs();
if (ret != true) {
return null; // return empty string if fail.
}
}
final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.US);
final String fileName = folderName + File.separator + firstName + "-" + patientId + "-" + procedureId + "-"
+ sdf.format(new Date(System.currentTimeMillis())) + ".log";
File f = new File(fileName);
if (!f.exists()) {
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
customLogFile = new BufferedWriter(new FileWriter(f, true));
} catch (IOException e) {
e.printStackTrace();
}
After creating the file i am storing the data in my device as .log with flag (below i have given the code )-->>
if (customLogFile != null) {
StringBuilder sb = new StringBuilder(500);
final String d = mFormatter.format(new Date(System.currentTimeMillis()));
if (pdMeanValue != -1) {
sb.append(pdMeanValue);
}
sb.append("|");
if (aoMean != -1) {
sb.append(aoMean);
}
sb.append("|");
if (aoMap != -1) {
sb.append(aoMap);
}
sb.append("|");
if (ffrValue != -1) {
sb.append(ffrValue);
}
sb.append("|");
if (ffrLowestValue != -1) {
sb.append(ffrLowestValue);
}
sb.append("|");
sb.append(d);
if (mIsRecording) {
sb.append("|1"); // this is the flag
}
if (!canLogFile(sb.toString().getBytes().length)) {
return false;
}
customLogFile.write(sb.toString());
customLogFile.newLine();
So i am getting the data from console continuously and plotting the graph, but now after this i want to fetch the stored file data and wants to plot again in graph but segment wise like one interval of time to another interval (i.e like if flag is 1,then that data i want to fetch from the device and plot the graph, by taking pdMeanValue, aoMean value which will be there in side file as string format). (stored data structure is like [20|30|45|10|12|time will place here|flag])
Please help me to plot the graph by taking the value where the flag is 1.
I have a program in which I'm trying to download the content of an image file from a server. I'm using java socket to download it. After downloading, I use BitmapFactory.decodeByteArray() to create a bitmap.
At the server side, the file is a .jpg file and it's only about 180 KBytes, so I don't need to try scaling it. I can see through logs that the exact number of bytes in the file is received by my image download code. I store all the bytes in a byte[] array and then convert it into a bitmap.
The imageView is initially hidden and then supposed to be made visible after populating the image. But using BitmapFactory.decodeByteArray() is returning null always. I did see some other posts about null bitmap, but nothing seems to have an answer for this problem.
I don't want to use any external library just for this, so please do not give me suggestions to try out some other libraries. Can someone spot any problem with the code? The server side program is also mine and I know that part is correct because using that, browsers are able to download the same image file. I have copy-pasted it below.
public class ImageDownloader {
private Socket sockToSrvr;
private PrintWriter strmToSrvr;
private BufferedInputStream strmFromSrvr;
private String srvrAddr;
private int port;
private String remoteFile;
private Context ctxt;
private Bitmap imgBmap;
private View parkSpotImgVwHldr;
private View mngAndFndVwHldr;
private View parkSpotImgVw;
public ImageDownloader(Context c) {
srvrAddr = KloudSrvr.srvrIp();
port = KloudSrvr.port();
sockToSrvr = null;
strmFromSrvr = null;
strmToSrvr = null;
remoteFile = null;
ctxt = c;
imgBmap = null;
parkSpotImgVwHldr = null;
mngAndFndVwHldr = null;
parkSpotImgVw = null;
}
public void downloadFile(String remf, View parkSpotImgVwHldrVal,
View mngAndFndVwHldrVal, View parkSpotImgVwVal) {
remoteFile = remf;
parkSpotImgVwHldr = parkSpotImgVwHldrVal;
mngAndFndVwHldr = mngAndFndVwHldrVal;
parkSpotImgVw = parkSpotImgVwVal;
Thread dwnThrd = new Thread() {
#Override
public void run() {
imgBmap = null;
openServerConnection(); sendReq(); doDownload(); closeServerConnection();
((Activity)ctxt).runOnUiThread(new Runnable() {
public void run() {
((Activity)ctxt).runOnUiThread(new Runnable() {
public void run() {
mngAndFndVwHldr.setVisibility(View.GONE);
parkSpotImgVwHldr.setVisibility(View.VISIBLE);
Toast.makeText(ctxt, "completed", Toast.LENGTH_LONG).show();
}
});
}
});
}
};
dwnThrd.start();
}
private void sendReq() {
if(strmToSrvr == null) return;
String req = "GET /downloadFile " + remoteFile + " HTTP/1.1\r\n\r\n";
Log.d("IMG-DWNL-LOG: ", "writing req msg to socket " + req);
strmToSrvr.write(req); strmToSrvr.flush();
}
private void doDownload() {
boolean gotContLen = false;
int contLen = 0;
while(true) {
String inLine = getLine(strmFromSrvr); if(inLine == null) break;
if((gotContLen == true) &&
(inLine.replace("\r", "").replace("\n", "").isEmpty() == true)) break;
if(inLine.trim().startsWith("Content-Length:") == true) {
// an empty line after this signifies start of content
String s = inLine.replace("Content-Length:", "").trim();
try {contLen = Integer.valueOf(s); gotContLen = true; continue;}
catch(NumberFormatException nfe) {contLen = 0;}
}
}
if((gotContLen == false) || (contLen <= 0)) return;
byte[] imgByts = new byte[contLen];
int totRdByts = 0, rdByts, chnk = 1024, avlByts;
while(true) {
try {
avlByts = strmFromSrvr.available(); if(avlByts < 0) break;
if(avlByts == 0) {try {Thread.sleep(1000);} catch(InterruptedException ie) {} continue;}
rdByts = (avlByts < chnk) ? avlByts : chnk;
rdByts = strmFromSrvr.read(imgByts, totRdByts, rdByts); if(rdByts < 0) break;
if(rdByts == 0) {try {Thread.sleep(1000);} catch(InterruptedException ie) {} continue;}
totRdByts += rdByts;
if(totRdByts >= contLen) break;
} catch(IOException ioe) {return;}
}
if(totRdByts < contLen) {
Log.d("IMG-DWNL-LOG: ", "error - bytes read " + totRdByts
+ " less than content length " + contLen);
return;
}
if(totRdByts <= 0) return;
Log.d("IMG-DWNL-LOG: ", "read all image bytes successfully, setting image into view");
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeByteArray(imgByts, 0, contLen, options);
if(bitmap == null) {Log.d("IMG-DWNL-LOG: ", "got a null bitmap");}
((ImageView)parkSpotImgVw).setImageBitmap(bitmap);
}
private void closeServerConnection() {
if(sockToSrvr == null) return;
if(strmFromSrvr != null) {
try {strmFromSrvr.close();}
catch(IOException e) {Log.d("IMG-DWNL-LOG: ", "Inp strm close exception");}
}
if(strmToSrvr != null) strmToSrvr.close();
try {sockToSrvr.close();}
catch(IOException e) {Log.d("IMG-DWNL-LOG: ", "Conn close exception");}
strmFromSrvr = null; strmToSrvr = null; sockToSrvr = null;
}
private void openServerConnection() {
try {sockToSrvr = new Socket(InetAddress.getByName(srvrAddr), port);}
catch(UnknownHostException e) {
Log.d("IMG-DWNL-LOG: ", "Unknown host exception"); sockToSrvr = null; return;
} catch(IOException e) {
Log.d("IMG-DWNL-LOG: ", "Server connect exception"); sockToSrvr = null; return;
}
Log.d("IMG-DWNL-LOG: ", "Connected to server");
try {
strmFromSrvr = new BufferedInputStream(sockToSrvr.getInputStream());
strmToSrvr = new PrintWriter(new BufferedWriter(new OutputStreamWriter
(sockToSrvr.getOutputStream())), true);
} catch(IOException e) {
closeServerConnection();
Log.d("IMG-DWNL-LOG: ", "Failed to open reader / writer. Closed the connection."); return;
}
}
private String getLine(BufferedInputStream dis) {
String outLine = "";
while(true) {
try {
int c = dis.read(); if((c == -1) && (outLine.length() <= 0)) return(null);
outLine += Character.toString((char)c);
if(c == '\n') return(outLine);
} catch(IOException e) {if(outLine.length() <= 0) return(null); return(outLine);}
}
}
}
I was making a mistake, assuming that a .jpg file's bytes can be directly decode with the android bitmap decoder. Apparently this is not the case. So, I wrote the received bytes into a temporary file in the phone storage and then called BitmapFactory.decodeFile() which is able to return a good bitmap and ends up showing the image.
So, have a working solution now.
Still - if anyone has a better suggestion how to decode directly from the received bytes (which are from a .jpg file), I would be very interested to try it out since that would be more efficient. Thanks.