Android Xamarin: how to grant BindTelecomConnectionService permission? - c#

I have an issue making phone calls from the foreground service and this is my question about that.
As suggested in the comments of the question - I started testing the ConnectionService. I added BIND_TELECOM_CONNECTION_SERVICE permission to the manifest file.
Declared MyConnectionService class:
[Service(Permission= Manifest.Permission.BindTelecomConnectionService)]
public class MyConnectionService : ConnectionService
{
}
And then I run this code:
var telecomManager = (TelecomManager)GetSystemService(Context.TelecomService);
var phoneAccountHandle = new PhoneAccountHandle(
new ComponentName(this.PackageName, nameof(MyConnectionService)), "MyApp");
var builder = new PhoneAccount.Builder(phoneAccountHandle, "CustomAccount");
var phoneAccount = builder.Build();
telecomManager.RegisterPhoneAccount(phoneAccount);
The telecomManager.RegisterPhoneAccount(phoneAccount); gives me an exception:
Java.Lang.SecurityException: 'PhoneAccount connection service requires BIND_TELECOM_CONNECTION_SERVICE permission.'
Ok - it seems the permission is not granted. Testing it with ActivityCompat.CheckSelfPermission() - yes, it is not granted.
Making a permission request with ActivityCompat.RequestPermissions() - it is executed and that's it.
No permission request on the screen, not way to grant on the application permission page.
My question is - how to grant this kind of permission?
Environmet:
Android API Level 28
Testing on Google Pixel 2 XL phone running Android 10

Comments by SushiHangover helped a lot and pointed to the right direction. In order to make the solution work and avoid the exception, the ConnectionService should have proper name (fully qualified Java class name) and permission declaration. These values can be added either in the manifest file or by declaring the ServiceAttribute in the code:
[Service(
Name = "com.sample.MyApp.MyConnectionService",
Permission = Manifest.Permission.BindTelecomConnectionService,
Enabled = true)]
public class MyConnectionService : ConnectionService
{
}
Secondly, the name of the service must be exact when creating ComponentName instance:
var telecomManager = (TelecomManager)GetSystemService(Context.TelecomService);
var phoneAccountHandle = new PhoneAccountHandle(
new ComponentName(this.PackageName, "com.sample.MyApp.MyConnectionService"),
"GateOpener");
var builder = new PhoneAccount.Builder(phoneAccountHandle, "CustomAccount");
var phoneAccount = builder.Build();
telecomManager.RegisterPhoneAccount(phoneAccount);

Related

Remove user from folder permission using MS Graph

We have a C# application that is using the Microsoft Graph API to display the contents of SharePoint folder to users in a Syncfusion FileManager control. We need to grant permissions to those folders for certain users in order that they can collaborate on files.
We can add specific users using the sharing invitation to add a permission (see https://learn.microsoft.com/en-us/graph/api/driveitem-invite?view=graph-rest-1.0&tabs=http). We also need to be able to remove a user from this permission without deleting the whole link (and therefore any other users using it). I cannot see a way of doing this!
I have also tried using CreateLink (see https://learn.microsoft.com/en-us/graph/api/driveitem-createlink?view=graph-rest-1.0&tabs=http) but get an ‘Invalid Request’ error when trying to ‘Grant’ permission to a user and therefore never get as far as trying to remove an individual user!. The code I am using to try and 'Grant' permission is as follows (the last line produces the error):
public object CreateSharingLink(string itemId, List<string> recipientList, List<string> roles)
{
if (itemId == null) return null;
var type = "edit";
var scope = "organization";
Permission p = GraphClient.Drives[documentLibrary.Id].Items[itemId].CreateLink(type, scope).Request().PostAsync().Result;
return GrantAccessToSharingLink(p.Link.WebUrl, recipientList, roles);
}
public object GrantAccessToSharingLink(string sharingUrl, List<string> recipientList, List<string> roles)
{
List<DriveRecipient> recipients = (recipientList.Select(r => new DriveRecipient { Email = r })).ToList();
string base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sharingUrl));
string encodedUrl = "u!" + base64Value.TrimEnd('=').Replace('/', '_').Replace('+', '-');
return GraphClient.Shares[encodedUrl].Permission.Grant(roles, recipients).Request().PostAsync().Result;
}
Any assistance would be much appreciated.
A similar question was asked a while ago but without an answer. Remove GrantedTo user from Permission using Graph API
You can delete only not inherited permissions. Only sharing permissions that are not inherited can be deleted. Here's the related doc.

Start GCE instance via client API with environment variable

