Cannot add new custom account from different app with same authenticator - android

I have two apps that both use a same custom account type. Those two apps are completely independent and just share the account. When one of them starts, it checks for existing custom accounts and if no account was found, shows the sign-in page.
So I have created my AccountAuthenticator as a library project and reference it in both apps. According to this tutorial:
Let’s say you copied your authenticator’s code to 2 of your apps, thus
sharing its logic, and altering the sign-in pages design on each app
to fit the app it belongs to. In that case, the first installed app’s
authenticator will be called for both apps when an auth-token will be
requested. If you uninstall the first app, the second app’s
authenticator will be called from now on (since it’s the only one
now).
When I run one of the apps (no matter which app) and call addAccount it shows the sign-in page well. Then, when I run the second app and call addAccount nothing happens and sign-in page is not shown. After uninstalling the first app, the second app works correctly and shows sign-in page. So what is the problem and how can I fix that?
The implementation of addAccount:
mAccountManager.addAccount(accountType, authTokenType, null, null, this, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bnd = future.getResult();
showMessage("Account was created");
} catch (Exception e) {
e.printStackTrace();
showMessage(e.getMessage());
}
}
}, null);
Thanks in advance

#Misagh Emamverdi Yeah .You missing that permission in your manifest .
android:sharedUserId
The name of a Linux user ID that will be shared with other applications. By default, Android assigns each application its own unique user ID. However, if this attribute is set to the same value for two or more applications, they will all share the same ID — provided that they are also signed by the same certificate.
Application with the same user ID can access each other's data and, if desired, run in the same process.
So android:sharedUserId is used to share the processes between two or more applications (Like Udinic Authenticator).
SYNTAX
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="string"
android:sharedUserId="string"
android:sharedUserLabel="string resource"
android:versionCode="integer"
android:versionName="string"
android:installLocation=["auto" | "internalOnly" | "preferExternal"] >
. . .

I'm not sure this the correct answer, but I found that the problem is that the apps have different UIDs. So I use sharedUserId in both apps and the problem was solved:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test"
android:sharedUserId="test.account"
android:versionCode="100"
android:versionName="1.0" >

Find the well written article Write your own Android Authenticator

Related

Integrating Air Watch Android Studio

