Open image (InternalStorage) with android default application using FileProvider - java

I have a picture stored in my internal application storage, and I want to open it with android default application (gallery or any other).
So I'm using a FileProvider, my code works fine on android 4.3, but on some versions (2.3.6 for example), it doesn't work, the application open itself but then blackscreen, nothing.
My app needs to be API-10 compatible
I read many topics relating this problem, nothing seems to fix it. The code is probably not wrong since it works on 4.3...
Any thought?
My code to launch the activity :
File file = getMyFile();
Uri contentUri = FileProvider.getUriForFile(getContext(), <full-path-to-my-activity>, file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(contentUri, "image/*");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent = Intent.createChooser(intent, "Open with");
startActivity(intent);
in my manifest :
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<full-path-to-my-activity>"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider"/>
</provider>
my provider.xml :
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="pictures"
path=""/>
</paths>

Related

Storage sharing with standard apps concept

In short:
My app should let the user take and display photos using the standard apps.
The photos should not show up in the Gallery.
The photos should be removed when the app is de-installed.
What I got so far:
Since I want to use the device's default camera app, I need to use a shareable place for the files.
I tried using 'ExternalFilesDir' with a 'Manifest/xml/provider' contructed Uri in the calling
intent. This seams to work with the camera app:
private String mImagePath;
private void takePhoto(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) == null) return;
String filename="Image" + System.currentTimeMillis();
File dir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file =null;
try{
file = File.createTempFile(filename,".jpg", dir);
}catch(Exception ex){
ex.printStackTrace();
}
if (file == null) return;
mImagePath =file.getAbsolutePath();
Uri uri = FileProvider.getUriForFile(this,getApplicationContext().getPackageName()+".provider", file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, requestcode);
}
This part seams to work (due to my 'competence' I cannot check the folder since the Android Studio's Device File Eplorer does not let me, grrh!).
But when I try to display the images, all the standard apps (Gallery, Foto etc.) throw an 'access denied' error message.
private void displayPhoto{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri contentUri = FileProvider.getUriForFile(this,getApplicationContext().getPackageName()+".provider", new File(mImagePath));
intent.setDataAndType(contentUri, "image/*");
startActivity(intent);
}
My questions are:
Why can the camera app store a file in ExternalFilesDir but the
displaying app cannot read it from there?
-or-
Is there something wrong with my code?
Can my app somehow grant access to the displaying app?
What other concept could I use to achieve my targets?
How can I browse the content of ExternalFilesDir within Android
Studio or another tool?
I do not want to write my own displaying code since the user is familliar with the standard app.
I need to use minSDKVersion 22.
Thanks for helping me here!
Meanwhile, after hours and hours, I found the reason why Gallery or other apps show the 'access denied' error:
Im addition to the uri the caller app has to set the 'FLAG_GRANT_READ_URI_PERMISSION' flag in the calling intent. Like this:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(mycontenturi, "image/*");
intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
Also I found that the only entries in the fileprovider xml which work are:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures/" />
<external-files-path name="my_images" path="." />
<external-files-path name="camera_image" path="."/>
<external-files-path name="camera_image" path="Pictures/"/>
</paths>
Funny enough: when path is "." it creates a Pictures subdir and when it says "Pictures/" it doesn't.

Home screen shortcut wont add

I am trying to add a short on home screen programmatically but it wont work.
The code works for Oreo and above but not below that.
public void addShortcutToHomeScreen() {
if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(this, "#1")
.setIntent(new Intent(this, ActivityMemes.class).setAction(Intent.ACTION_MAIN)) //!!! intent's action must be set on oreo
.setShortLabel("Memeify")
.setIcon(IconCompat.createWithResource(this, R.mipmap.ic_launcher))
.build();
ShortcutManagerCompat.requestPinShortcut(this, shortcutInfo, null);
} else {
Intent shortcutIntent = new Intent(getApplicationContext(),
Activity.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);
Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Name");
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(getApplicationContext(),
R.mipmap.ic_launcher));
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
addIntent.putExtra("duplicate", false);
getApplicationContext().sendBroadcast(addIntent);
}
}
Here is my Manifest file.
<activity
android:name="com.my.package.Activities.Activity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Please, Tell me what am I doing wrong cause I have tried to fixed it and have failed. And is there any better way than this? Any help would be appreciated thanks.
EDIT :
Found this in the Logcat.
2019-01-16 13:27:46.773 735-13377/? W/BroadcastQueue: Permission Denial: broadcasting Intent { act=com.android.launcher.action.INSTALL_SHORTCUT flg=0x10 launchParam=MultiScreenLaunchParams { mDisplayId=0 mBaseDisplayId=0 mFlags=0 } (has extras) } from com.chameleon.memeify (pid=14824, uid=10300) requires com.android.launcher.permission.INSTALL_SHORTCUT due to receiver com.sec.android.app.launcher/com.android.launcher3.home.InstallShortcutReceiver
you can use this method in your application class
public void createShortCut() {
Intent shortcutintent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
shortcutintent.putExtra("duplicate", false);
shortcutintent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.app_name));
Parcelable icon = Intent.ShortcutIconResource.fromContext(getApplicationContext(),
R.drawable.logo);
shortcutintent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
shortcutintent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(getApplicationContext(), SplashActivity.class));
sendBroadcast(shortcutintent);
}
}
and apply this permission
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
If your are on Android 8+ you can't use the broadcast anymore and you have to use the ShortcutManager :
https://developer.android.com/about/versions/oreo/android-8.0-changes#as
Android 8.0 (API level 26) includes the following changes to app shortcuts:
The com.android.launcher.action.INSTALL_SHORTCUT broadcast no longer has any effect on your app, because it is now a private, implicit broadcast. Instead, you should create an app shortcut by using the requestPinShortcut() method from the ShortcutManager class.
The ACTION_CREATE_SHORTCUT intent can now create app shortcuts that you manage using the ShortcutManager class. This intent can also create legacy launcher shortcuts that don't interact with ShortcutManager. Previously, this intent could create only legacy launcher shortcuts.
Shortcuts created using requestPinShortcut() and shortcuts created in an activity that handles the ACTION_CREATE_SHORTCUT intent are now fully-fledged app shortcuts. As a result, apps can now update them using the methods in ShortcutManager.
Legacy shortcuts retain their functionality from previous versions of Android, but you must convert them to app shortcuts manually in your app.
To learn more about changes to app shortcuts, see the Pinning Shortcuts and Widgets feature guide.

