NullPointerException when trying to get URI with FileProvider(Android) [duplicate] - android

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
i want to take a Photo after clicking on a button. But i am getting NullPointerException when trying to get URI with FileProvider.
Here is my ErrorCode:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:583)
at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:557)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:399)
at ibas.orosol.BildActivity.takePicture(BildActivity.java:86)
at java.lang.reflect.Method.invoke(Native Method) 
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 
at android.view.View.performClick(View.java:5637) 
at android.view.View$PerformClick.run(View.java:22429) 
at android.os.Handler.handleCallback(Handler.java:751) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6119) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
  
The Problem-Line seems to be:
mUri = FileProvider.getUriForFile(getApplication().getApplicationContext(),
"ibas.provider", file);
Here´s my Code:
public void takePicture(View view) throws IOException {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try{
File file = createImageFile();
mUri = FileProvider.getUriForFile(getApplication().getApplicationContext(),
"ibas.provider", file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
} catch (IOException e){
e.printStackTrace();
}
}
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
String path = "sdcard/orosol/captured_image.jpg";
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
Log.i("uri-data", "Uri: " + mUri.toString());
mBitmap = getBitmapFromUri(mImageView,BildActivity.this,mUri);
mImageView.setImageBitmap(mBitmap);
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
}
My Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ibas.orosol">
<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" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="ibas.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<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/Theme.AppCompat.NoActionBar">
<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=".MenuActivity" />
<activity
android:name=".HeizoelActivity"
android:theme="#style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MenuActivity" />
</activity>
<activity
android:name=".BildActivity"
android:theme="#style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MenuActivity" />
>
</activity>
<activity
android:name=".FacebookActivity"
android:theme="#style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MenuActivity" />
</activity>
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="#string/google_maps_key" />
<activity
android:name=".KontakteActivity"
android:theme="#style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MenuActivity" />
</activity>
<activity android:name=".UeberUnsActivity"
android:theme="#style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MenuActivity" />
</activity>
</application>
Provider in res/xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/> </paths>
Any Idea where the Problem Occurs?

The provider tag is outside of the application tag in the manifest file .
You should add it inside the <application></application> tag
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="ibas.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>

Related

Error while analyzing package during apk installation in app

I want to have the abilities to update my app from my application, so I can download my apk file ( each of them are signed ). And when the installation want to start:
First of all: I have preparation of installation popup which appear
Then: another popup appear and told me "A problem occurred while parsing the package"
My error is like this:
So my app, didn't update. Could you help me please ?
I use Xamarin Forms but especially for Android.
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.MyCompany.clamexdroid" android:installLocation="preferExternal">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application android:label="ClamexDroid" android:theme="#style/MainTheme" android:icon="#mipmap/ic_launcher">
</application>
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
</manifest>
My function when I click on my update Button
private async Task update()
{
this.popupIsVisible = false;
this.IsBusy = true;
string uri = "myLink.apk";
HttpClient cli = new HttpClient();
await cli.DownloadBasicFile(uri, DependencyService.Get<IDeviceDependency>().GetExternalAPKPath());
DependencyService.Get<IDeviceDependency>().InstallApk();
this.IsBusy = false;
}
And my InstallApk() function ( I'm sure that the file is downloaded )
public void InstallApk()
{
Intent promptInstall = new Intent(Intent.ActionView).SetDataAndType(
Android.Net.Uri.Parse($"content:///{this.GetExternalAPKPath()}"),"application/vnd.android.package-archive");
promptInstall.SetFlags(ActivityFlags.NewTask);
promptInstall.AddFlags(ActivityFlags.GrantReadUriPermission);
Android.App.Application.Context.StartActivity(promptInstall);
}
public string GetExternalAPKPath()
{
try
{
return Path.Combine(Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath, "com.MyCompany.clamexdroid.apk");
}
catch (Exception e) { Console.WriteLine(e.Message); }
return "";
}
At first, you can check the apk file you had downloaded has any damage. And then you can try to the following steps to install the apk:
1.Add the provider in the AndroidManifest.xml, such as:
<application android:allowBackup="true" android:icon="#drawable/androidicon" android:label="#string/app_name" android:supportsRtl="true" android:theme="#style/AppTheme">
<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" />
</provider>
</application>
2.Create the provider_paths.xml in the folder named xml below the values folder in the android part.
<paths >
<external-path
name="external_files"
path="." />
</paths>
3.Use the following code to install the apk:
var path = Path.Combine(Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath, "com.MyCompany.clamexdroid.apk");
Java.IO.File file = new Java.IO.File(path);
Intent install = new Intent(Intent.ActionView);
Android.Net.Uri apkURI = FileProvider.GetUriForFile(this, this.ApplicationContext.PackageName + ".provider", file);
install.SetDataAndType(apkURI, "application/vnd.android.package-archive");
install.AddFlags(ActivityFlags.NewTask);
install.AddFlags(ActivityFlags.GrantReadUriPermission);
StartActivity(install);

Getting unable to attach file error while attaching file in Gmail

I am trying to attach a pdf file from Downloads folder of internal storage to Gmail app using Intent. But it gives me error of Unable to attach the file. I am using FileProvider for getting the file of downloads folder. Here is the code that I have written.
MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File pdfDirectory = new File(Environment.getExternalStorageDirectory(), "Download");
File pdfFile = new File(pdfDirectory, "fileName.pdf");
Uri pdfFileContentUri = FileProvider.getUriForFile(this, APPLICATION_ID + ".fileprovider", pdfFile);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_STREAM, pdfFileContentUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
}
AndroidManifests
<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="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
provider_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Can somebody guide how to solve this issue?