I am very much new to AirWatch Concept but had gone thoroughly about AirWatch. I have gone through the following links,
http://developer.air-watch.com/android/application-configuration-with-the-android-sdk/
http://developer.air-watch.com/android/android-sdk-setup/
but in vain.
Could anyone please help me regarding the integration of Air Watch in Android ?
Things i have done so far,
I have created app in the https://apidev.awmdm.com, and i have added assignemnts. The question here is, How can i get the assignment details in my android application that were added in the Air Watch Console.
Help is really appreciated.
Update:
I am able to create and push the application from AIR WATCH CONSOLE to my Device. Now, the issue i am facing is, If i am adding some application configuration in the AIR WATCH CONSOLE, i am not able to get those details in my application.
I have gone through the below Url for the above scenario,
https://appconfig.org/android/ which is very much similar to https://appconfig.org/ios/
I have implemented those things that were mentioned in the above url but still then i am not able to get those details.Please let me know if i am wrong anywhere.
I got to know that the key value pairs that were being passed in Air watch console will be coming into com.apple.configuration.managed key in iOS. Does any one have an idea that how these key value pairs will come. As far as i know, they will be handled via Restriction Manager. But no idea/clue how to handle in Android.
Updated:
xml/app_restrictions.xml:
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<restriction
android:key="ManagedServer"
android:restrictionType="string"
android:title="Managed Server"
tools:ignore="ValidRestrictions" />
<restriction
android:key="#string/mdm_key_managed_server_name"
android:restrictionType="string"
android:title="#string/mdm_key_managed_server_url"
tools:ignore="ValidRestrictions" />
<restriction
android:key="#string/mdm_key_managed_server_url"
android:restrictionType="string"
android:title="#string/mdm_key_managed_server_url"
tools:ignore="ValidRestrictions" />
</restrictions>
oncreate Method :
IntentFilter restrictionsFilter =
new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get the current configuration bundle
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
// Check current configuration settings, change your app's UI and
// functionality as necessary.
Toast.makeText(LoginActivity.this, "Reciever Called", Toast.LENGTH_LONG).show();
RestrictionsManager myRestrictionsMgr =
(RestrictionsManager)
getSystemService(Context.RESTRICTIONS_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
if (myRestrictionsMgr != null) {
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
if (appRestrictions != null) {
if (appRestrictions.containsKey("ManagedServer")) {
String mConfigDetails = appRestrictions.getString("Managed Server");
Toast.makeText(LoginActivity.this, "" + mConfigDetails, Toast.LENGTH_LONG).show();
}
}
}
}
}
};
registerReceiver(restrictionsReceiver, restrictionsFilter);
List of Users:
When i am actually trying the other command:
Update:
Created a sample app and published to Play Store. App link as follows,
https://play.google.com/store/apps/details?id=com.manu.samplemdm
Now, its a play store app. When I am sending Application Configuration but unable to receive it in the Application. Its giving me still empty bundle from the application.
Help would be really appreciated.
Help is really appreciated
Beside AirWatch Resources, which tells you how you can create an app and set the app configurations,key-value pairs, to push to your devices, You need to check out Android Restriction Manager API. Follow the steps described in the link.
How the whole process works is, AirWatch controls AndroidForWork environment after you set your MDM as AirWatch. And then, AirWatch manages the device from AirWatch console and it pushes the App Configuration to AndroidForWork in your device. You need to implement Android Restriction Manager to access to these data passed you by your MDM. It goes same for all of the MDMs in the Market.
Update:
In order to install your app into Work Container in the development phase, you can use adb to copy it from Personal Container to Work Container.
First, list all of the active users in the device:
./adb shell pm list users
And later, find the Work User's ID from the List of Users and set it in the command below along with your app's package name and App's Main Activity.
./adb shell am start —user 13 -n “your.apps.package.name/your.main.activity.package.name”
13 up there in the command is the Work User's ID. In my case, it's 13.
For more information about ./adb commands in Managed Profiles, see this link and check the most bottom of the page.
There are a couple of different approaches to integrating with AirWatch. It depends on the technology set you're trying to use. I think these are the 2 that are most relevant to you based on what I see in your post:
AirWatch SDK
AppConfig Standard
Both these approaches can accomplish similar functionality but each have different deployment requirements. It sounds like you have gone with the second approach which is using the AppConfig standard and the native APIs provided by Google to have an app read configuration values delivered through AirWatch.
One important thing to note is the AppConfig standard approach on Android requires the device to support "Android for Work" enrollment which is a relatively newer management protocol released by Google. It's worth noting that AirWatch does support Android for Work enrollment so it may just be a matter of getting your AirWatch test instance configured for "Android for Work enrollment" instead of the traditional older Android enrollment protocol. More information about Android for Work can be found here:
https://enterprise.google.com/android/solutions/personal/
If you're already a customer of AirWatch, it may be helpful to create an account here on their resource portal if you haven't done so already to get access to documentation about how you can setup Android for Work within AirWatch. https://resources.air-watch.com
I hope this helps.

RestrictionManager getRestrictions() is always empty

