I'm trying to implement auto download and install apk in my application using file provider. For android version less than Oreo it works fine but getting problem while running app on device with android 8.0 and above. It works fine till Nougat, but doesn't works with Oreo. Downloading apk from server working fine but fails to install new apk.
Here is my code.
File file, folder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Utility.checkPermissionCamera(Main2Activity.this);
Utility.checkPermissionInstall(Main2Activity.this);
String fileName = "AutoDownloadApplication.apk";
folder = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString());
Logger.e("FOLDER", " " + folder);
file = new File(folder.getAbsolutePath(), fileName);
Log.e("File ", "" + file);
final Uri uri = FileProvider.getUriForFile(Main2Activity.this, BuildConfig.APPLICATION_ID + ".provider", file);
Logger.e("Check URI ", "" + uri);
if (Utility.checkPermissionCamera(Main2Activity.this)) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(StaticConstant.DOWNLOADAPK));
request.setDescription("Downloading New Apk");
request.setTitle(Main2Activity.this.getString(R.string.app_name));
//set destination
request.setDestinationInExternalFilesDir(Main2Activity.this, BuildConfig.APPLICATION_ID + ".provider", fileName);
// get download service and enqueue file
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
//set BroadcastReceiver to install app when .apk is downloaded
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(uri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
} else {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.setDataAndType(uri,
manager.getMimeTypeForDownloadedFile(downloadId));
startActivity(install);
}
unregisterReceiver(this);
}
};
//register receiver for when .apk download is compete
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
}
Manifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="MyPackageName">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<permission
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
android:protectionLevel="normal" />
<uses-permission
android:name="android.permission.REQUEST_DELETE_PACKAGES"
tools:ignore="ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="MyPackageName.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
Here is the file_paths xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="Download" path="Android/data/MyPackageName/files/Download"/>
</paths>
Please add the <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> permission in Manifest.xml first.
We should check the result of getPackageManager().canRequestPackageInstalls() if the SDK version is equal or large than 26.
The code is below:
private void checkIsAndroidO() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
boolean result = getPackageManager().canRequestPackageInstalls();
if (result) {
installApk();
} else {
// request the permission
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_PACKAGES_REQUESTCODE);
}
} else {
installApk();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case INSTALL_PACKAGES_REQUESTCODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
installApk();
} else {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
startActivityForResult(intent, GET_UNKNOWN_APP_SOURCES);
}
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case GET_UNKNOWN_APP_SOURCES:
checkIsAndroidO();
break;
default:
break;
}
}
I hope it will help you.
You can read more about FileProvider implementation in details how it works from below article:
https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en
The soluciton of JohnWatsonDev Worked perfectly!
Just one thing, to call your app directly, is just put:
intent.setData(Uri.parse("package:" + getPackageName()));
Before call
startActivityForResult(intent, GET_UNKNOWN_APP_SOURCES);
Related
I have a project I'm working on that requires a file to be downloaded normally, and then opened (generally in a PDF reader).
I have a broadcast receiver class which looks like this
public class DownloadBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
{
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0));
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = manager.query(query);
if (cursor.moveToFirst()) {
if (cursor.getCount() > 0) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
Long download_id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,0);
String downloadFilePath = null;
String downloadFileLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
File file = new File(Uri.parse(downloadFileLocalUri).getPath());
// status contain Download Status
// download_id contain current download reference id
if (status == DownloadManager.STATUS_SUCCESSFUL) {
String fname=cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
File pdfFile = new File(Environment.getExternalStorageDirectory()+"/Downloads/"+fname);//File path
if (pdfFile.isFile()) //Checking if the file exists or not
{
Uri path = Uri.fromFile(pdfFile);
Intent objIntent = new Intent(Intent.ACTION_VIEW);
objIntent.setDataAndType(path, "application/pdf");
objIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(objIntent);//Starting the pdf viewer
} else {
Log.d("OO",Environment.getExternalStorageDirectory()+"/Downloads/"+fname);
Log.d("OO",fname);
// Toast.makeText(getApplicationContext(),"Test",Toast.LENGTH_LONG).show();
}
}
}
}
cursor.close();
}
}
}
The Manifest looks like this
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.org.bridgewaterha.boardapp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".pdf"></activity>
<receiver android:name=".DownloadBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
</receiver>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
</manifest>
the paths file is as below
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="Download" path="."/>
<cache-path name="cache" path="/" />
</paths>
The problem I'm having is that in the Broadcast receiver class, the line
if (pdfFile.isFile())
ALWAYS returns false.
I've tried a few variations I've come across on the web, but none seem to be working at all.
Any tips greatly appreciated.
After downloading you have to check your file is mFile.exists() or not...
use this to open pdf file:
I think your application default behavior is not opening it directly.
so we need to use chooser
Intent myIntent = new Intent(Intent.ACTION_VIEW);
myIntent.setData(Uri.fromFile(file));
Intent j = Intent.createChooser(myIntent, "Choose an application to open with:");
startActivity(j);
while (cursor.moveToNext()) {
if (cursor.getCount() > 0) {
Log.e("filelistingloop","loopfollowingss "+cursor.getCount());
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
String file = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
if (file != null) {
File mFile = new File(Uri.parse(file).getPath());
final String fileName = mFile.getAbsolutePath().substring(mFile.getAbsolutePath().lastIndexOf('/') + 1, mFile.getAbsolutePath().length());
if (mFile.exists()){
Toast.makeText(yourActivit.this," File donwloaded successfully",Toast.LENGTH_LONG).show();
//here you can open your pdf
}
}
// So something here on success
}else if (status == DownloadManager.STATUS_FAILED){
int message = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
// So something here on failed.
Toast.makeText(getActivity(),"File Not donwloaded "+ message,Toast.LENGTH_LONG).show();
}
}
}
Recently, I updated a project with android 7.0 and upper.
I figured out the provider problem.
When I take photo and use onActivityForResult to resize the image or show it. I find the data is null. I wonder why? I have tried several ways to get Uri.
But the data is null.
//A button click to call this.
Uri tempUri;
private void takePhoto() {
if (isSdcardExisting()) {
//create a file.
File file = new File(getExternalFilesAbsolutePath(this),HERO_IMAGE);
if(file.exists()){
try {
file.delete();
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
//use a class to deal uri problem android 7.0 problem.
Uri uri = FileProvider7.getUriForFile(this,file);
Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
//put some keys to intent
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
cameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
/*
* grant uri
*
* the temp sulution :
* tempUri = uri;
*/
FileProvider7.grantUriPermission(this,cameraIntent,uri);
startActivityForResult(cameraIntent, CODE_TAKE_PHOTO);
} else {
Toast.makeText(this, "请插入SD卡", Toast.LENGTH_LONG)
.show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if(resultCode != RESULT_OK){
return;
}else{
switch (requestCode){
case CODE_TAKE_PHOTO:
/**
* the requestCode and resultCode is right,but the data is null
* I wander how to use this.
*
* the temp solution is to define a Uri obejct to store the uri.
*
* if(tempUri != null)
* resize(tempUri);
*/
Log.d(TAG, "onActivityResult: data ---> " + data);
if(data != null){
Bundle bundle = data.getExtras();
Log.d(TAG, "onActivityResult: bundle ---> " + bundle);
if(bundle != null){
Uri resizeUri = bundle.getParcelable(MediaStore.EXTRA_OUTPUT);
Log.d(TAG, "onActivityResult: resizeUri ---> " + resizeUri);
String imageType = bundle.getString("outputFormat");
Log.d(TAG, "onActivityResult: imageType ---> " + imageType);
Uri uri = data.getData();
Log.d(TAG, "onActivityResult: getData ---> " + uri);
resize(resizeUri);
}
}
break;
case CODE_SHOW_IMAGE:
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
I found a solution that the activity needs to add action in manifest activity intent filter.But it doesn't seems to work.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rambopan.demotryusercamera">
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="com.android.camera.action.CROP"/>
<action android:name="android.media.action.IMAGE_CAPTURE"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
</manifest>
The log.The uri is ok,the data is null.(Android 5.0)
06-12 15:26:11.063 368-368/com.rambopan.demotryusercamera D/XADAX.FileProvider7: getUriForFile: ---> file:///storage/emulated/0/Android/data/com.rambopan.demotryusercamera/files/hero
06-12 15:26:32.624 368-368/com.rambopan.demotryusercamera D/XADAX.MainActivity: onActivityResult: data ---> null
You can get the image from the uri variable that you are sending in cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
I have an APK-File in /storage/emulated/0/Download/app-debug.apk.
I want to install this file by FileProvider because I am using Android N.
When I try to launch the intent logcat doesn't show any error but I receive following message on my phone:
There was a problem parsing the package.
What am I doing wrong?
MainActivity
public class MainActivity extends AppCompatActivity {
Button btnStartIntent;
String strRootPathInternalStorage = Environment.getExternalStorageDirectory().toString(); //-> /storage/emulated/0 //-> /storage/emulated/0/Download/
String strApkToInstall = "app-debug.apk";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
--> Booooh bad way! <--
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
*/
btnStartIntent = (Button)findViewById(R.id.btnStartIntent);
btnStartIntent.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
installApk(MainActivity.this, strRootPathInternalStorage+"/Download/"+strApkToInstall);
}
});
}
public static void installApk(Context context, String apkPath) {
if (context == null || TextUtils.isEmpty(apkPath)) {
return;
}
File file = new File(apkPath);
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= 24) {
//provider authorities
Uri apkUri = FileProvider.getUriForFile(context, "com.spicysoftware.test.provider", file);
//Granting Temporary Permissions to a URI
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
context.startActivity(intent);
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.spicysoftware.test.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="Download" path="Download" />
</paths>
For anyone who has the same problem.
I had to specify the exactly folder with getExternalFilesDir();
MainActivity
public class MainActivity extends AppCompatActivity {
Button btnStartIntentFileProvider;
String strRootPathInternalStorage = Environment.getExternalStorageDirectory().toString();
String strApkToInstall = "app-debug.apk";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStartIntentFileProvider = (Button)findViewById(R.id.btnFileProvider);
btnStartIntentFileProvider.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
File fileApkToInstall = new File(getExternalFilesDir("Download"), strApkToInstall);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", fileApkToInstall);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
MainActivity.this.startActivity(intent);
} else {
Uri apkUri = Uri.fromFile(fileApkToInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.this.startActivity(intent);
}
}
});
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.spicysoftware.test">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.spicysoftware.test.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
<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>
provider_paths (in XML Folder)
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="Download" path="Download/" />
</paths>
After doing research and trying everything out, Here is my working code for android sdk 31:
1- created FileProvider and put it res/xml and named it "provider_paths":
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external" path="." />
</paths>
2- manifest:
<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/provider_paths"/>
3-In the main activity I have a function to download the apk from a server and receive the file and launch an installation intent to install the new version:
void checkUpdate()
{
try{
//check if file exists delete it
File file=new File("/sdcard/Download/app-debug.apk");
if(file.exists())
{
file.delete();
Log.d(TAG,"Update file exists, Deleting it!");
}
int versionCode = BuildConfig.VERSION_CODE;
String url="https://Website.com/index.php?version="+versionCode;
Log.d(TAG,url);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder()
.url(url)
.build();
Response response = null;
response = client.newCall(request).execute();
if(response.code()!=200)
{
runOnUiThread(() -> Toast.makeText(getApplicationContext(),"No update found",Toast.LENGTH_LONG).show());
return;
}
//downloading the file
InputStream is = response.body().byteStream();
BufferedInputStream input = new BufferedInputStream(is);
String strRootPathInternalStorage = Environment.getExternalStorageDirectory().toString();
String path = strRootPathInternalStorage+"/"+Environment.DIRECTORY_DOWNLOADS+"/app-debug.apk";
Log.d(TAG,path);
ResponseBody body = response.body();
long contentLength = body.contentLength();
Log.d(TAG,""+contentLength);
BufferedSource source = body.source();
BufferedSink sink = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
sink = Okio.buffer(Okio.sink(Paths.get(path)));
}else
{
Log.e(TAG,"Check this");
}
Buffer sinkBuffer = sink.buffer();
long totalBytesRead = 0;
int bufferSize = 8 * 1024;
for (long bytesRead; (bytesRead = source.read(sinkBuffer, bufferSize)) != -1; )
{
sink.emit();
totalBytesRead += bytesRead;
}
sink.flush();
sink.close();
source.close();
//finished downloading the file start installing
runOnUiThread(() -> {
try {
File fileApkToInstall = new File("/sdcard/Download/app-debug.apk");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", fileApkToInstall);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
MainActivity.this.startActivity(intent);
} else {
Uri apkUri = Uri.fromFile(fileApkToInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.this.startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
});
}catch (Exception e)
{
e.printStackTrace();
}
}
4- the website update logic is to get the current version from the app and check in the server to see if it's the last version if yes than return 404 or something similar and if no than return the apk file.
My problem is in this line:
pictureUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", createImageFile());
when i comment it the camera does not return null intent to onActivityResult but when I uncomment it, it sends null to Intent data,but its saving the file with the name i specified.
Here is the code:
Start Camera:
private void invokeCamera() {
// get a file reference
Uri pictureUri;
pictureUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", createImageFile());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// tell the camera where to save the image.
intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
// tell the camera to request WRITE permission.
intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
Create File:
private File createImageFile() {
File imageFile;
// the public picture director
File picturesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
String IMGname = Ti.getText().toString() + IMGCounter;
// put together the directory and the timestamp to make a unique image location.
imageFile = new File(picturesDirectory, IMGname + ".jpg");
Toast.makeText(this, IMGname + ".jpg", Toast.LENGTH_LONG).show();
return imageFile;
}
onActivityResult code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK && data != null){
if(requestCode == REQUEST_IMAGE_CAPTURE) {
Toast.makeText(this, "Reached REq", Toast.LENGTH_SHORT).show();
// AddImgToView(data);
}else if(requestCode == IMAGE_GALLERY_REQUEST){
AddImgToView(data);
}
}else{
Toast.makeText(this, "Op 2"+data, Toast.LENGTH_SHORT).show();
}
}
Manifest Code:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<!--Required Permissions-->
<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"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:authorities="company.com.retrofit.provider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"/>
</provider>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".InsertData"></activity>
</application>
Check for writing to external storage permission , implement dynamic permission model, I see nothing wrong in the code otherwise
I found out that the default Android camera sends data when you are sending a thumbnail, but when you use EXTRA_OUTPUT it sends null and I have to use the URI I specified.
HERE is my code
MAINIFEST
<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" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
provider_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Here checking if Naugat do this
if (haswritePermission == PackageManager.PERMISSION_GRANTED && hasWriteContactsPermission == PackageManager.PERMISSION_GRANTED) {
++imageId;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
String imageFilePath = Environment.getExternalStorageDirectory().toString() + "/Images/Profile/profile.jpg";
File imageFile = new File(imageFilePath);
imageUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", imageFile);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent, PICK_FROM_CAMERA);
}
}
onActivityResult
public void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case PICK_FROM_CAMERA:
mCropImageView.setImageUriAsync(imageUri);
[crop_dialog][1].show();
break;
}
}
}
for crop image I am using this Library
compile 'com.theartofdev.edmodo:android-image-cropper:2.5.+'
Getting this kind of null image or Empty image
I just change code for Nougat .add separate case for nougat
**for less than M**
case PICK_FROM_CAMERA:
mCropImageView.setImageUriAsync(imageUri);
path=getRealPathFromURI(imageUri);
Bitmap bitmap=rotateBitmapOrientation(path);
mCropImageView.setImageBitmap(bitmap);
crop_dialog.show();
break;
**for Nougat **
case CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE:
mCropImageView.setImageUriAsync(imageUri);
selectedImage);
crop_dialog.show();
break;