I'm trying to programmatically start up GCE instances from the C#/REST API (ie not using gcloud or the console). These instances must have values (identifying who started them, so will be different for each instance) passed to them during start-up, which will then get passed to the various applications running within. The obvious way of adding environment variables to the GCE request doesn't appear to be possible, so how does one provide dynamic configuration?
My current code for creating the instances which works fine:
public void CreateInstance(string name)
{
var credentials = GoogleCredential.GetApplicationDefault().CreateScoped(ComputeService.Scope.Compute);
var service = new ComputeService(new BaseClientService.Initializer
{
HttpClientInitializer = credentials,
ApplicationName = "Spin-up"
});
var spec = new Google.Apis.Compute.v1.Data.Instance
{
Name = name
};
var instanceTemplate = service.InstanceTemplates.Get(GCloudConfig.ProjectName, GCloudConfig.TemplateName).Execute();
var insertRequest = service.Instances.Insert(spec, GCloudConfig.ProjectName, GCloudConfig.Region);
insertRequest.SourceInstanceTemplate = instanceTemplate.SelfLink;
insertRequest.Execute();
}
You might use the API for Compute Engine Method: instances.start or instances.stop to trigger the start or stop of VM Instances with C# code requests.
Additional information about these API methods are described in documents: instances.start. and instances.stop.

Cannot update read/write attributes of UserPoolClient via C# SDK

When programmatically creating a Cognito user pool and app client, if the app client is to have read/write access to attributes of the user pool, that access must be explicitly given. I have been able to do so successfully for custom attributes but built-in attributes always return an error of "Invalid write attributes specified while creating a client" or "Invalid read attributes specified while creating a client".
Documentation is ... both voluminous and difficult to find. I have yet to see an example of this or an actual bit of useful documentation on the CreateUserPoolClientRequest type that says anything about this other than things like "ReadAttributes is a list of strings that are the attributes that can be read".
Here is the code I'm using that always ends up with that error message and failure to create the app client. _client is an AmazonCognitoIdentityProviderClient properly instantiated and credentialed and running in a lambda function.
var request = new CreateUserPoolClientRequest { UserPoolId = userPoolId, ClientName = $"{name}AppClient" };
var builtInAttributes = new List<string>()
{
"address","birthdate","email","family name","gender","given name","locale","middle name","name","nickname","phone number", "picture","preferred username","profile","zoneinfo","updated at","website"
};
var readAttributes = new List<string>();
var writeAttributes = new List<string>();
readAttributes.InsertRange(0,builtInAttributes);
writeAttributes.InsertRange(0, builtInAttributes);
var attributeConfig = ConfigurationHelper.GetListFromSection("UserPoolCustomAttributes");
foreach (var attribute in attributeConfig)
{
readAttributes.Add($"custom:{attribute.Key}");
writeAttributes.Add($"custom:{attribute.Key}");
}
request.ReadAttributes = readAttributes;
request.WriteAttributes = writeAttributes;
var result = await _client.CreateUserPoolClientAsync(request, CancellationToken.None);
Any help is greatly appreciated.
Figured it out. Though I have yet to find it documented anywhere, default attributes with a space in the name in the ui need to have that space replaced with an underscore when using their name in the api.

How to get Workspace object in new TeamFoundation 2013 Templates