I'm trying to set-up the remote configuration for my app with MobileIron EMM. I've done everything as described in developer guide:
1. I've set-up the manifest:
...
<meta-data
android:name="android.content.APP_RESTRICTIONS"
android:resource="#xml/app_restrictions"/>
</application>
2. I've described the restriction:
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<restriction
android:title="#string/some_title"
android:key="SOME_KEY"
android:restrictionType="string"
android:defaultValue="123"/>
</restrictions>
3. I'm trying to receive it as following:
RestrictionsManager manager = (RestrictionsManager) context.getSystemService(Context.RESTRICTIONS_SERVICE);
Bundle b = manager.getApplicationRestrictions();
if(b!=null){
if(b.containsKey("SOME_KEY")) {
return b.getString("SOME_KEY");
}else{
System.out.println("bundle is not null");
for (String s: b.keySet()){
System.out.println("key in b is : " + s);
}
System.out.println(b.isEmpty() + " bundle is empty");
}
}else{
System.out.println("Bundle is null");
}
return "";
}
I've always got the output:
bundle is not null
true bundle is empty
although I've set the default value for the restriction. Why am I not getting at least default value for the restriction? Why am I never get an actual values (at the server side I've set the values with MobileIron Cloud and its AppConnect configuration)? Tried with several devices. What am I missing? Please help. My goal is to remotely set-up some key-value to the app.
If you're not receiving any restrictions at all then it's probably because your app isn't part of a managed profile. App restrictions only work in two scenarios... your device has been provisioned using your EMM console (can only be done after a factory reset) or your device has an Android for Work profile that is managed by your EMM console. You don't actually need to declare each restriction in the manifest, that only allows the EMM to provide that information in their console.
The easiest way to test your app restrictions on an unprovisioned device is to download the Test DPC app from the google play store. Setting it up will encrypt your device and install a work profile you can use for testing. You can use the DPC app to simulate applying app restrictions, reading the restrictions from manifest, and a number of other things EMMs do. You can install your app on the work profile using adb or by following the developer's guide to tell Android Studio how run the app in your work profile.
https://developer.android.com/work/guide.html#testing
These two posts should help post1 and post2.
Fred helped me understand from those posts, but to summarize:
If an item has not been explicitly set by a managed configurations provider, then that item will not be in the Bundle. An empty, but "not null" bundle just means nothing has been set by a managed configurations provider. The defaultValue in the managed configurations XML file is not used here. And the app is not being actively managed.
To get the defaultValue, query the configuration item's value using this RestrictionsManager.getManifestRestrictions(). It returns a list of all the RestrictionEntry objects as they are set in the managed configuration XML file. This means the value of the item is the defaultValue as defined in the XML file.
I had the same problem. We have tested with an Xamarin csharp app, used the public google test app "Test DPC" available via Play Store. It has a button "Load manifest restrictions" that should be able to load the app restrictions defined (it did not, in my case anyway).
It worked only, if:
I did NOT debugged the application (there the values applied with DPC always not defined/empty) but started at the device directly, and
add/set the key/value pairs manually within the Test DPC app.
Then I got my boolean values switched from within DPC... (ensure you pressed "Save" within "Manage applications" screen)

Requesting more than one oauth2 scope through AccountManager in Android

I'm in a situation where I need to request access tokens for two scopes (from my android application), https://www.googleapis.com/auth/userinfo.email and https://www.googleapis.com/auth/userinfo.userinfo
I would like to get both permissions on a single call to getAuthToken, but can't figure out the string to pass in the authTokenType parameter. I tried several reasonable combinations with no positive results :(
Has anyone solved this issue? Is it possible?
I was having the same issue. Shah is almost right, but his scope string is wrong. It should be
"oauth2:<scope_url> <scope_url>"
not
"oauth2:<scope_url> oauth2:<scope_url>"
If you need multiple OAuth 2.0 scopes, use a space-separated list.
oauth2:https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.userinfo
You asked for sample code, so have a look at the Google Docs Upload Sample application, and in this application have look at the authentication flow done in this sample Android screen (ignore that it's about Google Docs, it still authorizes first). You can get the whole application and run it in an emulator with Google APIs present or run it on your phone. The authorization workflow starts with the buttonAuthorize click, Authorize() and you are specifically interested in this method:
private void gotAccount(Account account)
{
Bundle options = new Bundle();
accountManager.getAuthToken(
account, // Account retrieved using getAccountsByType()
"oauth2:https://www.googleapis.com/auth/userinfo.email oauth2:https://www.googleapis.com/auth/userinfo.userinfo", // Auth scope
//"writely", // Auth scope, doesn't work :(
options, // Authenticator-specific options
this, // Your activity
new OnTokenAcquired(), // Callback called when a token is successfully acquired
null); // Callback called if an error occurs
}
The user gets this access request screen:
Note that this is using the 'local' OAuth2 mechanism, not opening a web browser, but using the authentication provided when you first activated the Android phone.
Also note that the user sees the full URL of the scope instead of a friendly name, I haven't found a way around this and if you do find out it would be great if you could share the answer.

Android addAccountExplicitly using "com.google" type

I'm looking for the answer since the begining of the day and I still don't know what to do!
To explain the problem:
My application uses GTasks API. To do this, the user MUST have a google account. I have two ways to check that:
I instantiate an Account manager and look for "com.google" accounts if there are no such accounts
I launch a webview on which the user logs on Google and accepts to use the API.
Then, I have to synchronize my application with GTask.
From the information extracted from the webview, I tried to create a "com.google" account using the AccountManager but I always have the error "Caller UID is different...". I know that the problem should come from "account-authenticator" because the "accountType" has to be the same in the XML file and in the app but I think that's not the case because when I use a different account type, it perfectly works (but I can't obtain an authToken from GTask).
So, here is my code:
Authenticator.xml:
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.google"
android:icon="#drawable/miniicon"
android:smallIcon="#drawable/miniicon"
android:label="#string/app_name"
android:accountPreferences="#xml/preferences"
/>
Definition of the account type:
public class AuthenticationService extends Service {
public static final String ACCOUNT_TYPE = "com.google";
How I use it in my class:
AccountManager manager = AccountManager.get(activity);
final Account account = new Account(login, AuthenticationService.ACCOUNT_TYPE);
manager.addAccountExplicitly(account, password, new Bundle());
When I use "com.plop" or anaything else instead of "com.google", it works really fine.
So, my two questions are:
1. Can I use the "com.google" account type?
2. Is that normal that I can't obtain my authToken using something else than "com.google" (knowing that the account used is still a Google account, it's just not set like that on Android) ?
Thx in advance for your help and, please, forgive me if the answer was on the site!
I answered my own question: that's not possible the way I wanted to. You have to use the "addAccount" function using a "com.google" account type. This will result in popping the account creation activity used by the android system. Then, everything is fine using GTasks API.

