Parse error when programmatically installing an APK from Assets Folder - java

I am trying to install apk programatically from assets folder, But Parse Error
I have Googled for days and fine almost everything is fine but still error exists
Here is my code
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths" />
</provider>
</application
file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
<root-path name="root" path="." />
</paths>
MainActivity
private void installApk() {
File f = new File("file:///android_asset/app.apk");
f.setReadable(true, false);
Uri apkUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider",f);
Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(installIntent);
}
Checking Permission
private void checkWriteExternalStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!getPackageManager().canRequestPackageInstalls()) {
startActivity(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", getPackageName()))));
}
}
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
installApk();
} else {
installApk();
}
}
private void requestWriteExternalStoragePermission() {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
} else{
ActivityCompat.requestPermissions(MainActivity.this,new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode==MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
installApk();
} else {
Toast.makeText(MainActivity.this, "Permission Not Granted.", Toast.LENGTH_SHORT).show();
}
}
File app.apk location : main->assets
Please Note even I write file as
File f = new File(getFilesDir(), "app.apk");
and still parse error
TargetSDK = 31

You cannot install APK directly from assets folder because that folder is not accessible to system's package installer. You must first copy that APK to a shared folder like public documents directory and then pass the URI of file from that directory to intent
val publicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
Edit: Steps to copy file to external storage:
val file = new File("file:///android_asset/app.apk");
val publicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val destinationAPKFile = File(publicDir, "your_apk_name.apk")
try {
FileUtils.copyFile(file, destinationAPKFile)
}
catch (e: Exception)
{
e.printStackTrace();
}
Then you can use the URI of destinationAPKFile and install APK as you are doing.
Edit 2: In java
File file = new File("file:///android_asset/app.apk");
File publicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
File destinationAPKFile = File(publicDir, "your_apk_name.apk");
try {
FileUtils.copyFile(file, destinationAPKFile)
}
catch (Exception e)
{
e.printStackTrace();
}
Edit 3:
To use FileUtils.copyTo, add following dependency to your app level gradle
implementation group: 'commons-io', name: 'commons-io', version: '2.6'

Related

Can not take a picture using registerForActivityResult

I want to to use registerForActivityResult to take a photo. Whenever I take a picture and tap the confirm button the result code is always 0. here is my codes:
Uri mImageUri;
ActivityResultLauncher<Intent> mCameraLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
// ---> Here the result code is always 0 <----
Intent data = result.getData();
if (result.getResultCode() == RESULT_OK && data != null) {
Bitmap bitmap = BitmapFactory.decodeFile(mImageUri.toString());
}
});
public void launchCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File tempDir = new File(Environment.getExternalStorageDirectory().getPath(),
APP_NAME + File.separator + "Temp");
if (!tempDir.exists()) {
tempDir.mkdirs();
}
File file = new File(tempDir.getAbsolutePath() + File.separator + "tempImage");
if (Build.VERSION.SDK_INT < 24) {
mImageUri = Uri.fromFile(file);
} else {
mImageUri = Uri.parse(file.getPath());
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mCameraLauncher.launch(intent);
}
Manifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
How can I solve this problem?

Can't upload canvas image to server using retrofit

