Intend:
I´m trying to develop a single-purpose app, which you can not exit. It should run on a phone as an "operating system". This phone will be used for further purposes. The app will not be in the play store and also you can´t leave it so I need to update it otherwise if I have newer versions. For this purpose I´ve written another app which you could call the "updater-app". I want to do this update via Bluetooth. I already prepared everything and it´s ready for file transfer. The phones can connect by an InsecureRfcommSocket. I also managed to select the .apk file which I want to send with a chooser on the updater-app and I´m converting the uri into bytes in this Code:
sendUpdateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mBtService != null) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("application/vnd.android.package-archive");
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(Intent.createChooser(intent, "Choose .apk"), FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(getApplicationContext(), "No File-Explorer found", Toast.LENGTH_SHORT).show();
}
}
}
});
and the onActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILE_SELECT_CODE && resultCode == RESULT_OK && data != null) {
Uri selectedFile = data.getData();
try {
byte[] sendingByte = readBytes(selectedFile);
mBtService.send(sendingByte);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), R.string.transmissionFailed, Toast.LENGTH_SHORT).show();
}
}
}
the readBytes function:
public byte[] readBytes(Uri uri) throws IOException {
InputStream inputStream = getContentResolver().openInputStream(uri);
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
with the mBtService.send(sendingByte) row the following function is called in the ConnectedThread:
public void send(byte[] selectedFile) {
try {
mmOutStream.write(selectedFile);
} catch (IOException e) {
e.printStackTrace();
}
}
Problem:
In the receiver phone I´ve got no idea how to receive the bytes and convert it back to a file/uri (no idea yet) .apk and save it to my phone to execute it with another button which is not part of this question.
Question:
So my question is what to to in the code of the receiver phone app to manage finish my intend? If I missed to post any relevant code I´m sorry and will add it on your Request. As I have to program this both apps for my studies I´m thankful for any help.
I found a Solution to save the received Bytes to a ByteArray and then save it to a File. In my Bluetooth ConnectedThread I have the following run() method:
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int len;
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
try {
while ((len = mmInStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
mHandler.obtainMessage(Constants.MESSAGE_READ, len, -1, byteBuffer.toByteArray())
.sendToTarget();
}
} catch (IOException e) {
e.printStackTrace();
connectionLost();
}
}
And in my Activity I have the following Handler MESSAGE_READ:
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
...
break;
case Constants.MESSAGE_READ:
byte[] buffer = (byte[]) msg.obj;
try {
String filePath = Environment.getExternalStorageDirectory() + "/download/app.apk";
File file = new File(filePath);
file.getParentFile().mkdirs();
if (file.exists()) {
file.delete();
file.createNewFile();
}
else
file.createNewFile();
BufferedOutputStream objectOut = new BufferedOutputStream(new FileOutputStream(file));
objectOut.write(buffer);
objectOut.close();
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
};
With this Code the .apk is saved to the regular Download folder as "app.apk".
Hope this is helpful for anyone.
Related
I'm working on an app where I'm downloading a PDF file, saving it to internal storage and then opening that file in other app using FileProvider.
Note: It may be a duplicate question, I've gone through most of the questions on StackOverflow, but still didn't find the solution.
The file is getting downloaded fine but when I'm opening it, it is empty.
The downlaoded file is 30 kb and it has 5 pages but all are empty.
Initially, I thought it is empty because the other app doesn't have permission to open the file, but I did another thing to check whether it is a permission issue. I've saved the file to external storage, still, it was empty. So, it means it is not a permission issue.
Please Note:
Along with pdf file, there is some .xls file as well and when I'm opening those in excel android app, it says cannot open the file. This indicates, that there is some issue while writing the byte stream.
Retrofit Interface.java
#GET(ApiConstants.END_POINT_DOWNLOAD_DOCUMENT)
#Streaming
Call<ResponseBody> downloadDocument(#Query("bucket") String bucket, #Query("filename") String fileName);
Code to Download the file: Here I'm checking if a file is already there, then return the file, otherwise download the file.
public LiveData<Resource<File>> openOrDownloadFile(String bucket, String fileName) {
MutableLiveData<Resource<File>> documentLiveData = new MutableLiveData<>();
documentLiveData.postValue(Resource.loading(null));
Context context = MyApp.getInstance();
final File file = new File(context.getFilesDir(), fileName);
if (file.exists()) {
documentLiveData.postValue(Resource.success(file));
} else {
Call<ResponseBody> call = apiService.downloadDocument(bucket, fileName);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
appExecutors.diskIO().execute(new Runnable() {
#Override
public void run() {
try {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
inputStream = response.body().byteStream();
outputStream = new FileOutputStream(file);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
}
documentLiveData.postValue(Resource.success(file));
outputStream.flush();
} catch (IOException e) {
documentLiveData.postValue(Resource.error("Error: Unable to save file/n"+e.getLocalizedMessage(), null));
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
Log.e(AppConstants.TAG, e.getMessage(), e);
documentLiveData.postValue(Resource.error("Error: Unable to save file/n"+e.getLocalizedMessage(), null));
}
}
});
} else {
documentLiveData.postValue(Resource.error("Unable to download file", null));
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
documentLiveData.postValue(Resource.error(t.getLocalizedMessage(), null));
}
});
}
return documentLiveData;
}
Fragment Code
private void onItemClickListener(Document document) {
mDocumentsViewModel.openORDownloadFile(document.getType(), document.getName()).observe(this, new Observer<Resource<File>>() {
#Override
public void onChanged(#Nullable Resource<File> fileResource) {
binding.setResource(fileResource);
if (fileResource.status == Status.SUCCESS) {
openFile(fileResource.data);
}
}
});
}
void openFile(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID, file);
intent.setDataAndType(uri, mDocumentsViewModel.getMimeType(file.getAbsolutePath()));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
PackageManager pm = getActivity().getPackageManager();
if (intent.resolveActivity(pm) != null) {
startActivity(intent);
} else {
Toast.makeText(getActivity(), "This file cannot be opened on this device. Please download some compatible app from play store", Toast.LENGTH_SHORT).show();
}
}
Following are the versions :
ext.retrofit_version = "2.4.0"
ext.okhttp_version = "3.8.0"
I'm struggling with this issue, it'll be a great help if you can point out the issue. Thank you.
Update: The problem was with the backend APIs. My code was correct. Once they've fixed the problem at there side, it started working at my side without any changes.
i'm trying to decode data that i send through TCP.
I successfully managed to fill in the decoder.
But when i try to get the output to render it on a surfaceView. i get this error:
dequeueBuffer failed: BAD_VALUE(-22)
Also, outputBufferIdde is always equal to -1 (try again later)
this is my code :
try {
serverSocket = new ServerSocket(2968);
Log.d(TAG,"server accept");
Socket client = serverSocket.accept();
InputStream inputStream = client.getInputStream();
inputBuffersde = decodec.getInputBuffers();
Log.d(TAG, "encodeDecode 1");
DecoderRunnable decoderRunnable=new DecoderRunnable(decodec,infode);
new Thread(decoderRunnable).start();
while (true) {
dataSizes=new byte[4];
inputStream.read(dataSizes,0,4);
dataSize=ByteBuffer.wrap(dataSizes).getInt();
Log.d(TAG,"size: "+dataSize);
totalLen=0;
data= new byte[dataSize];
for(;totalLen<dataSize;) {
len=inputStream.read(data, totalLen, dataSize-totalLen);
totalLen+=len;
Log.d(TAG,"totalLen: "+totalLen+" ,len: "+len);
}
int inputBufferIdde = decodec.dequeueInputBuffer(5000);
Log.d(TAG,"inputBufferIdde: "+inputBufferIdde);
if (inputBufferIdde >= 0) {
Log.d(TAG,"inputBufferIdde: "+inputBufferIdde);
inputBuffersde[inputBufferIdde].clear();
inputBuffersde[inputBufferIdde].rewind();
inputBuffersde[inputBufferIdde].put(data);
decodec.queueInputBuffer(inputBufferIdde, 0, inputBuffersde[inputBufferIdde].position(), System.nanoTime(), 0);
}
}
} catch(IOException e){
e.printStackTrace();
}
DecoderRunnable looks like this :
public DecoderRunnable(MediaCodec decodec, MediaCodec.BufferInfo infode) {
this.decodec = decodec;
this.infode = infode;
}
#Override
public void run() {
while(true){
int outputBufferIdde = decodec.dequeueOutputBuffer(infode, 5000);
Log.d(TAG, "outputBufferIdde : " + outputBufferIdde);
if (outputBufferIdde >= 0) {
Log.d(TAG, "encodeDecode 7");
decodec.releaseOutputBuffer(outputBufferIdde, true);
}
}
}
Can someone help me?
I've followed the tutorial on the cloud print website and created a Print activity by copy and pasting the example code.
I'm trying to print an image from the MediaStore but when I get as far as the print screen nothing happens after I press the 'Print' button.
This is the code I'm using to call the intent
Intent printIntent = new Intent(GalleryActivity.this, PrintDialogActivity.class);
Uri fileUri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, Long.toString(imageId));
Log.d(this, "File Uri:" + fileUri);
printIntent.setDataAndType(fileUri, "image/*");
startActivity(printIntent);
The Uri being logged looks like content://media/external/images/media/26848
The Logcat output when I press the print button is
[INFO:CONSOLE(1)] "Uncaught TypeError: Object [object Object] has no method 'getType'", source: https://www.google.com/cloudprint/dialog.html (1)
[INFO:CONSOLE(280)] "Uncaught TypeError: Cannot call method 'k' of null", source: https://www.google.com/cloudprint/client/442365700-dialog_mobile.js (280)
Edit: I've tested on a couple of other devices and I don't get the above log output, so it may not be related. However, the result is the same on every device; when I press the print button in the webview nothing happens.
Add the #JavascriptInterface in the methods of PrintDialogJavaScriptInterface class.
final class PrintDialogJavaScriptInterface {
#JavascriptInterface
public String getType() {
return cloudPrintIntent.getType();
}
#JavascriptInterface
public String getTitle() {
return cloudPrintIntent.getExtras().getString("title");
}
#JavascriptInterface
public String getContent() {
try {
ContentResolver contentResolver = getContentResolver();
InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = is.read(buffer);
while (n >= 0) {
baos.write(buffer, 0, n);
n = is.read(buffer);
}
is.close();
baos.flush();
return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
#JavascriptInterface
public String getEncoding() {
return CONTENT_TRANSFER_ENCODING;
}
#JavascriptInterface
public void onPostMessage(String message) {
if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
finish();
}
}
}
i am developing an application which can send camera frames and audio recorded from one android mobile to another
using UDP with DatagramPacket class
I've managed to send the recorded audio and playing it on the other side
also I've managed to capture Camera Frames through
Camera.PreviewCallback previewCalBac = new PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (data != null) {
// mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Log.d("CAMERA", "CHANGED" + data.length);
startStreamingVideo(data);
}
}
};
and the sending operation is like this
private void startStreamingVideo(byte[] data) {
Log.d(VIDEO_CLIENT_TAG, "Starting the video stream");
if(data!=null){
currentlySendingVideo = true;
startVStreaming(data);}
else{
Log.d(VIDEO_CLIENT_TAG, "NULL DATA");
}
}
private void startVStreaming(final byte[] data) {
Log.d(VIDEO_CLIENT_TAG,
"Starting the background thread to stream the video data");
Thread streamThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Log.d(VIDEO_CLIENT_TAG, "Creating the datagram socket");
DatagramSocket socket = new DatagramSocket();
Log.d(VIDEO_CLIENT_TAG, "Creating the buffer of size "+ data.length);
byte[] buffer = new byte[4096];
Log.d(VIDEO_CLIENT_TAG, "Connecting to "+ ipAddress.getText().toString() + ":" + VPORT);
final InetAddress serverAddress = InetAddress.getByName(ipAddress.getText().toString());
Log.d(VIDEO_CLIENT_TAG, "Connected to "+ ipAddress.getText().toString() + ":" + VPORT);
Log.d(VIDEO_CLIENT_TAG,"Creating the reuseable DatagramPacket");
DatagramPacket packet;
Log.d(VIDEO_CLIENT_TAG, "Creating the VideoRecord");
// recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,RECORDING_RATE, CHANNEL, FORMAT, data.length);
// Log.d(VIDEO_CLIENT_TAG, "VideoRecord recording...");
// recorder.startRecording();
while (currentlySendingVideo == true) {
// read the data into the buffer
Log.d(VIDEO_CLIENT_TAG, "Here0");
// int read = recorder.read(data, 0, data.length);
Log.d(VIDEO_CLIENT_TAG, "Here");
// place contents of buffer into the packet
packet = new DatagramPacket(data, 4096,serverAddress, VPORT);
Log.d(VIDEO_CLIENT_TAG, "Here1");
// send the packet
socket.send(packet);
Log.d(VIDEO_CLIENT_TAG, "Here2");
}
Log.d(VIDEO_CLIENT_TAG, "VideoRecord finished recording");
} catch (Exception e) {
Log.e(VIDEO_CLIENT_TAG, "HERE Exception: " + e);
}
}
});
// start the thread
streamThread.start();
}
the server side i can get to know that i am receiving the packets
the problem is that the bitmap image byte[] is too big to be sent
i need to scale it to the best size so i can transfer it and receive it with the least amount of wasted bytes.
any solution to this problem?
Not with UDP, no. You need a protocol on top of UDP to handle messages>64K. There is no alternative.
The only way to get and visualize the data table of my database inside external devices is by atribution of privilege of superuser privilege in external device? Don't exist another way that allow visualize the data tables as in emulator?
I make this question because this way of superuser privilege not inspire me security.
Thanks for your attention (PS: Sorry by mistakes, but english is not my mother language :) )
You can add functionality to export the database file from the internal read-only app storage to the SD-Card by simply letting your app copy the file.
Then use whatever ways you have to get it from there. Works on any device and no root required.
private void exportDb() {
File database = getDatabasePath("myDb.db");
File sdCard = new File(Environment.getExternalStorageDirectory(), "myDb.db");
if (copy(database, sdCard)) {
Toast.makeText(this, "Get db from " + sdCard.getPath(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Copying the db failed", Toast.LENGTH_LONG).show();
}
}
private static boolean copy(File src, File target) {
// try creating necessary directories
target.mkdirs();
boolean success = false;
FileOutputStream out = null;
FileInputStream in = null;
try {
out = new FileOutputStream(target);
in = new FileInputStream(src);
byte[] buffer = new byte[8 * 1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
success = true;
} catch (FileNotFoundException e) {
// maybe log
} catch (IOException e) {
// maybe log
} finally {
close(in);
close(out);
}
if (!success) {
// try to delete failed attempts
target.delete();
}
return success;
}
private static void close(final Closeable closeMe) {
if (closeMe != null)
try {
closeMe.close();
} catch (IOException ignored) {
// ignored
}
}