I followed this simple app AndroidScannerDemo which has two main button open camera and open gallery. The Camera is working fine on my phone API 19, but when I try to launch the camera on other devices or emulator the app crash.
From what I could understand this could be due to permission
Edit : Apparently this was asked here awhile ago as well but the issue remain
Wrong Update : the root problem coming from createImageFile method
I tried changing
//cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempFileUri); to
cameraIntent.putExtra(ScanConstants.OPEN_INTENT_PREFERENCE, preference);
I'm able to start the camera but I get crash right after taking picture
Update 2 : I'm trying following this article provided the answer below the only issue I'm using fragment
So How do I change this line
tempFileUri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
"com.scanlibrary.provider", // As defined in Manifest
file);
to
tempFileUri = FileProvider.getUriForFile(PickImageFragment.this,
getString(R.string.file_provider_authority),
file); inside a fragment !
Wrong First argument PickImageFragment
EDIT : Changed openCamera() method inside PickImageFragment
What Im I missing ?
Stack trace
2019-11-29 23:45:05.750 27993-27993/com.nabeeltech.capturedoc E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.nabeeltech.capturedoc, PID: 27993
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nabeeltech.capturedoc/com.scanlibrary.ScanActivity}: java.lang.SecurityException: UID 10091 does not have permission to content://com.scanlibrary.provider/external_files/scanSample/IMG_20191129_224505.jpg [user 0]
Caused by: java.lang.SecurityException: UID 10091 does not have permission to content://com.scanlibrary.provider/external_files/scanSample/IMG_20191129_224505.jpg [user 0]
at com.scanlibrary.PickImageFragment.openCamera(PickImageFragment.java:131)
at com.scanlibrary.PickImageFragment.handleIntentPreference(PickImageFragment.java:79)
at com.scanlibrary.PickImageFragment.init(PickImageFragment.java:60)
at com.scanlibrary.PickImageFragment.onCreateView(PickImageFragment.java:50)
PickImageFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.pick_image_fragment, null);
init();
return view;
}
private void init() {
cameraButton = (ImageButton) view.findViewById(R.id.cameraButton);
cameraButton.setOnClickListener(new CameraButtonClickListener());
galleryButton = (ImageButton)
view.findViewById(R.id.selectButton);
galleryButton.setOnClickListener(new GalleryClickListener());
if (isIntentPreferenceSet()) {
handleIntentPreference();
} else {
getActivity().finish();
}
}
private void handleIntentPreference() {
int preference = getIntentPreference();
if (preference == ScanConstants.OPEN_CAMERA) {
openCamera();
} else if (preference == ScanConstants.OPEN_MEDIA) {
openMediaContent();
}
}
public void openCamera() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri tempFileUri = null;
File file = createImageFile();
boolean isDirectoryCreated = file.getParentFile().mkdirs();
Log.d("", "openCamera: isDirectoryCreated: " + isDirectoryCreated);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tempFileUri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
"com.scanlibrary.provider", // As defined in Manifest
file);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempFileUri);
} else {
tempFileUri = Uri.fromFile(file);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempFileUri);
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
cameraIntent.setClipData(ClipData.newRawUri("", tempFileUri));
cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
startActivityForResult(cameraIntent, ScanConstants.START_CAMERA_REQUEST_CODE);
private File createImageFile() {
clearTempImages();
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new
Date());
File file = new File(ScanConstants.IMAGE_PATH, "IMG_" + timeStamp +
".jpg");
fileUri = Uri.fromFile(file);
return file;
}
private void clearTempImages() {
try {
File tempFolder = new File(ScanConstants.IMAGE_PATH);
for (File f : tempFolder.listFiles())
f.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
ScanConstants
public class ScanConstants {
public final static int PICKFILE_REQUEST_CODE = 1;
public final static int START_CAMERA_REQUEST_CODE = 2;
public final static String OPEN_INTENT_PREFERENCE = "selectContent";
public final static String IMAGE_BASE_PATH_EXTRA = "ImageBasePath";
public final static int OPEN_CAMERA = 4;
public final static int OPEN_MEDIA = 5;
public final static String SCANNED_RESULT = "scannedResult";
public final static String IMAGE_PATH = Environment
.getExternalStorageDirectory().getPath() + "/scanSample";
public final static String SELECTED_BITMAP = "selectedBitmap";
}
You've written the code Fileprovider.getUriforFile which is fine, but have you declare the permissions required.
The only way to solve this is to grant permissions to all of the packages that might need it, like this:
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
If above doesn't solve issue i'd suggest to refer this article by Lorenzo Quiroli that solves this issue for older Android versions.
He discovered that you need to manually set the ClipData of the Intent and set the permissions for it, like so:
if ( Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP ) {
takePictureIntent.setClipData( ClipData.newRawUri( "", photoURI ) );
takePictureIntent.addFlags( Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_READ_URI_PERMISSION );
}
Related
I have the following activity in my application:
public class DisplaySettingsActivity extends AppCompatActivity implements View.OnClickListener {
Button saveIntoFile;
TextView msg;
private ActivityResultLauncher<String> requestPermissionLauncher;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_settings);
requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
Log.d("H300s","Permissions Callback");
if (isGranted) {
Log.d("H300s","Permission Accepted 2");
saveFile();
} else {
permissionSaveDenied();
}
});
this.saveIntoFile = (Button)findViewById(R.id.save);
this.saveIntoFile.setOnClickListener(this);
}
private void saveFile(){
Log.d("Η300s","Saving");
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) {
Log.e("H300s","Unable to detect external storage");
saveMsgHandler(null);
return;
}
this.saveIntoFile.setEnabled(false);
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyMMdd");
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
file = new File( file.getAbsolutePath(),"voip_h300s_"+pattern.format(LocalDate.now())+".txt");
Log.d("H300s",file.toString());
try {
file.createNewFile();
PrintWriter out = new PrintWriter(new FileWriter(file));
out.println("SOME VALUES");
out.close();
saveMsgHandler(file.getAbsolutePath());
} catch (Exception e) {
saveMsgHandler(null);
}
}
#Override
public void onBackPressed() {
return;
}
private void saveMsgHandler(String savePath){
if (savePath == null) {
msg.setText(R.string.could_not_save_settings);
int errorColor = ContextCompat.getColor(this, R.color.error);
msg.setBackgroundColor(errorColor);
} else {
String string = String.format(getString(R.string.save_success),savePath);
msg.setText(string);
int success = ContextCompat.getColor(this, R.color.success);
msg.setBackgroundColor(success);
}
msg.setVisibility(View.VISIBLE);
this.saveIntoFile.setEnabled(true);
}
private void permissionSaveDenied(){
msg.setVisibility(View.VISIBLE);
msg.setText(R.string.could_not_save_settings);
int errorColor = ContextCompat.getColor(this, R.color.error);
msg.setBackgroundColor(errorColor);
this.saveIntoFile.setEnabled(true);
}
#Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d("H300s","Permission Accepted");
saveFile();
} else {
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE );
}
}
}
And I want once I save the file to be able to prompt into androids file manager and list the saved file. Any provided solution tells me hot to select a path before saving as seen in this answer or in this question, but instead I want just to show the file into device's file manager after I successfully saving it.
So far, what I've developed is this method:
public void displayFileIntoFileManager(String path){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
startActivity(intent, 7);
}
As a method to call from a button, once I saved the file in saveFile method. But how I can provide the path to the intent in order to be shown?
I just want to list the file into device's file manager.
I want just to show the file into device's file manager after I successfully saving it.
There is no standard Intent action for "open a file manager on a directory containing a specific file", sorry.
So far, what I've developed is this method
ACTION_GET_CONTENT is to allow the user to select a piece of content. If you are not looking to have the user do that, then this is not a suitable Intent action.
How I can prompt a file manager into a known path in an android app?
Wrong question.
You should have asked:
How can i let ACTION_GET_CONTENT, ACTION_OPEN_DOCUMENT and ACTION_OPEN_DOCUMENT_TREE open in a pre determined directory?
That question has been answered before.
The trick is to use extra INITIAL_URI.
In my application(which is run on a couple of type of tv-boxes from same manufacturer and all deviecs are rooted) I do check last version of my application from a server of my own and if there is a new version available, I download the APK file and try to install it using pm install command.
Though I've never started any activity to install the APK, it automatically opens the activity from intent Intent intent = new Intent(Intent.ACTION_VIEW);.
I've never used Intent.ACTION_VIEW in my whole project, so I assume that the android DownloadManager opens this activity automatically, and I want to stop it from doing so. Any idea how?
Here is my code:
//this is the method where I download the apk
//I'm putting only the important parts to make the question as short as possible
private void downloadApk() {
if (status == State.DOWNLOADING)
return;
setStatus(State.DOWNLOADING);
String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
String fileName = appType + versionInfo.getVersionName() + ".apk";
destination += fileName;
Uri uri = Uri.parse("file://" + destination);
String url = versionInfo.getUrl();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Downloading new Hub version");
request.setTitle("Downloading");
request.setDestinationUri(uri);
downloadId = manager.enqueue(request);
monitorDownloadPercentage();
mContext.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
This method only calculates how much of the file is downloaded in percentage and calls the callback with the value. This calculated value, on it's path updates one ProgressBar and gets set as the text of a TextView.
private void monitorDownloadPercentage() {
new Thread(new Runnable() {
#Override
public void run() {
downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = manager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.
getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (upgradeStateListener != null) {
upgradeStateListener.onDownloading((float) bytes_downloaded / bytes_total * 100);
}
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
}
}
}).start();
}
This is the broadcast receiver which gets fired when download is completed. And I'm sure this broadcast doesn't cause my problem since the only place in the code where could cause it is the onDownloadCompleted() method(which installs the APK using root privileges and I've commented all of it's body and it still pops up the activity.
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
final Cursor cursor = manager.query( new DownloadManager.Query().setFilterById(downloadId));
if (cursor.moveToFirst()) {
Uri uri ;
final String downloadedTo = cursor.getString(
cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
uri = Uri.parse(downloadedTo);
Log.d(TAG, "onReceive: it's ok " + uri.getPath());
upgradeStateListener.onDownloadCompleted(uri.getPath());
}
setStatus(State.DOWNLOADED);
mContext.unregisterReceiver(this);
}
};
I am trying to open zoom app by passing uri to the intent with below and it works fine.
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("<zoom url>"))
val packageManager = packageManager
if (intent.resolveActivity(packageManager) != null) {
startActivity(launchApp)
}
But this shows my browser also as user can select it and open the uri I pass. what I want to do is only open zoom app with the uri.
By using val activities = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) I can filter the apps that can open my intent but how can I select the exact app(zoom) and pass uri to it and open zoom app only with my meeting url?
May be need a packageName?
I referenced some code from Google in this
public static void openCustomTab(Activity activity,
CustomTabsIntent customTabsIntent,
Uri uri,
CustomTabFallback fallback) {
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
//If we cant find a package name, it means theres no browser that supports
//Chrome Custom Tabs installed. So, we fallback to the webview
if (packageName == null) {
if (fallback != null) {
fallback.openUri(activity, uri);
}
} else {
customTabsIntent.intent.setPackage(packageName);
customTabsIntent.launchUrl(activity, uri);
}
}
it use setPackage(),then the app will open the chrome app without chooser.
This is the method of getPackageNameToUse
static final String STABLE_PACKAGE = "com.android.chrome";
static final String BETA_PACKAGE = "com.chrome.beta";
static final String DEV_PACKAGE = "com.chrome.dev";
static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
...
...
public static String getPackageNameToUse(Context context) {
if (sPackageNameToUse != null) return sPackageNameToUse;
PackageManager pm = context.getPackageManager();
// Get default VIEW intent handler.
Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
String defaultViewHandlerPackageName = null;
if (defaultViewHandlerInfo != null) {
defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
}
// Get all apps that can handle VIEW intents.
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
List<String> packagesSupportingCustomTabs = new ArrayList<>();
for (ResolveInfo info : resolvedActivityList) {
Intent serviceIntent = new Intent();
serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
serviceIntent.setPackage(info.activityInfo.packageName);
if (pm.resolveService(serviceIntent, 0) != null) {
packagesSupportingCustomTabs.add(info.activityInfo.packageName);
}
}
// Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
// and service calls.
if (packagesSupportingCustomTabs.isEmpty()) {
sPackageNameToUse = null;
} else if (packagesSupportingCustomTabs.size() == 1) {
sPackageNameToUse = packagesSupportingCustomTabs.get(0);
} else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
&& !hasSpecializedHandlerIntents(context, activityIntent)
&& packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
sPackageNameToUse = defaultViewHandlerPackageName;
} else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
sPackageNameToUse = STABLE_PACKAGE;
} else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
sPackageNameToUse = BETA_PACKAGE;
} else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
sPackageNameToUse = DEV_PACKAGE;
} else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
sPackageNameToUse = LOCAL_PACKAGE;
}
return sPackageNameToUse;
}
Maybe it will help you.
I've a little problem. There are 2 days that I am trying to solve it without success.
I am trying to create an app that name every photo taken by a predefined name (ex : "coucou.jpg" instead of "IMG_20191119_201907.jpg").
So I've applyed some tutorials on the internet (https://developer.android.com/training/camera/photobasics.html#TaskPhotoView - https://www.youtube.com/watch?v=8890GpBwn9w (in french))
And it works !... Almost !
The photo are well created in the folder "Pictures".
But the problem that I have is the following : Created files don't receive the name that I gave to them. They are named 1574245595878.jpg - 1574245714222.jpg - 1574358229963.jpg - etc.
And I don't know where I'm wrong... I give you my code, normally, they should be called "coucou.jpg")
Can someone help me to give them the good name (or at least to rename them after creation in the same code) please ? It would be wonderful !
public class MainActivity extends AppCompatActivity {
private static final int RETOUR_PRENDRE_PHOTO = 1;
private Button btnPrendrePhoto;
private ImageView imgAffichePhoto;
private String photoPath = null;
private Bitmap image;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initActivity();
}
private void initActivity(){
btnPrendrePhoto = (Button)findViewById(R.id.btnPrendrePhoto);
imgAffichePhoto = (ImageView)findViewById(R.id.imgAffichePhoto);
btnPrendrePhoto.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
prendreUnePhoto();
}
});
}
private void prendreUnePhoto(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getPackageManager()) != null){
File photoDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
try {
File photofile = File.createTempFile("coucou",".jpg",photoDir);
photoPath = photofile.getAbsolutePath();
Uri photoUri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getApplicationContext().getPackageName()+".fileprovider", photofile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, RETOUR_PRENDRE_PHOTO);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==RETOUR_PRENDRE_PHOTO && resultCode==RESULT_OK){
image = BitmapFactory.decodeFile(photoPath);
imgAffichePhoto.setImageBitmap(image);
MediaStore.Images.Media.insertImage(getContentResolver(), image, "coucou.jpg", "description");
}
}
}
When you say createTempFile() it will append timestampInMillis to end of created File, that's the numbers you are looking at in your case, so try creating a normal File
replace
File photofile = File.createTempFile("coucou",".jpg",photoDir);
with
File image = new File(photoDir, "coucou.jpg");
i have read several already answered article on this site and used this
Sending message through WhatsApp
i am able to share from chrome but not from app.
my code is
public void onClickWhatsApp(View view) {
PackageManager pm=getPackageManager();
try {
Intent waIntent = new Intent(Intent.ACTION_SEND);
waIntent.setType("text/plain");
String text = "YOUR TEXT HERE";
PackageInfo info=pm.getPackageInfo("com.whatsapp", PackageManager.GET_META_DATA);
//Check if package exists or not. If not then code
//in catch block will be called
waIntent.setPackage("com.whatsapp");
waIntent.putExtra(Intent.EXTRA_TEXT, text);
startActivity(Intent.createChooser(waIntent, "Share with"));
} catch (NameNotFoundException e) {
Toast.makeText(MainActivity.this, "WhatsApp not Installed", Toast.LENGTH_SHORT).show();
}
}
when i click on share button in my android app whatsapp icon it gives error page not found but when same thing is shared from chrome it just works fine.
my url is http://way2enjoy.com/app/jokes.php
if anyone can guide where the mistake is i will be thankful
you can use my code which works for me
void openWhatsappContact(String number) {
Uri uri = Uri.parse("smsto:" + number);
Intent i = new Intent(Intent.ACTION_SENDTO, uri);
i.setPackage("com.whatsapp");
startActivity(Intent.createChooser(i, ""));}
enjoy your code time:)
you can use this code also
//method used to show IMs
private void show_custom_chooser(String value) {
List<ResolveInfo> list = null;
final Intent email = new Intent(Intent.ACTION_SEND);
email.setData(Uri.parse("sms:"));
email.putExtra(Intent.EXTRA_TEXT, "" + value);
email.setType("text/plain"); // vnd.android-dir/mms-sms
WindowManager.LayoutParams WMLP = dialogCustomChooser.getWindow()
.getAttributes();
WMLP.gravity = Gravity.CENTER;
dialogCustomChooser.getWindow().setAttributes(WMLP);
dialogCustomChooser.getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialogCustomChooser.setCanceledOnTouchOutside(true);
dialogCustomChooser.setContentView(R.layout.about_dialog);
dialogCustomChooser.setCancelable(true);
ListView lvOfIms = (ListView) dialogCustomChooser
.findViewById(R.id.listView1);
PackageManager pm = getPackageManager();
List<ResolveInfo> launchables = pm.queryIntentActivities(email, 0);
// ////////////new
list = new ArrayList<ResolveInfo>();
for (int i = 0; i < launchables.size(); i++) {
String string = launchables.get(i).toString();
Log.d("heh", string);
//check only messangers
if (string.contains("whatsapp")) {
list.add(launchables.get(i));
}
}
Collections.sort(list, new ResolveInfo.DisplayNameComparator(pm));
int size = launchables.size();
adapter = new AppAdapter(pm, list, MainActivity.this);
lvOfIms.setAdapter(adapter);
lvOfIms.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
ResolveInfo launchable = adapter.getItem(position);
ActivityInfo activity = launchable.activityInfo;
ComponentName name = new ComponentName(
activity.applicationInfo.packageName, activity.name);
email.addCategory(Intent.CATEGORY_LAUNCHER);
email.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
email.setComponent(name);
startActivity(email);
dialogCustomChooser.dismiss();
}
});
dialogCustomChooser.show();
}