I'm trying to make a service that will run every 10 seconds to check a queue and if there is some data in the queue upload the given uri (uri of a picture just taken from the app) to a certain url.
I have created something along these lines
public QueueProcessor(final Context context){
this.mContext = context.getApplicationContext();
}
/**
* Starts processing the items on a separate thread.
*/
public void process() {
Runnable running = new Runnable() {
#Override
public void run() {
try{
Log.i(RUN_QP_TAG, "Processing queue");
// more here
isRunning = true;
Queue theQ = Queue.getInstance();
if(theQ.getSize() > 0){
WorkQItem itm = theQ.pop();
if(itm.hasImage()){
pushImageUploadToProcess(itm);
}
}
} catch (Exception e) {
// TODO: handle exception
}
finally{
//also call the same runnable to call it at regular interval
handler.postDelayed(this, 10000);
}
}
};
new Thread(running).start();
}
The pushImageUploadToProcess takes the WorkQItem and tries to upload the image from the item (which is saved as String picUri) by opening the uri and writing the bytes. However I get a permissions denied exception when trying to open the picUri location.
MediaDocumentsProvider uri content://com.android.providers.media.documents/document/image%3A531 from pid=795, uid=10327 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
How can I allow this Thread/Runnable to have access to the URI?
Note I have tried the upload directly from a button event and it does work.
I have the following permissions in the manifest:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
You should implement runtime permission, for that use below code
PermissionsManager.getInstance().requestAllManifestPermissionsIfNecessary(this, new PermissionsResultAction() {
#Override
public void onGranted() {
// Proceed with initialization
}
#Override
public void onDenied(String permission) {
// Notify the user that you need all of the permissions
}
});
add below dependency in your app gradle
compile 'com.anthonycr.grant:permissions:1.0'
It looks like the actual permission error is not the real issue. The real issue was the way I was choosing and picking the image.
I ended up using https://gist.github.com/Mariovc/f06e70ebe8ca52fbbbe2 this picker and it seemed to work without any issues.
I tweaked this code a little bit to suit my needs as any image picked from the camera needed to be saved too so that if there are several images being done and each is needed for later use the relative uri initially will get overwritten therefore you need a fixed one (e.g: to be saved).
Related
I've spend a day on this issue, and I'm stumped. I've read through numerous similar questions, and tried all the suggestions, but nothing worked for me.
I have an app, with a preference screen where the user can turn on Bluetooth. The preference screen sends an intent to the MainActivity, which then checks security permissions and if needed requests permission.
I am building against version SDK version 32.
In Manifest I have:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.bluetooth" android:required="true"/>
In MainActivity I check if permission is already granted:
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (Objects.equals(intent.getAction(), CustomIntent.CHECK_BLUETOOTH_SECURITY_PERMISSION)) {
int check = ContextCompat.checkSelfPermission( thisActivity, Manifest.permission.BLUETOOTH_CONNECT );
if ( check == PackageManager.PERMISSION_DENIED )
getPermission( Manifest.permission.BLUETOOTH_CONNECT, RequestCodes.BT_SECURITY_REQUEST.ordinal() );
}
and if not, I request permission.
When requesting permission, I have tried the old way with:
public void getPermission( String permission, int requestCode ) {
if ( shouldShowRequestPermissionRationale( permission ) ) {
// TODO: display a dialog to explain the reason for needing the permission
Toast.makeText( this, "Need to put together an explanation for the permission", Toast.LENGTH_LONG ).show();
} else {
requestPermissions( new String[]{ permission }, requestCode );
}
}
I have tried both with CompactActivity.requestPermissions and with just requestPermissions as above.
and I have also tried with the new way. In onCreate I have:
activityResultLauncher = registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
#Override
public void onActivityResult(Map<String, Boolean> result) {
Log.e("ActivityResultLauncher", ""+result.toString() );
Boolean areAllGranted = true;
for ( Boolean b : result.values() ) {
areAllGranted = areAllGranted && b;
}
if ( areAllGranted )
Log.e( "ActivityResultLauncher","It worked");
else
Log.e( "ActivityResultLauncher", "wah wah wah");
}
});
and in getPermission() i then call
activityResultLauncher.launch(new String[]{
Manifest.permission.BLUETOOTH_CONNECT
});
But no matter what I do, the user dialog asking the user to grant permission never show, and the onPermissionRequestResult just immediately return with False, i.e. Denied.
I don't see any error messages in the LogCat (outside of the log entries I put there myself). I've also tried to step through the Android libraries to see i can see any exception thrown, but all looks fine there as well.
UPDATE
Just as I posted this, I tried to clear the emulator device.
After that, the first time I ran the code, the app crashed, hard.
I was able to catch this in logCat
Attempting to launch an unregistered ActivityResultLauncher with >contract
androidx.activity.result.contract.ActivityResultContracts$RequestMultiplePermissions
and input [Ljava.lang.String. You must ensure the
ActivityResultLauncher is registered before calling launch().
I do register the activityResultLauncher in onCreate. So I'm not clear on why it doesn't know it's registered.
It's also weird that this error only happens first time I run the app after clearing device files.
Then I launched the app again, (without changing anything in my code) and this time it worked. The dialog was displayed, and I could grant permissions.
Anyone know what in the world is going on?
I am trying to show live stream from camera & microphone in <video> html element.
In blazor file (sample.razor) I invoke method to request and show video:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
await JSRuntime.InvokeVoidAsync("requestMediaAndShow");
}
}
In javascript file (sample.js) I request stream and assign to video html element.
// Create request options
let options = {
audio: true,
video: true
};
// Request user media
navigator.mediaDevices
.getUserMedia(options)
.then(gotLocalStream)
.catch(logError);
But when I am requesting i catch an error like "NotAllowedError: Permission denied".
AndroidManifest.xml contains:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
MainActivity.cs contains:
public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.Camera, Manifest.Permission.RecordAudio, Manifest.Permission.ModifyAudioSettings }, 0);
}
}
Any ideas how to request audio and video stream by javascript in BlazorWebView natively on android?
PS. On both on website and natively on Windows platform works great and no extra permissions are required.
Although the Android permissions seem to be granted OK, I suspected the website permissions were not. Not sure if the author of this question is the same person, but an issue was opened on the .NET MAUI repo as well about this.
While we are looking into making this work out of the box, another helpful user has posted this workaround for now.
Implement your own handler like so
public class MauiWebChromeClient : WebChromeClient
{
public override void OnPermissionRequest(PermissionRequest request)
{
request.Grant(request.GetResources());
}
}
public class MauiBlazorWebViewHandler : BlazorWebViewHandler
{
protected override WebChromeClient GetWebChromeClient()
{
return new MauiWebChromeClient();
}
}
And register this handler in your MauiProgram.cs:
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<IBlazorWebView, MauiBlazorWebViewHandler>();
});
This will automatically grant all the requested permissions from the web side of things.
I think you are missing some parts of the permission checks. You should read this section about runtime permissions that were introduced in Android 6.0. For example, I cannot see any override of OnRequestPermissionsResult in MainActivity.
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/permissions?tabs=macos#runtime-permission-checks-in-android-60
I try to load a image from my Firebase Storage with Picasso into an Imageview that is placed in a InfoWindowAdapter from a Marker.
I'm very desperate about it. The problem is Picasso only shows the placeholder Icon.
My code for the FirebaseStorageRefernce looks like this referring to this Firebase Blog post:
StorageReference load = getImage(id);
load.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
downloadUri = uri;
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e("Failure",e.toString());
}
});
The downloadUri that I get is valid and works fine. Now I use this downloadUri for Picasso.
Picasso picasso = new Picasso.Builder(getApplicationContext()).listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) {
e.printStackTrace();
}
}).build();
picasso.setLoggingEnabled(true);
picasso.load(downloadUri).placeholder(R.drawable.toxic_bait_icon).fit().into(thump, new MarkerCallback(marker));
In reference to an answer that I found here on StackOverFlow, I made a MarkerCallback Class:
public class MarkerCallback implements Callback {
com.google.android.gms.maps.model.Marker marker = null;
MarkerCallback(Marker marker)
{
this.marker = marker;
}
#Override
public void onError(){
Log.e(getClass().getSimpleName(), "Error loading thumbnail!");
}
#Override
public void onSuccess(){
Log.d("onSuccess","Picasso Callback");
if(marker != null && marker.isInfoWindowShown()){
Log.d("onSuccess","Picasso Callback in if");
marker.hideInfoWindow();
marker.showInfoWindow();
}
}}
You can see that I added some Log.d messages on the onSuccess method to track if it's called. But it looks like the onSucess method isn't called anytime because the Log.d message never appears in LogCat.
Also Picasso doesn't show any exception, errors, failures, nor a log even though I enabled it.
picasso.setLoggingEnabled(true);
The only thing that happens is that the ImageView in the Infowindow shows the Placeholder.
I thought maybe its because the image size too large to load, but the image I try to load is only 652.86 KB.
PS: Picasso also doesn't show the ribbons in the left corner to debug the cache behaviour. I try to activate with:
picasso.setIndicatorsEnabled(true);
I use Picasso 2.5.2. I have no idea what I'm doing wrong or how to debug this if Picasso doesn't show logs nor ribbons. I hope someone can help me. I need this feature so badly.
Addendum:
I have also check the permissions, referring to this post, they are OK.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission
android:name="android.permission.INTERNET"/>
<uses-permission
android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission
android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Update
After some trial-and-error, I found out that Picasso shows the log, but i don't see it in logcat. After I restart my phone, I saw the log in the logcat after a while. The log disappears again, but this time even a restart doesn't help the, log doesn't reappear.
But I've also done some research and found another answer that refers to my problem.
So I changed my code but it doesn't help. The issue is still the same. Picasso shows only the placeholder.
Why don't you do everything at once? Inside the Firebase Storage getDownloadUrl() method:
StorageReference load = getImage(id);
load.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
// Got the download URL for 'users/me/profile.png'
// Pass it to Picasso to download, show in ImageView and caching
Picasso.with(context).load(uri.toString()).into(imageView);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});
Using Kotlin extension functions to Task<Uri> as receiver:
fun Task<Uri>.loadIntoPicasso(imageView: ImageView){
addOnSuccessListener { Picasso.with(imageView.context).load(it).into(imageView) }
}
I've been working on an android program. One portion of this program interacts with a webservice using a socket connection, sending files that on average are about 320 kB. The code ran on a desktop takes about 1.5 minutes to transfer. Using my android phone (Atrix) it seems to be taking about an hour. The phone is connected to wifi so I wasn't expecting it to take such a long time. My initial thought was to add a wifi lock, but it hasn't helped any.
I have the actual upload running in a async task (For reading I've made some of it pseudo)
#Override
protected void onPreExecute()
{
//Before starting the task show the uploading dialog
uploadingDialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
//After the task close the dialog
uploadingDialog.dismiss();
}
#Override
protected Boolean doInBackground(String... params) {
//Upload the files in the background
//keep track of upload results
boolean uploaded = true;
boolean temp;
//lock wifi on and stop the program from sleeping
_keepOnStart();
//Upload each file individually
for(int i=0; i <= fileNameList.size()-1; i++){
//this method does the actual writing to the socket/converts
//the file to a byte array etc.
temp = serverConnection.uploadWord(fileNameList.get(i));
if(temp == false) {
uploaded = false;
}
}
_keepOnStop();
return uploaded;
}
private void _keepOnStart() {
if (_powerManagement == null) {
_powerManagement = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
}
if (_wakeLock == null) {
_wakeLock = _powerManagement.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE,
"0 Backup power lock");
}
_wakeLock.acquire();
WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
_wifiLock = wifiManager.createWifiLock("0 Backup wifi lock");
_wifiLock.acquire();
}
}
private void _keepOnStop() {
if ((_wifiLock != null) && (_wifiLock.isHeld())) {
_wifiLock.release();
}
if ((_wakeLock != null) && (_wakeLock.isHeld())) {
_wakeLock.release();
}
}
On the desktop version of the code I was just timing "serverConnection.uploadWord(fileNameList.get(i));" with a set file name.
The method itself grabs the byte data from the file, creates a packet to send to the server and then sends it out.
Some of my manifest permissions:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
I'm wondering if anyone can provide an explaination for this. My assumption is that the device is using it's data connection, but at the same time only background data is allowed on the device, and I see no data use in the last 7 days.
(any and all help is much appreciated. If I'm unclear in anyway please let me know.)
For anyone looking at the same thing. It seems this is the correct approach. The immense amount of time was a derivative of a very inefficient encoding scheme that was done before sending the data. (It did not scale well)
I'm using the android.location.Geocoder for the first time. The Idea is: I have a Listener on a button which takes input from an EditText and resolve the location. Up to now it's debugging phase, so I have no handler taking messages from the thread, only geocoding and write to logcat.
Q: Why this method always returns an empty list of Address objects?
private View.OnClickListener checkLocation = new View.OnClickListener() {
#Override
public void onClick(View v) {
location = ((EditText)findViewById(R.id.getLocation)).getText().toString();
Thread thr = new Thread(){
public void run (){
Log.d("Looking for", location);
Geocoder gc = new Geocoder(ctx,Locale.ITALY);
try {
fa= gc.getFromLocationName(location, 3);
if (fa.isEmpty())Log.d("getFromLocationName", "NothingFound");
else
{
int size= fa.size();
for (int i = 0; i<size ;i++)
Log.d("getFromLocationName.at("+ String.valueOf(i) +")", fa.get(i).getAddressLine(0)+", "+fa.get(0).getAddressLine(1));
}
} catch (IOException e) {
Log.e("IOException", e.getMessage());
}
}
};
thr.start();
}
};
manifest:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Somebody knows why? (btw I am using 1.6 sdk) Input tried
the project wasn't targeting the correct AVD. To use geolocation you have to make it point an avd implementing the google APIs. Once I changed it everything worked just fine. Sorry for bothering
Because it doesn't recognize the address you are putting in or it can't reach the service.
What address are you putting in? Try something as simple as a zip code or city or state name.