I'm creating an app using flash cc. I needed storage permission. It turns out I needed to ask user the permission for using storage devices. I can ask user for permission and it is working fine. I use examples from this website: https://helpx.adobe.com/flash-player/release-note/fp_24_air_24_release_notes.html
But my problem is I wasn't able to capture the complete event for accessing the storage permission. Because of that I couldn't run codes after I get access to storage. Is it possible to capture complete event for granting any permission?
the code I used:
var file:File = File.documentsDirectory.resolvePath("somefile.txt");
trace("url_txt:" + file.url);
file.addEventListener(PermissionEvent.PERMISSION_STATUS, function permissionStatusHandler(e:PermissionEvent):void
{
file.removeEventListener(PermissionEvent.PERMISSION_STATUS, permissionStatusHandler);
if(e.status == PermissionStatus.GRANTED)
{
myTextLoader.load(new URLRequest(file.url));
myTextLoader.addEventListener(Event.COMPLETE, onLoadTextComp);
myTextLoader.addEventListener(IOErrorEvent.IO_ERROR, loadingTextError);
}
else
{
showPermissionError();
}
}
);
try
{
trace("Requesting permission");
file.requestPermission();
}
catch(error:Error)
{
trace("Request permission error");
}
UPDATE:
The above code seems to work fine. But the problem occurs when I tried to request for same permission twice at different time. I've another question. Can we add description while we request permission? A lot of app seems to be adding description why the app need that particular permission. Is it possible do achieve this from flash as3? I've looked into web but couldn't find anything. And how to request permission for READ_PHONE_STATE?
Finally, I figured it out. Prerequisites:
AIR runtime 24+
Android 6+
APK must be published with WRITE_EXTERNAL_STORAGE permission (otherwise it is automatically DENIED - that what I was stuck at)
Then, this code works for me just fine, it displays Android's "Grant Permission" dialog and then outputs GRANTED or DENIED with regard to my choice. The Log class is just a debug panel of my own, you can change Log.log calls to trace or grab it here (it has no dependencies): https://bitbucket.org/thydmitry/ru.delimiter/src/9083fb46ce1c/classes/ru/delimiter/utils/
package
{
import ru.delimiter.utils.Log;
import flash.filesystem.File;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.PermissionEvent;
import flash.permissions.PermissionStatus;
public class Permissions extends Sprite
{
private var F:File;
public function Permissions()
{
if (stage) onStage();
else addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
Log.create(this, true);
Log.log("[Permissions Test] started");
Log.log("File.permissionStatus:", File.permissionStatus);
F = File.applicationStorageDirectory.resolvePath("somefile.txt");
F.addEventListener(PermissionEvent.PERMISSION_STATUS, onPerm);
stage.addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void
{
F.requestPermission();
}
private function onPerm(e:PermissionEvent):void
{
Log.log("User's decision:", e.status.toUpperCase());
}
}
}
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
(See UPDATE below)
I have a Xamarin Forms app on Android which uses the Xamarin.Essentials library.
The app requires to run in the background to be fed location data (not particularly relevant to the question in hand, but included for context), and so must not be put to sleep by any battery optimisations that the OS might attempt.
I know that the user can manually opt out specific apps from Battery Optimizations, but as it is so crucial to the successful operation of the app, I would like the app to be able to :
check the Battery Optimization Opt-out permission status to ensure it is appropriately set,
and/or
force Android to opt the app of any battery optimizations.
I have added an entry into AndroidManifest.xml, but it doesn't seem to help, with the newly-installed app defaulting to being Battery Optimized.
AndroidManifest.xml
The manifest contains the following entry:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Xamarin.Essentials
This library gives access to a number of permission-related info on the device, but Battery Optimizations doesn't seem to be one of them.
Device being used
I don't know if it's relevant, but I am testing on a Samsung Galaxy S20 Ultra.
Can anyone offer any advice?
UPDATE Aug 28 2021
Following the advice from contributors and with reference to the docs at https://learn.microsoft.com/en-us/xamarin/essentials/permissions?tabs=android#extending-permissions ...
In My Shared Code
public interface IRequestIgnoreBatteryOptimizationPermission
{
Task<PermissionStatus> CheckStatusAsync();
Task<PermissionStatus> RequestAsync();
}
In My Android Project
[assembly: Xamarin.Forms.Dependency(typeof(RequestIgnoreBatteryOptimizationPermission))]
namespace MyAndroidProject
{
public class RequestIgnoreBatteryOptimizationPermission : Permissions.BasePlatformPermission, IRequestIgnoreBatteryOptimizationPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)>
{
(Android.Manifest.Permission.RequestIgnoreBatteryOptimizations, true)
}.ToArray();
}
}
On Shared App Initialization
// Ensure Required Permissions have been granted
var requestIgnoreBatteryOptimizationPermission = DependencyService.Get<IRequestIgnoreBatteryOptimizationPermission>();
var status = requestIgnoreBatteryOptimizationPermission.CheckStatusAsync().Result;
if (status != PermissionStatus.Granted)
{
status = requestIgnoreBatteryOptimizationPermission.RequestAsync().Result;
}
Result...
On calling CheckStatusAsync, the result comes back as Granted.
But the app settings still say otherwise...
I've tried it on both a physical device (Samsung Galaxy S20 Ultra) and on an Android Emulator (Pixel 2 API 28), with same result on both.
From this document, there are two ways to set Battery Optimization
An app can fire the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent to take the user directly to the Battery Optimization, where they can add the app.
An app holding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission can trigger a system dialog to let the user add the app to the exemption list directly, without going to settings. The app fires a ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Intent to trigger the dialog.
I use PowserManager.isIgnoringBatteryOptimizations to check Battery Optimization.
Firstly, add RequestIgnoreBatteryOptimizations in AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Then creating Interface in Shared code.
public interface IBattery
{
void getbattery();
}
Implementing this interface in Android platform.
[assembly: Dependency(typeof(ImplementBattery))]
namespace FormsSample.Droid
{
public class ImplementBattery : IBattery
{
public void getbattery()
{
Intent intent = new Intent();
String packageName = MainActivity.mac.PackageName;
PowerManager pm = (PowerManager)MainActivity.mac.GetSystemService(Context.PowerService);
if (pm.IsIgnoringBatteryOptimizations(packageName))
intent.SetAction(Android.Provider.Settings.ActionIgnoreBatteryOptimizationSettings);
else
{
intent.SetAction(Android.Provider.Settings.ActionRequestIgnoreBatteryOptimizations);
intent.SetData(Android.Net.Uri.Parse("package:" + packageName));
}
MainActivity.mac.StartActivity(intent);
}
}
}
Creating static Mainactivity field in Mainactivity.cs.
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity mac;
protected override void OnCreate(Bundle savedInstanceState)
{
initFontScale();
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
mac = this;
Now, using DependencyService to fire.
private void Button_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IBattery>().getbattery();
}
In your MainActivity add two properties:
private const int RequestPermissionsId = 0
and
private readonly string[] ManifestPermissions =
{
Manifest.Permission.RequestIgnoreBatteryOptimizations
// Add here other permissions you want to check
}
Then override the OnStart method and force permission check there:
public override void OnStart()
{
base.OnStart();
if ((int)Build.VERSION.SdkInt >= 23)
{
if (CheckSelfPermission(Manifest.Permission.RequestIgnoreBatteryOptimizations != Permission.Granted)
RequestPermissions(ManifestPermissions, RequestPermissionsId);
}
}
And of course, remember that you must have the OnRequestPermissionsResult method implemented:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
Well, I am guessing you are trying to check it directly through shared code
The easiest way to do it would be to extend the needed permission in native using essentials.
Check the status and request permission through an interface:
public interface IRequestIgnoreBatteryOptimizations
{
Task<PermissionStatus> CheckStatusAsync();
Task<PermissionStatus> RequestAsync();
}
Implement the native part for the same:
public class IgnoreBatteryOptimizationsPlatformPermission : Xamarin.Essentials.Permissions.BasePlatformPermission, IRequestIgnoreBatteryOptimizations
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
new (string, bool)[] { (Manifest.Permission.RequestIgnoreBatteryOptimizations, true) };
}
Then register it in your Native XF caller class(MainActivity, Appdelegate(for some other permission))
DependencyService.Register<IRequestIgnoreBatteryOptimizations, IgnoreBatteryOptimizationsPlatformPermission>();
And then in your XF class use this method:
public static async Task<PermissionStatus> CheckAndRequestBatteryOptimizations()
{
var batteryOptimizationsPermission = DependencyService.Get<IRequestIgnoreBatteryOptimizations>();
var status = await batteryOptimizationsPermission.CheckStatusAsync();
if (status != PermissionStatus.Granted)
{
status = await batteryOptimizationsPermission.RequestAsync();
}
return status;
}
And then request for it whenever you like:
var status= await CheckAndRequestBatteryOptimizations();
More information here: https://learn.microsoft.com/en-us/xamarin/essentials/permissions?tabs=android#extending-permissions
I created a simple app using Meteor 1.3, which has only one method. It works like that: When a button is clicked, the method is invoked - it calculates a specific value and returns the result.
The app works perfectly on the localhost server, but when I launch it on my device with "meteor run android-device", it cannot access the method (simply opens the app, but nothing happens when I press a button.
Do you know how I could resolve this?
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
import './main.html';
Template.check.onCreated(function checkOnCreated() {
this.state = new ReactiveDict();
});
Template.check.events({
'click .checkit'(event, instance) {
Meteor.call('code.check', function(error, result){
if(error){
console.log('Error from the client side!');
} else {
instance.state.set('fett', result.titles[0]);
}
});
},
});
Template.check.helpers({
fett() {
const instance = Template.instance();
if (instance.state.get('fett')) {
return instance.state.get('fett');
} else {
return 'Value still not known...'
}
},
});
Ensure your smartphone's WiFi is turned on and it connected to the same WiFi network as you computer where meteor app is running. Then everything should work fine.
Also, I recommend to use chrome://inspect feature (more info here) in order to debug your app on Android. Then, you will be able quickly investigate any problems with mobile app.
I'm looking for a programmatic way to set-up http proxy settings for android handsets. I've tried using android.provider.Settings.System.putString() to set System.HTTP_PROXY, but my call fails (I'm using a 2.2 emulator image at the moment). My code looks like:
if (System.putString(getContentResolver(), System.HTTP_PROXY, "10.10.2.1:8080")) {
tv.append("put for HTTP_PROXY succeeded.\n");
}
else {
tv.append("put for HTTP_PROXY failed.\n");
}
I've also added to my android manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
..although it's not clear from the docs which permission, if any, is required.
I'm familiar with this SO thread, but the technique there requires manual adb commands, which require the SDK tools and (possibly) a rooted phone.
Is there a way to accomplish this? Ideally, I'd like away to set an http proxy that will be used for both data and wifi connections.
It's not possible to do this as a 3rd-party app. You get this message:
12-07 12:39:37.736: W/PackageManager(85): Not granting permission android.permission.WRITE_SECURE_SETTINGS to package com.mgranja.xxxxxxx (protectionLevel=3 flags=0xbe46)
Only apps that are signed with the same key as system apps can get this permission (i.e.: if you cook your own rom, you could add that funcionality)
More info about permission levels on this question, specially adamk's answer.
Why are these permissions being refused?
If you are limiting the use of proxies to your own application you can use the Proxy and ProxySelector API.
To set the proxy check Mike's answer;
Following is code snippet to retrieve proxy details
public static String getProxyDetails(Context context) {
String proxyAddress = new String();
try {
if (IsPreIcs()) {
proxyAddress = android.net.Proxy.getHost(context);
if (proxyAddress == null || proxyAddress.equals("")) {
return proxyAddress;
}
proxyAddress += ":" + android.net.Proxy.getPort(context);
} else {
proxyAddress = System.getProperty("http.proxyHost");
proxyAddress += ":" + System.getProperty("http.proxyPort");
}
} catch (Exception ex) {
//ignore
}
return proxyAddress;
}
It'll return empty if some exception or no proxy detected;
You can set the proxy for your application VM, but due to security reasons, third party apps may not have the functionality to set device proxy.
I found something here that looks like it might work
package com.BrowserSettings;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.provider.Settings;
public class BrowserSettingsUI extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button = (Button) findViewById(R.id.Button01);
button.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
try {
Settings.System.putString(getContentResolver(),
Settings.System.HTTP_PROXY, "127.0.0.1:100");//enable proxy
}catch (Exception ex){
}
}
});
final Button button2 = (Button) findViewById(R.id.Button02);
button2.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
try {
Settings.System.putString(getContentResolver(),
Settings.System.HTTP_PROXY, "");//disable proxy
}catch (Exception ex){
}
}
});
}
}
You must add
<uses-permission android:name=”android.permission.WRITE_SETTINGS” />
to your manifest.
Did you try to call the com.android.settings.ProxySelector activity and let the user to enter the proxy? It's stored globally, but seems that it doesn't support the standard Proxy and ProxySelector API (for this problem there is already another question: How users/developers can set the Android's proxy configuration for versions 2.x?)