Sharing failed while sharing Firebase image URI to other apps?

While sharing image URI to other sharing is getting failed. So I want a solution on how to share my app images to other app using bluetooth, whatsapp etc.
Here is my code:
ArrayList <Uri> imageUri = new ArrayList<>();
for (int i = 0; i < urimodel.size(); i++) {
Uri model_uri = urimodel.get(i); //getting uri from here
imageUri.add(model_uri);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.setType("image/*");
context.startActivity(Intent.createChooser(shareIntent, "Share images to.."));
}
My suggestion first save image which u want to share then pass uri
Ref : Share Image with Other Apps
Try something Like this
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
shareIntent.setType("image/*");
// For a file in shared storage. For data in private storage, use a ContentProvider.
Uri uri = Uri.fromFile(getFileStreamPath(pathToImage));
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(shareIntent)
If you want to share it via the assets folder, you'll have to use a ContentProvider. See this answer on how to do so:
https://stackoverflow.com/a/7177103/1369222
OR
Add File Provider in Android Manifest
<provider
android:name="android.support.v4.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="${applicationId}">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths"/>
file_provider_paths.xml
<paths>
<cache-path name="cache" path="/" />
<files-path name=”files” path=”/” />
</paths>
See That How to use support FileProvider for sharing content to other apps?
this must be because your firebase storage setting didn't allow to read and write without auth
just go to to storage>rules and change the rules with this
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read;
allow write: if request.auth != null;
}
}
}
this will allow everyone can read your image
Warning reading and writing the storage database also count and you need to pay cost to remain it work after certain limit. check pricing here