Sync Adapter without Account

I need to fetch some data over the cloud from my app. I've watched the google IO video on RESTful android apps # http://www.youtube.com/watch?v=xHXn3Kg2IQE&t=43m58s It recommends in the final slides to use a SyncAdapter to integrate with the Android System.
Later I learned that one has to use an Account to implement SyncAdapter. My app does not use an account. Users can freely download data without registration. Can I still use SyncAdapter? Is there a stock dummy account that I could use?
Edit: I do have a content provider for my app so that's not a problem
Edit2: I've just looked at the Weather and Stock apps under Settings -> Accounts & Sync. You can see that they allow syncing, but don't have a remove account button. On the other hand, Google, Facebook and Skype apps allow syncing PLUS they have a remove account button. This means Weather and Stock don't use accounts, whereas Google, Facebook and Skype do.
The tutorials I found # http://ericmiles.wordpress.com/2010/09/22/connecting-the-dots-with-android-syncadapter/ and # http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/ say that one MUST have an account to use Sync Adapter. :S ???
As the Android Developer docs say
Even if your app doesn't use accounts, you still need to provide an authenticator component. If you don't use accounts or server login, the information handled by the authenticator is ignored, so you can provide an authenticator component that contains stub method implementations. You also need to provide a bound Service that allows the sync adapter framework to call the authenticator's methods.
There is an entire article on Creating a Stub Authenticator. I realise that this question is old and an answer was accepted long ago, but I felt that a recent addition to the official docs should be included here.
I have created a contact sync adapter where I don't have a account authorization and or configuration screens. It wasn't that hard. I don't think having to deal with the Android Account stuff was that much of a deal.
Quote from your tutorial link:
The bad news is that there is no
“stock” functionality to give you an
easy way to provide an Account to the
system. However, in the same Sync
Adapter Example that comes with the
SDK there is a lot of code you can
borrow to give you Account
functionality. Unless you desire a
custom credentials screen, you can
heist all the code in the
com.example.android.samplesync.authenticator
package with only a few minor changes.
So it's basically just a copy and paste from the example, that's pretty much what I did and it worked fine.
I don't know for sure but all the adapters that don't have "Remove Account" seems to be built-in ROM adapters on all the devices I've looked at. I'm not sure you have to worried about it.
I keep getting lots of notifications from this question, so I thought I'll share this info. This is how you add SyncAdapter without Account. You can put this in onCreate of MyApplication extends Application class. This assumes you already have a SyncAdapter and ContentProvider implemented. You can do that by following the tutorials listed in the question.
final String ACCOUNT_NAME = "MyApp";
final String ACCOUNT_TYPE = "com.myapp.account";
final String PROVIDER = "com.myapp.provider";
Account appAccount = new Account(ACCOUNT_NAME,ACCOUNT_TYPE);
AccountManager accountManager = AccountManager.get(getApplicationContext());
if (accountManager.addAccountExplicitly(appAccount, null, null)) {
ContentResolver.setIsSyncable(appAccount, PROVIDER, 1);
ContentResolver.setMasterSyncAutomatically(true);
ContentResolver.setSyncAutomatically(appAccount, PROVIDER, true);
}
res/xml/syncadapter.xml
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="#string/provider"
android:accountType="#string/account_type"
android:userVisible="true"
android:supportsUploading="true"
/>
res/xml/authenticator.xml
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="#string/account_type"
android:icon="#drawable/app_icon"
android:smallIcon="#drawable/app_icon"
android:label="#string/app_label"
/>

Categories

Resources