In new version of TeamFoundation 2013 default build templates, the Workspace variable is missing. It is needed as intput parameter for few key activities like ConvertWorkspaceItem. How do I get current workspace for TfvcTemplate.12.xaml templates? I've tried to use this msdn thread but it's not working for me (returns null workspace name). Any suggestions?
There's a new activity in 2013 called GetLocalPath that replaces ConvertWorkspaceItem.
The activity is under the Microsoft.TeamFoundation.Build.Activities.Core namespace in the Microsoft.TeamFoundation.Build.Activities assembly.
It uses the LocalPathProvider class that aggregates all workspaces used in the build and exposes path translation for all of them in one place. This basically removes the dependency of knowing the workspace in order to translate server paths to local paths and allows you to use as many workspaces as you want without worrying about breaking something down the line.
When MS takes something away, it's usually for a good reason. "hacking" is really not necessary.
I went with a hack using internal classes from Microsoft.TeamFoundation.Build.Activities.dll (used by microsoft to create workspace name). You need to create custom activity with following code:
public sealed class GetDefaultWorkspace : BaseActivity<Workspace>
{
public override Activity CreateBody()
{
var type = typeof(TfGetSources).Assembly.GetType("Microsoft.TeamFoundation.Build.Activities.TeamFoundation.TfGetSources+GetDefaultWorkspaceName");
var activity = (CodeActivity<string>)Activator.CreateInstance(type);
var sequence = new Sequence();
var workspaceName = new Variable<string>();
sequence.Variables.Add(workspaceName);
sequence.Activities.Add(activity);
activity.Result = (OutArgument<string>) workspaceName;
sequence.Activities.Add(new GetWorkspace
{
Name = workspaceName,
Result = new LambdaReference<Workspace>(ctx => Result.Get(ctx))
});
return sequence;
}
}
This answer might work better for some people. ghord's answer works well, and passes the Workspace back where it can be used in the XAML. However, for my purposes I only want the workspace in my custom TFS activities, so I ended up with this alternative...
public sealed class CustomActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
// get workspace
var buildDetail = context.GetExtension<IBuildDetail>();
var buildAgent = context.GetExtension<IBuildAgent>();
var buildDirectory = buildAgent.GetExpandedBuildDirectory(buildDetail.BuildDefinition);
var workspacePath = Path.Combine(buildDirectory, "src");
var wsInfo = Workstation.Current.GetLocalWorkspaceInfo(workspacePath);
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsInfo.ServerUri);
tfs.Connect(ConnectOptions.None);
var vcs = tfs.GetService<VersionControlServer>();
// finally can get to the workspace here
var workspace = vcs.GetWorkspace(workspacePath);
}
}
Using this method, I don't have to have an activity that just returns the workspace, and then have to pass the workspace into other TFS activities. I just get the workspace from within my own activity while it runs.
I believe the method employed here will use the already downloaded workspace. Keep in mind, that this approach will only work within the scope of "Run on agent" sequence after "Initialize Environment" and before ResetEnvironment within the finally statement of Try Compile, Test, Publish. Else, the workflow will have no knowledge of a sources directory.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/420ba073-bdf5-4ab4-88da-c84561d1a1ba/creating-dynamic-working-folder-in-tfs2013-defaulttemplate?forum=tfsbuild

CreateOrganizationProfile error Object reference not set to an instance of an object

I'm using Microsoft code to create a new Organisation in the User Profile Server, as per http://msdn.microsoft.com/en-us/library/ms545122.aspx.
Every time I call CreateOrganizationProfile I get the following:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Office.Server.UserProfiles.OrganizationProfile.set_Parent(ProfileBase value)
The exact code I'm using is:
[WebMethod]
public void CreateOrganisation(string OrganisationName)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(_serverName))
{
// Removing this will cause the error "Operation is not valid due to the current state of the object".
HttpContext.Current = null;
SPServiceContext context = SPServiceContext.GetContext(site);
ProfileSubtypeManager psm = ProfileSubtypeManager.Get(context);
// choose default organization profile subtype as the subtype
string subtypeName = ProfileSubtypeManager.GetDefaultProfileName(ProfileType.Organization);
ProfileSubtype subType = psm.GetProfileSubtype(subtypeName);
OrganizationProfileManager opm = new OrganizationProfileManager(context);
// choose Root Organization as the parent
OrganizationProfile parentOrg = opm.RootOrganization;
// create an organization profile and set its display name
OrganizationProfile profile = opm.CreateOrganizationProfile(subType, parentOrg);
profile.DisplayName = "Test Org1";
// commit to save changes
profile.Commit();
}
});
return;
}
Curiously, somebody else ran into the exact problem here http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/7b5101fd-0ea6-4716-82b1-ac4609b9973c/, but it was never resolved.
I've confirmed the User Profile Service is running and responding. Also, parentOrg and subtypeName are not null when calling CreateOrganizationProfile.
Does anybody have anything I can try, or can anybody spot what might be the problem?
Very grateful!
I had the same problem and I fixed it by changing the line
OrganizationProfile parentOrg = opm.RootOrganization;
To
OrganizationProfile parentOrg = (OrganizationProfile)opm.GetProfile(1);
GetProfile(1) returned the RootOrganization in my case.
Hope this helps someone!
I am no sharepoint expert but this http://msdn.microsoft.com/en-us/library/microsoft.office.server.userprofiles.organizationprofilemanager.createorganizationprofile.aspx states that you need user profile administrative permissions and this http://msdn.microsoft.com/en-us/library/microsoft.office.server.userprofiles.organizationprofile.parent.aspx could be hint that you need user profile manager permission to do what you are trying to do.
EDIT:
since your code try to "write" something this seems relevant http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx
basically it says you are missing a call to SPUtility.ValidateFormDigest() or SPWeb.ValidateFormDigest() before calling SPSecurity.RunWithElevatedPrivileges

Categories

Resources