Install application in Android N programmatically

I want to install an apk in my application and I'm using this method but all the time I get the errors listed below:
Code
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test.apk");
Uri fileUri = Uri.fromFile(file);
if (Build.VERSION.SDK_INT >= 24) {
fileUri = FileProvider.getUriForFile(DLActivity.this, "codenevisha.com.apps.bartarinapp.provider",file);
}
Intent intent = new Intent(Intent.ACTION_VIEW, fileUri);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.setDataAndType(fileUri, "application/vnd.android" + ".package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
And this is my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="codenevisha.com.apps.bartarinapp">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:name=".utils.G"
android:allowBackup="true"
android:icon="#mipmap/logo_chabok"
android:label="#string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="codenevisha.com.apps.bartarinapp.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/paths"/>
</provider>
<activity
android:name=".activity.ActivitySplash"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".activity.DLActivity">
</activity>
</application>
</manifest>
I used this path.xml file:
<external-files-path
name="share"
path="."/>
But when I run my application get this error:
Process: codenevisha.com.apps.bartarinapp, PID: 21392
java.lang.RuntimeException: Unable to start activity ComponentInfo{codenevisha.com.apps.bartarinapp/codenevisha.com.apps.bartarinapp.activity.DLActivity}: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/test.apk
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/test.apk
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
at codenevisha.com.apps.bartarinapp.activity.DLActivity.onCreate(DLActivity.java:46)
at android.app.Activity.performCreate(Activity.java:6955)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
Why is this error happening?
Your FileProvider is misconfigured. Your FileProvider metadata needs an <external-path> element, and you do not have one. See the documentation.
I tested the below code.
Add below permission in Menifest
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Below code for installing package
//// TODO: 1/16/18 Check the external storage permission
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test.apk");
Uri fileUri = Uri.fromFile(file);
if (Build.VERSION.SDK_INT >= 24) {
String packageId = getApplicationContext().getPackageName();
fileUri = FileProvider.getUriForFile(MainActivity.this, packageId + ".files", file);
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.setDataAndType(fileUri, "application/vnd.android" + ".package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
Provider in Menifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.files"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
file_paths.xml
<paths>
<external-path name="external" path="/"/>
Per the Android documentation on EXTRA_NOT_UNKNOWN_SOURCE:
For this to work you must start the installer with startActivityForResult().

Installing Android apk from Unity Application [duplicate]

This question already has answers here:
How to install Android apk from code in unity
(6 answers)
Error: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser
(1 answer)
Closed 5 years ago.
I recently read This post and write below code lines for installing .apk file in my unity application :
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject unityContext = currentActivity.Call<AndroidJavaObject>("getApplicationContext");
//Get the package Name
string packageName = unityContext.Call<string>("getPackageName");
string authority = packageName + ".fileprovider";
AndroidJavaClass intentObj = new AndroidJavaClass("android.content.Intent");
string ACTION_VIEW = intentObj.GetStatic<string>("ACTION_VIEW");
AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);
int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic<int>("FLAG_ACTIVITY_NEW_TASK");
int FLAG_GRANT_READ_URI_PERMISSION = intentObj.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION");
//File fileObj = new File(String pathname);
AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", filePath);
//FileProvider object that will be used to call it static function
AndroidJavaClass fileProvider = new AndroidJavaClass("android.support.v4.content.FileProvider");
//getUriForFile(Context context, String authority, File file)
AndroidJavaObject uri = fileProvider.CallStatic<AndroidJavaObject>("getUriForFile", unityContext, authority, fileObj);
intent.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
intent.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_NEW_TASK);
intent.Call<AndroidJavaObject>("addFlags", FLAG_GRANT_READ_URI_PERMISSION);
currentActivity.Call("startActivity", intent);
but after running and call this function my application forced to stop.
here is my Android manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="Store.Narenjgame.store"
android:versionCode="1.2"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application android:icon="#drawable/app_icon"
android:label="#string/app_name"
android:debuggable="false"
android:supportsRtl="true"
android:allowBackup="true">
<activity android:name="com.unity3d.player.UnityPlayerNativeActivity" android:label="#string/app_name" android:screenOrientation="fullSensor" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
</activity>
</application>
</manifest>
My android device sdk version is 24.
How can I install apk in unity android application?

Android / Google Plus - Cannot share image from my content provider

I have used this code and can successfully share an image (from my phone's gallery) with text to google+ from my Android app.
However, when I try to post an image from my app's content provider, the image is showing up on my google+ page like this...
...and that is despite the intended image being displayed fine on the google+ app preview screen.
The code I am using to share is:
String message = "My message";
Uri localImageUri = ContentUris.withAppendedId(DbContentProvider.CONTENT_URI_PRODUCTS, mProductId;
PlusShare.Builder builder = new PlusShare.Builder(getActivity());
builder.setText(message);
builder.addStream(localImageUri);
builder.setType("image/jpeg");
Intent shareIntent = builder.getIntent();
startActivityForResult(shareIntent, RC_GOOGLE_PLUS);
...and, like I say, the image is successfully displayed on the final google+ page if the localImageUri value is for a resource in my phone's Gallery - whereas the above placeholder image is shown if I set localImageUri to a uri from my app's own content provider.
So I presume there must be an issue with my content provider, which is defined in my manifest as:
<provider
android:name=".DbContentProvider"
android:authorities="com.example.provider"
android:exported="true"
android:grantUriPermissions="true" />
So, could there be something missing from my manifefst - or even from my searchable.xml file:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/app_name"
android:hint="#string/search_hint"
android:searchSuggestAuthority="com.example.provider"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchSuggestIntentData="content://com.example.provider/suggest"
android:searchSuggestThreshold="3"
android:includeInGlobalSearch="true"
android:searchSettingsDescription="#string/search_settings_description"
android:queryAfterZeroResults="true"
android:voiceSearchMode="showVoiceSearchButton" >
</searchable>
If not, then what could the problem be?
Update (Following CommonsWare's comment)
Exceptions were indeed thrown by the Google+ library because as well doing a query on the _data column (which existed), the Google+ API was also looking for columns that didn't exist - namely, datetaken, date_added, date_modified.
So I have added these columns to my database table - adding them all as text columns with recent millis values such as '1419379390000' (ref here) but I still get the same placeholder image being displayed on my Google+ page.
So I added some logging code to the query() method of my DbContentProvider class and when google+ does its single-column query for datetaken, the value returned in the cursor is indeed 1419379390000. However, the value returned for the (separate) _data query is null.
I'm not sure why the google API queries the _data column (because I do not need to call it in my code when I retrieve the image from the database in order to show in on the UI - instead, I call...
Uri localImageUri = ContentUris.withAppendedId(DbContentProvider.CONTENT_URI_PRODUCTS, mProductId);
InputStream in = cr.openInputStream(localImageUri);
Bitmap img = BitmapFactory.decodeStream(in);
imageView.setImageBitmap(img);
...but presumably the null in my cursor for the _data value is the problem. Not sure where to start to address this, though??
30-Dec-2014 Update
Here is the LogCat output. So, when I click my g+ button...
12-30 21:45:34.344: D/DbContentProvider(24633): getType(content://com.example.provider/products/1668)
12-30 21:45:34.534: D/DbContentProvider(24633): getType(content://com.example.provider/products/1668)
12-30 21:45:34.544: D/DbContentProvider(24633): openFile(content://com.example.provider/products/1668, r)
12-30 21:45:34.584: D/DbContentProvider(24633): openFile(content://com.example.provider/products/1668, r)
12-30 21:45:34.604: D/DbContentProvider(24633): openFile(content://com.example.provider/products/1668, r)
12-30 21:45:34.604: D/DbContentProvider(24633): openFile(content://com.example.provider/products/1668, r)
12-30 21:45:34.624: D/DbContentProvider(24633): openFile(content://com.example.provider/products/1668, r)
...that brings up the g+ screen for customising the share message (which, I confirm, does include the image from my content provider). So I then click the Share button on the g+ screen and the LogCat output is...
12-30 21:45:57.526: D/DbContentProvider(24633): openFile(content://com.example.provider/products/1668, r)
12-30 21:45:57.576: D/DbContentProvider(24633): getType(content://com.example.provider/products/1668)
12-30 21:45:57.576: D/DbContentProvider(24633): DbContentProvider - query(content://com.example.provider/products/1668)
12-30 21:45:57.576: D/DbContentProvider(24633): - projection: {"datetaken"}
12-30 21:45:57.576: D/DbContentProvider(24633): - selection: null
12-30 21:45:57.576: D/DbContentProvider(24633): - selectionArgs: null
12-30 21:45:57.576: D/DbContentProvider(24633): - sortOrder: null
12-30 21:45:57.576: D/DbContentProvider(24633): SQL (without selectionArgs): SELECT datetaken FROM products WHERE (_id = 1668) LIMIT 1
12-30 21:45:57.596: D/DbContentProvider(24633): returned value: 1419379390000
12-30 21:45:57.596: D/DbContentProvider(24633): cursor count: 1
12-30 21:46:03.642: D/DbContentProvider(24633): getType("content://com.example.provider/products/1668") - returns "vnd.android.cursor.item/vnd.example.elemental"
23-Jan-2015 Update
Here is my manifest in full:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example"
android:versionCode="10"
android:versionName="0.10" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="20" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="com.example.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.permission.C2D_MESSAGE" />
<uses-permission android:name="com.android.vending.BILLING" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
<provider
android:name=".DbContentProvider"
android:authorities="com.example.provider"
android:exported="false"
android:grantUriPermissions="false" >
<grant-uri-permission android:pathPrefix="/products" />
</provider>
<activity
android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:theme="#android:style/Theme.Translucent" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</activity>
<activity
android:name=".SplashActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<intent-filter android:label="#string/app_name_short">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".LoginActivity"
android:label="#string/title_activity_login"
android:windowSoftInputMode="stateHidden" >
</activity>
<activity
android:name=".HomeActivity"
android:label="#string/app_name_short"
android:windowSoftInputMode="adjustPan" >
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchResultsActivity" />
</activity>
<activity
android:name=".SearchResultsActivity"
android:label="#string/app_name_short"
android:launchMode="singleTop"
android:parentActivityName=".HomeActivity"
android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchResultsActivity" />
</activity>
<activity
android:name=".SingleShoppingListActivity"
android:label="#string/shopping_list"
android:parentActivityName=".HomeActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<activity
android:name=".SingleProductActivity"
android:label="#string/shopping_list_item"
android:parentActivityName=".HomeActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<activity
android:name=".InfoMenuActivity"
android:label="#string/why_gmo_free"
android:parentActivityName=".HomeActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<activity
android:name=".InfoContentActivity"
android:label="#string/why_gmo_free"
android:parentActivityName=".InfoMenuActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".InfoMenuActivity" />
</activity>
<activity
android:name=".SettingsActivity"
android:label="#string/settings"
android:parentActivityName=".HomeActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<activity
android:name=".TwitterCallbackActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="twitter"
android:scheme="oauth" />
</intent-filter>
</activity>
<activity
android:name=".DummyActivity"
android:label="#string/title_activity_dummy" >
</activity>
<activity
android:name=".SmartSearchResultsActivity"
android:label="#string/app_name_short"
android:parentActivityName=".SearchResultsActivity"
android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".SearchResultsActivity" />
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchResultsActivity" />
</activity>
<activity
android:name=".WebViewActivity"
android:label="#string/app_name_short"
android:parentActivityName=".HomeActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<activity
android:name=".UpgradeActivity"
android:label="#string/upgrade_to_pro_qm" >
</activity>
</application>
</manifest>
This is an interesting problem. If your ContentProvider is exported (which is not entirely clear in the question -- it seems to be in the first snippet you posted, but not in the full AndroidManifest.xml added later) what you're doing should work. Not sure why it doesn't.
In any case, you can certainly share any image file to the Google+ app by means of a FileProvider:
FileProvider is a special subclass of ContentProvider that facilitates
secure sharing of files associated with an app by creating a
content:// Uri for a file instead of a file:/// Uri.
Therefore, if your image is actually a file under getFilesDir() (very likely) or can be at least moved there, then you can apply this solution.
First you must define the provider in your AndroidManifest.xml file:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.testshare.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
Then this file in res\xml\filepaths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="shared_images" path="shared_images/" />
</paths>
Then, to share an image file, first make sure it's in the path specified above (i.e. shared_images under getFilesDir() -- you don't need the WRITE_EXTERNAL_STORAGE permission to copy if there because this location is inside your own app's private storage area). Then build the share intent as follows:
File file = getImageFileToShare();
Uri fileUri = FileProvider.getUriForFile(this, "com.example.testshare.fileprovider", file);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setType("image/png");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
(Make sure the authority specified in the getUriForFile() method matches the one in the manifest).
This will produce a content:// Uri (like content://com.example.testshare.fileprovider/shared_images/img1.png that the Google+ app will be able to access, and thus include in the post).

Categories

Resources