How to open wps office in my application Nougat?

I tried below code it is working upto Marshmallow it's not working in Nougat..can any one help me how to solve this...
I have a Excelfile in my internal storage...i what open excelfile when button clicked if wps is not install i am redirected to Playstore to Install wps...
I am getting error like:
android.os.FileUriExposedException:
file:///storage/emulated/0/Test%20Distributor%20Report.xlsx exposed
beyond app through Intent.getData()
void openExcel()
{
Intent intent = new Intent(Intent.ACTION_VIEW);
/*vnd.ms-excel*/ /*application/vnd.openxmlformats-officedocument.spreadsheetml.sheet*/
intent.setDataAndType(Uri.fromFile(file),"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
try {
context.startActivity(intent);
}catch (Exception e)
{
Toast.makeText(context,"Please Install WPS Application To View Reports",Toast.LENGTH_LONG).show();
Intent viewIntent =
new Intent("android.intent.action.VIEW",
Uri.parse("https://play.google.com/store/apps/details?id=cn.wps.moffice_eng&hl=en"));
context.startActivity(viewIntent);
Log.d("printexeption",""+e.toString());
}
}
If your targetSdkVersion is 24 or higher, we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps. We create our own class inheriting FileProvider in order to make sure our FileProvider doesn't conflict with FileProviders declared in imported dependencies as described here.
Steps to replace file:// uri with content:// uri:
add a class extending FileProvider
public class GenericFileProvider extends FileProvider {
}
add a FileProvider tag in AndroidManifest.xml under tag. Specify an unique authority for the android:authorities attribute to avoid conflicts, imported dependencies might specify ${applicationId}.provider and other commonly used authorities.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...
<provider
android:name=".GenericFileProvider"
android:authorities="${applicationId}.my.package.name.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
</manifest>
then create a provider_paths.xml file in xml folder under res folder. Folder may be needed to create if it doesn't exist.
The content of the file is shown below. It describes that we would like to share access to the External Storage at root folder (path=".") with the name external_files.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
The final step is to change the line of code below in
Use the below mentioned code to open excel file :
File file = new File(Environment.getExternalStorageDirectory()+ "/filepath/" + filename);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file),"application/vnd.ms-excel");
startActivity(intent);
Edit: If using an intent to make the system open your file, you may need to add the following line of code:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Hope this will help...:)
Please refer, full code and solution has been explained here.
If your targetSdkVersion is 24 or higher, you can not use file: Uri values in Intents on Android 7.0+ devices.
Your choices are:
Drop your targetSdkVersion to 23 or lower, or
Put your content on internal storage, then use FileProvider to make it available selectively to other apps
For example:
Intent i=new Intent(Intent.ACTION_VIEW, FileProvider.getUriForFile(this, AUTHORITY, f));
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(i);

Launching Adobe Air app from my Android app

It it possible to start an adobe air apk from my current android app?
I tried this code but I got ActivityNotFoundException:
Intent intent = new Intent();
intent.setAction("air.caarsvcmobile.debug");
startActivity(intent);
Manifest:
<activity
android:name="caarsvcmobile"
android:label="CAARS Video Chat" >
<intent-filter>
<action android:name="air.caarsvcmobile.debug" />
</intent-filter>
</activity>
Is it possible to check package name and class name of an Air app?
After some Googling I found the solution of my problem:
Since I only knew the package name of the apk file I could use this code to launch the default launcher activity.
Intent i = new Intent(Intent.ACTION_MAIN);
PackageManager manager = getPackageManager();
i = manager.getLaunchIntentForPackage("air.caarsvcmobile.debug");
i.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(i);
Thats all. I works fine.

Categories