I'm trying to send an image that has been created using Canvas. there is no problem with the image and it can be displayed in ImageView.
this is the error I get:
D/onFailure: /storage/emulated/0/sign_3.png: open failed: ENOENT (No such file or directory)
I got the error even though I got permission to write and read external storage. where I found out from the following logs:
V/ContentValues: Permission is granted
this is my code to send the image:
mainactivityBinding.ivSignature.invalidate();
BitmapDrawable drawable = (BitmapDrawable)
mainactivityBinding.ivSignature.getDrawable();
Bitmap bitmap = drawable.getBitmap();
if(isStoragePermissionGranted()){
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root);
myDir.mkdirs();
String fname = "sign_"+ Preferences.getKeyIdLogin(getBaseContext()) +".png";
file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
};
}
String token = Preferences.getKeyTokenLogin(getBaseContext());
RequestBody postToken = RequestBody.create(okhttp3.MultipartBody.FORM, token);
RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Partbody = MultipartBody.Part.createFormData("upload", file.getName(), reqFile);
Call<ResponseSign> call =getApi().postSign(postToken, body);
call.enqueue(new Callback<ResponseSign>() {
#Override
public void onResponse(Call<ResponseSign> call, Response<ResponseSign> response) {
String message = response.body().getMessage();
Log.d("RESPON", "onResponse: " + message);
}
#Override
public void onFailure(Call<ResponseEditProfil> call, Throwable t) {
String message = response.body().getMessage();
Log.d("RESPON", "onResponse: " + message);
}
});
this is the code for the given storage permission:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
return true;
} else {
Log.v(TAG,"Permission is revoked");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted");
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}
this is my Retrofit Interface:
#Multipart
#POST("postSign")
Call<ResponseSign> postSign(#Part("token") RequestBody token,
#Part MultipartBody.Part image);
this is the contents of my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapps">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.MyTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I tried this app on android 11.
what should I do so that the image can be sent to the server? does the image really have to be saved in a file? or it can be sent directly without having to save to a file?
it's my first time trying to upload an image to the server, so sorry if there are some basics I don't understand.
Thank you.
I know where I went wrong, I should have checked whether my device has external memory or not.
If the device does not have external memory, the file will be stored on the internal memory.
if you want to know how to check internal and external memory you can see here:
how to check internal and external storage if exist

Android Image FIle variable is becoming null after image capture

The app I am currently developing has the feature of being able to capture an image, record a video, browse and upload a media file from gallery. Problem is, the app works well enough in emulator. Without any errors (checked with android 9+ emulators). But the app behaves unexpectedly while testing on physical device (Android 10). Unexpected, because, video recording and playing works fine, as well as browsing and uploading media from gallery. What fails is image capture. The thing is the image file is actually getting created, But I am getting the image file variable photoFile value as null in onActivityResult() method.
Here is the implementation:
manifest.xml
<provider android:name=".utils.MyFileProvider"
android:authorities="com.app.mtccrm.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
method to create image_file
public static File createImageFile(Context mContext, String name) throws IOException {
String imageFileName = name.replaceAll(" ", "_");
File storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = new File(storageDir + File.separator + imageFileName + ".png");
return image;
}
method responsible for opening the camera
private void openCamera() {
if (ActivityCompat.checkSelfPermission(AddNewFileActivity.this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_PERMISSION_CODE_IMAGE);
} else {
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
photoFile = CommonMethod.createImageFile(this, fileName);
} catch (IOException ioe) {
ioe.printStackTrace();
}
//Toast.makeText(this, ""+photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
if(photoFile != null ) {
Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", photoFile);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
captureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(captureIntent, TAKE_PICTURE_CODE);
}else {
Toast.makeText(this, "Something went wrong while trying to create a file. Please try again", Toast.LENGTH_SHORT).show();
}
}
}
onActivityResult()
Toast.makeText(this, ""+photoFile, Toast.LENGTH_SHORT).show();
if (requestCode == TAKE_PICTURE_CODE && resultCode == RESULT_OK) {
if(photoFile == null) {
if(data != null) {
parseGalleryFile(data);
}
}else {
setImage(Uri.parse(photoFile.getAbsolutePath()));
}
}
The first Toast in onActivityResult() gives me null value. So somehow the photoFile variable is becoming null, however I am at a loss about the cause. Since, from the same activity using the same methods, recording of videos and browsing gallery works just fine. I thought it might have something to do with the activity getting paused when the camera is called. So, I added this
#Override
public void onSaveInstanceState(#NonNull Bundle outState, #NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
Toast.makeText(this, ""+photoFile, Toast.LENGTH_SHORT).show();
if(photoFile != null) {
outState.putString("FileId", photoFile.getAbsolutePath());
}
}
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Toast.makeText(this, ""+savedInstanceState.getString("FileId"), Toast.LENGTH_SHORT).show();
if(savedInstanceState.getString("FileId") != null) {
if (photoFile == null) {
photoFile = new File(savedInstanceState.getString("FileId"));
}
}
}
Unfortunately, save and restore state methods are not getting called, so that means the activity is not being paused. So what could be the cause for photofile becoming null? what exactly am I doing wrong?
Thanks for the help.

mkdirs() doesnt create new directory in android

I tried to make some folder in my storage and store image from camera into it, but mkdirs always return false, already tried using mkdir and canWrite, but still the same
2020-02-12 09:32:44.043 22914-23146/example.com.absensiapp D/TET: Folder Not Exist
2020-02-12 09:32:44.047 22914-23146/example.com.absensiapp D/TET: Failed To Create Directory
Here is the code for making the folder and save the image from camera
String wholeFolderPath = fh.TRAINING_PATH + name;
File dir = new File(wholeFolderPath);
if(!dir.exists()) {
Log.d("TET", "Folder Not Exist");
//create new directory
if(dir.mkdirs())
fh.saveMatToImage(m, wholeFolderPath + "/");
else
Log.d("TET", "Failed To Create Directory");
}
else {
Log.d("TET", "Folder Exist");
//save the image to directory
fh.saveMatToImage(m, wholeFolderPath + "/");
}
Already put the permission in my manifest and main activity
Manifest :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Main Activity :
private static boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
private void checkPermission() {
int PERMISSION_ALL = 1;
String[] PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
if (!hasPermissions(this, PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}
}
Solve the problem. Downgrade my targetSdkVersion in build.gradle from 29 to 21

Nougat getUriForFile issue with camera Return

I've been trying to update my app to the way Nougat handles URI in intents and can't for the life of me figure out how to get the camera to work again. I've tried following the documentation but I must be missing something. Can anyone help?
this is my dispatch event
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
return;
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.everywhere_ww.provider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
this is my provider in manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.everywhere_ww.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
This is my file paths
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="imgFolder" path="pictures" />
<external-path name="tempFolder" path="temp" />
Attempting to take a picture always fails with a
java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.everywhere_ww/files/temp/JPEG_20170223_101548_1550424251.jpg
/data/data/com.everywhere_ww/files/temp/JPEG_20170223_101548_1550424251.jpg would appear to be a path pointing to internal storage. You created this via getFilesDir(), presumably.
Replace:
<external-path name="tempFolder" path="temp" />
with:
<files-path name="tempFolder" path="temp" />
Hi not sure can make the difference but try to add to your xml file paths the following param
<external-path name="external_files" path="."/>

Categories