From my device owner application, I'd like to create a new user and switch directly to it. For now, I can only create a new user, switch to it but:
it brings me to the keyguard screen, that I need to manually unlock.
then, tells me to setup the newly created user - with firstname, lastname, WIFI settings, and 3 Google usage statistics/reporting options.
I'd like to know if there's a way to programmatically setup the new user and switch directly to it's "session". I'd like to programmatically avoid the "unlock" page et pre-setup the newly created user with name, WIFI settings, but also available apps and security settings.
here's what I do so far :
// init block (in onCreate...)
DevicePolicyManager mDPM = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName mDeviceAdminRcvr = new ComponentName(this, DeviceAdminRcvr.class);
// in my button "create a new user"
ComponentName profileOwnerComponent = new ComponentName(this, ProfileAdminRcvr.class);
Bundle adminExtras = new Bundle();
UserHandle userHandle = mDPM.createAndInitializeUser(mDeviceAdminRcvr, name, ownerName, profileOwnerComponent, adminExtras);
// TODO : place here missing instructions to provision the user...
mDPM.switchUser(mDeviceAdminRcvr, userHandle);
I couldn't find any documentation on the official Google page about device owner apps or profile apps.
Could anyone help me or point me to useful links ?
As far as I've seen, there is no way to programmatically unlock the screen lock. Even the Smart lock functionnality added in Lollipop will just disable the Key Guard, which means that the "PIN" or "Pattern" will transform into a "Swipe Lock" when a trusted agent unlocks the device. Even in this case, you'll need to manually swipe the screen to unlock the device.
Concerning the second point, it's possible to avoid the "Setup Wizard" proposed the first time you unlock a newly created user. Here's how to do it :
in your ProfileAdminRcvr.java, you'll need to hide the system application called com.google.android.setupwizard. You could do this in the onEnabled() method of your DeviceAdminReceiver's implementation (the one you set for your profile when creating the user).
To complete this, you can disable the "first use hint", by setting the Settings.Secure.SKIP_FIRST_USE_HINTS property.
Here's the code to do it :
public class ProfileOwnerRcvr extends DeviceAdminReceiver {
private DevicePolicyManager mDPM;
private ComponentName mProfileAdminRcvr;
#Override
public void onEnabled(Context context, Intent intent) {
mDPM.setProfileName(mProfileAdminRcvr, "My new user");
// ... setup other things by yourself...
mDPM.setApplicationHidden( mProfileAdminRcvr, "com.google.android.setupwizard", true);
mDPM.setSecureSetting(mProfileAdminRcvr, Settings.Secure.SKIP_FIRST_USE_HINTS, "1");
}
Google updated its demo app to use Android-N preview version, it seems that there will be a flag called DevicePolicyManager.SKIP_SETUP_WIZARD to do part of what you are trying to do (i.e skipping the wizard) in N.
Related
I'm trying to make a new PhoneAccount to use my implementation of ConnectionService. In the documentation it says I need to register a new PhoneAccount with TelecomManager and then select it in my phone-app's settings.
Here's my code:
TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
ComponentName componentName = newComponentName("se.example.connectionservicestandalonetest", "se.example.connectionservicestandalonetest.MyConnectionService");
PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, "Admin");
PhoneAccount phoneAccount = PhoneAccount.builder(phoneAccountHandle, "Admin").build();
telecomManager.registerPhoneAccount(phoneAccount);
As you can see, it creates a new ComponentName that points towards my implementation of ConnectionService, then creates a new PhoneAccountHandle where I supply the ComponentName and a unique account-name. I then supply the PhoneAccountHandle in the PhoneAccount buildes, as well as label (a name?), to create a new PhoneAccount. Lastly I register the account in the telecomManager.
When I open up the phone app, nothing has changed. I see no where I could possibly change the PhoneAccount... Any ideas?
Thanks!
I've got some information that I'll just leave here for posterity.
When building your PhoneAccount, you must add CAPABILITY_CALL_PROVIDER if you make and receive calls on your own, or CAPABILITY_CONNECTION_MANAGER if you want to make or receive calls using the builtin PhoneAccount. Without either, you won't show up in the UI.
As far as I can tell, there is no dedicated API for checking whether the user has enabled your PhoneAccount. However, you can use TelecomManager.addNewIncomingCall for this purpose. Simply provide a Bundle containing a boolean extra (named whatever you want) and set that boolean to true if you're really receiving a call or false if you just want to do a permission check (or vice-versa). Then your implementation of ConnectionService.onCreateIncomingConnection can check your extra and return Connection.createCanceledConnection if you're just doing a permission check. This does not register as a call in the call log, and the ringtone never plays. addNewIncomingCall will throw if your PhoneAccount is not enabled, and succeed if it is.
As noted in the comments above, you can prompt the user to enable your PhoneAccount using TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS. Because the user can enable or disable your PhoneAccount at any time, all operations that require an enabled PhoneAccount (like addNewIncomingCall) should be placed in a try block.
Here is a little more info that might be helpful to others. After you have configured your phone account, the user needs to enable permission for your app. Getting the user to that screen should be easier. I've only seen the TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS action, but it doesn't take you to the proper screen to enable the permission. You have to select "All calling accounts" after launching that activity.
If you would like to take the user directly to the "Calling accounts" screen, I've found that this Intent will take you there.
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.server.telecom","com.android.server.telecom.settings.EnableAccountPreferenceActivity"));
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
I've tested this with a Motorola G5S Plus and it should also work with mostly stock devices like Nexus and Pixel devices. I'm not sure if it will work with Samsung devices.
As an addendum to j__m's answer: I found a way to check if the phone account is activated without setting up a call:
private boolean checkAccountConnection(Context context) {
boolean isConnected = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
final List<PhoneAccountHandle> enabledAccounts = telecomManager.getCallCapablePhoneAccounts();
for (PhoneAccountHandle account : enabledAccounts) {
if (account.getComponentName().getClassName().equals(MyConnectionService.class.getCanonicalName())) {
isConnected = true;
break;
}
}
}
}
return isConnected;
}
As stated in the Javadoc to android.telecom.TelecomManager.getCallCapablePhoneAccounts()
Returns a list of {#link PhoneAccountHandle}s which can be used to make and receive phone calls. The returned list includes only those accounts which have been explicitly enabled by the user.
Can someone please provide an example for a real case where I might need to use OnProvideAssistDataListener. I can't seem to wrap my head around it. I look at the source code, and then I look online. Someone online says
Application.OnProvideAssistDataListener allows to place into the
bundle anything you would like to appear in the
Intent.EXTRA_ASSIST_CONTEXT part of the assist Intent
I have also been reading through the Intent Docs.
There is an Now On Tap functionality implemented by Google. By long pressing the Home Button, you will get some information displayed on the screen. The information you get depends on what you're viewing on your screen at that time. (for eg: Music app displays information about music on the screen).
To provide additional information to the assistant, your app provides global application context by registering an app listener using registerOnProvideAssistDataListener() and supplies activity-specific information with activity callbacks by overriding onProvideAssistData() and onProvideAssistContent().
Now when the user activates the assistant, onProvideAssistData() is called to build a full ACTION_ASSIST Intent with all of the context of the current application represented as an instance of the AssistStructure. You can override this method to place anything you like into the bundle to appear in the EXTRA_ASSIST_CONTEXT part of the assist intent.
In the example below, a music app provides structured data to describe the music album that the user is currently viewing:
#Override
public void onProvideAssistContent(AssistContent assistContent) {
super.onProvideAssistContent(assistContent);
String structuredJson = new JSONObject()
.put("#type", "MusicRecording")
.put("#id", "https://example.com/music/recording")
.put("name", "Album Title")
.toString();
assistContent.setStructuredData(structuredJson);
}
For more info refer https://developer.android.com/training/articles/assistant.html
I need to set Screen Lock Setting to "None" in the android system.
I am deploying an app that is being sent out to users on pre-configured tablets.
This pre-configuration is done manually by the tablet supplier.
The settings to pre-configure is to set the Screen lock to None when the app is installing.
I don't think this is possible, the user has to do it them self.
Considering all apps (With a similar requirment) I have used so far send me to the "Select lock screen" screen & ask me to disable it manually.
I could be wrong tho!
Try this:
try{
Class lockPatternUtilsCls = Class.forName("com.android.internal.widget.LockPatternUtils");
Constructor lockPatternUtilsConstructor =
lockPatternUtilsCls.getConstructor(new Class[]{Context.class});
Object lockPatternUtils = lockPatternUtilsConstructor.newInstance(getContext());
Method setLockScreenDisabled = lockPatternUtils.getClass().getMethod("setLockScreenDisabled", boolean.class ,int.class);
setLockScreenDisabled.invoke(lockPatternUtils, new Object[]{true,0});
}
catch(Exception e){
Log.e(this.toString(),e.toString());
}
if you want change lock to swipe:
setLockScreenDisabled.invoke(lockPatternUtils, new Object[]{false,0});
but you need to change your app to system uid:
android:sharedUserId="android.uid.system"
If there are multiple services(apps) capable of NFC HCE payments are installed. Those application services are visible under settings NFC Tap and Pay.
There are two AID group defined, one for payment and second for other cateogy.
How to programmatically change your application to be the default 'other category'service if it's not?
Below is the code that I'm executing, but dialog is not invoked to select running application for 'other category'. However for 'payment category' dialog is opened successfully. Below is the code:
CardEmulation cardEmulation = CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(this));
boolean isDefaultCategorySelected = cardEmulation.isDefaultServiceForAid(new ComponentName(this, MyOffHostApduService.class), "F4100000040001");
if(!isDefaultCategorySelected(CardEmulation.CATEGORY_OTHER)){
Intent intent = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT);
intent.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_OTHER);
intent.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, new ComponentName(this, MyOffHostApduService.class));
startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_TRANSIT_SERVICE);
return;
}
You can't.
Global defaults are currently only supported for CATEGORY_PAYMENT. The resolution strategy for CATEGORY_OTHER is always set to SELECTION_MODE_ASK_IF_CONFLICT. Hence, your application must either be the only application that registers a certain AID group in CATEGORY_OTHER or Android will ask the user upon a transaction which app should be used.
You may be able to use CardEmulation.setPreferredService() though in order to set your HCE service as the default while one of your activities is in the foreground.
I've been experimenting with the Android SDK over the past few days, in readiness to write an App for the store, however I've run across a bit of a problem.
The App I'll be writing requires that the user has a Google account associated with the phone. Retrieving and making use of the Auth token etc was not a problem, however I would like to be able to show the activity that a user would normal reach by going through the menus Settings->Accounts->Add Account.
Now through experimentation I've been able to launch this activity from the shell using the following command.
am start -n com.google.android.gsf/.login.AccountIntroActivity
I'm having trouble performing the same action in JAVA using the Intent class.
Would anyone be able to tell me firstly whether or not this can be done via JAVA, and secondly how I could go about it please?
If I have to settle for the Sync Settings screen then I will (this can be achieved through the Settings.ACTION_SYNC_SETTINGS intent), however it'd be quite nice to be able to direct the user straight to the required screen.
Check out the ACTION_ADD_ACCOUNT
startActivity(new Intent(Settings.ACTION_ADD_ACCOUNT));
Try the following:
public static void addGoogleAccount(final Activity activity) {
final AccountManager accountMgr = AccountManager.get(activity);
accountMgr.addAccount("com.google", "my_auth_token", null, null, activity, null, null);
}
Android Account Manager provides an API to add account. (google or other account types)
public AccountManagerFuture addAccount (String accountType, String authTokenType, String[] requiredFeatures, Bundle addAccountOptions, Activity activity, AccountManagerCallback callback, Handler handler)
http://developer.android.com/reference/android/accounts/AccountManager.html
the answer for the above question by providing EXTRA_ACCOUNT_TYPES in the intent extra data. and set the value to "com.google" in order to alert the activity:
public static void startAddGoogleAccountIntent(Context context){
Intent addAccountIntent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
addAccountIntent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, new String[] {"com.google"});
context.startActivity(addAccountIntent); }
For recent Androids using adb you can do:
adb shell am start -a android.settings.ADD_ACCOUNT_SETTINGS \
-n com.android.settings/.accounts.AddAccountSettings
(You’ll still have to select what account type you’d like though)
The clue is in your shell command:
Intent intent = new Intent();
intent.setClassName( "com.google.android.gsf", "com.google.android.gsf.login.AccountIntroActivity" );
context.startActivity( intent );