How to customize Android Google Setup Wizard for device owner provisioning? - java

--Use case:
1-System app apk in priv-app folder to be used as device owner.
2-User starts up device and Google setup wizard comes up.
3-Immediately starts device provisioning activity.
--Things that used to work:
This method used to work on Android 6.0 Marshmallow using the action intent:
<activity android:theme="#style/InvisibleNoTitle" android:name="OwnerActivity" android:launchMode="singleTop" android:immersive="true">
<intent-filter android:priority="5">
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.DEVICE_INITIALIZATION_WIZARD" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
without any problem.
After updating to Android 8.1 Oreo, this method no longer works. The OwnerActivity shows up only after setup wizard finishes which is useless since device is already provisioned by user and can't be provision again.
Is there any newer way of doing this so that my OwnerActivity shows up first to provision the device? What is changed in Oreo?

This is a bit late for an answer, and without talking to Google it's a little hard to see what the design decisions have been. However, what we can know is what's changed.
1. android.intent.action.DEVICE_INITIALIZATION_WIZARD is deprecated atleast as early as Oreo.
2. Package Manager Service has had changes to reference the setup wizard. The new approach appears to be the category android.intent.category.SETUP_WIZARD which your manifest definition lacks.
Reading the comments around the code (which you can find below) we see this log:
Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size()
+ ": matches=" + matches);
https://android.googlesource.com/platform/frameworks/base/+/nougat-mr2.3-release/services/core/java/com/android/server/pm/PackageManagerService.java#17872
So it seems like as of Nougat, Android doesn't support having multiple setup wizards that are chained together.
For your specific problem of how to setup the device admin I have 2 suggestions.
If you care about CDD and CTS then you should get your users to go through the Google device owner provisioning process which they keep updated.
If you don't care about that and you just want your build to always have a device owner, just make changes in the frameworks or add some system binary that always runs before the setup wizard which will set your device owner application for you.

Related

Tile only application

Having seen the questions about activities with no GUI here, here and here. In addition, these answer are rather old, I don't know if they're still relevant.
I want to create an app for which the only user interaction is a quick tile.
I understood there can't be no activity at all, so I have a blank activity with no display using #android:style/Theme.NoDisplay
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service
android:name=".AdaptativeSleepTile"
android:icon="#drawable/ic_launcher_background">
</service>
But the app appears in my app list (with nothing happening when I click it, logically), which is not what is written in the comments of this answer.
I can't remove the line <category android:name="android.intent.category.LAUNCHER"/> otherwise I get the error message
Could not identify launch activity: Default Activity not found
Error while Launching activity
So what should I do to have a service for which the only user interaction is the quick tile? (Same question would also apply for no interaction at all, or only widget I guess)
Using Android Studio 4 and Sdk 29
I want to create an app for which the only user interaction is a quick tile.
That may or may not be practical. Since Android 3.1, apps are installed in a "stopped state", and it takes an explicit Intent to move them out of the stopped state and allow them to run. Normally, that comes from the user tapping on an icon in a launcher to run your MAIN/LAUNCHER activity.
It is possible that simply having a TileService available in the manifest is enough to get you listed in the notification shade, and the act of adding the tile will be enough to move your app out of the stopped state. However, I certainly cannot guarantee that, and it would not surprise me if this does not work.
Also, please bear in mind that you may need an activity for other reasons:
To display your terms of service
To display your privacy policy
To provide access to tech support
To allow for configuration of the app
And so on
But the app appears in my app list (with nothing happening when I click it, logically), which is not what is written in the comments of this answer.
If you mean the first comment, that is simply wrong, as is pointed out by other comments on that answer.
I can't remove the line otherwise I get the error message
I assume that you are getting that from Android Studio. You will need to change your run configuration to not try starting an activity.
Same question would also apply for no interaction at all
Fortunately, there is no solution for that. Malware authors think that totally invisible apps are wonderful, and Android takes steps to prevent such apps from being able to work. And, this is why I would not be surprised if you need an activity for your TileService.

Launch the Android App using deep linking

I'm trying to launch my Android App, using deep linking. Basically, the users will receive emails with links, when the user clicked the link, the App should launch.
I know how to do the basic deep linking, however, I want to launch the actual App not just a specific activity. My deep linking scheme is something like "mydeeplinking" and in the email is like "mydeeplinking://".
I am looking for Something similar to the iOS deep linking, which launch the entire App.
Any help would be appreciated.
Thanks in advance.
Basically, all you need to do is use intent-filter to tell Android what type of data should be routed to your app.
AndroidManifest.xml:
<activity android:name="com.example.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="www.example.com" />
<data android:path="/" />
<data android:path="/map" />
</intent-filter>
</activity>
This will launch your MainActivity when the user clicks any of these links:
http://www.example.com/
https://www.example.com/
http://www.example.com/map
https://www.example.com/map
Deep linking is greatly enhanced by Firebase. It's a little hard to get started, but it works great! Check this link for an example.
Comparing this deep linking to iOS is where the confusion may come in, because theirs works differently. Android has always been able to push information from one app to another and even pull from the web, which is what iOS is doing. That isn't deep linking per-se. It can go MUCH further than that- it is meant to provide a personalized app experience even before a user creates a profile (or something similar). It's also important to note that deep linking holds onto this personalized info even through the installation of an app and opens the app with whatever that info was! It's not just an intent! Your question has to do with URI schemes. Maybe this will help if you still agree that you're looking for deep linking.
If you are simply looking to launch an app (already installed on the users device or not), intent filters are the way to go, and intents can pass information. If you are wanting a user to use an activity in an app without ever installing it, android instant apps is the right choice. If you're looking for a way to pass information "deeply" from the user's email or internet to your app, deep linking is advised.
Intent filters can be used to open some apps from web pages. When a link is selected that could be opened in a browser or in an app (or multiple apps), a box will pull up from the bottom of the phone's screen, asking for the user's preference for the default to open in on future clicks. (see image below) The web site's javascript may have to be altered to detect the user's operating system and send the proper URL call. iOS works a little differently.
Here is how to use an intent filter. It has some extra code that you may find useful..
public void startNewActivity(Context context, String packageName) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if (intent == null) {
// brings user to the market if app is not installed already
intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id=" + packageName));
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // opens a new "page" instead of overlapping the same app
context.startActivity(intent);
}
If you need to pass data at the same time, use intent.putExtra("name", "value");

Installing application without icon or activity

I had a discussion with a friend and he told me that some applications can be installed on android without any activity or icon showed in menu. Because i'm studying android too i was surprised because i never heard of that.
App's name is showed in "Manage Applications" section and its easy to uninstall it.
So now i'm asking as programmer. How is possible(if it is) to install that kind of application? (with no activity or launcher ).
Just remove all of the following intent filters from your manifest:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Keep in mind though that from Android 3.1 onwards, your app will not receive any broadcasts, or be listed in any other places where an intent filter would make it available (like in the share menu) if the user hasn't manually opened your app UI (main Activity) at least once from the launcher.
There is another way that works even on Android3.1+ .You can not disable the icon itself, but you can disable one component of an application. So disabling the applications launcher activity will result its icon to be removed from launcher.
The code to do this is simple:
ComponentName componentToDisable =
new ComponentName("com.helloandroid.apptodisable",
"com.helloandroid.apptodisable.LauncherActivity");
getPackageManager().setComponentEnabledSetting(
componentToDisable,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
There is a few things to know about this solution:
1-the disabled component will not be launchable in any way
2-other non disabled activities will be launchable from other applications
3-an application can only disable its own component. There is a permission "android.permission.CHANGE_COMPONENT_ENABLED_STATE", but it wont work, 3rd party plications can not have this permission
4-the icon will only disapper when the launcher is restarted, so likely on next phone reboot, forcing the launcher to restart is not recommended
In this way,App must be run atleast on time.
Reference:
Removing an app icon from launcher
Yeah this kind of application is possible. You have to create an Application that has no Launcher Activity in the Manifest file.
For eg:- You can register a Broadcast for on boot received. So, that when the device boots your application will be called though it doesn't have any UI. You can checkout this one.
NOTE - This type of Application will only work below 3.1.

Android Custom Permission Fails Based on App Install Order

Having issues with my apps on Google Play. I have a free app which utilizes a custom permission. This permission allows access to paid apps. These paid apps act as "keys" and unlock features in the free app. Basically the free app will attempt to start the intent of one of the paid apps. The paid app will do some stuff and return saying whether the free app should unlock features or not.
Problem arises based on the order of app installation. If the free app is installed first then a paid app, the free app can't start the intent. Returns permission denial. If the paid app is installed first then the free app, the free app can start the intent no problem. Rebooting the device and/or force stopping the apps doesn't resolve the issue. I'm attaching the relavent code. Something tells me I'm doing something incorrectly.
Free App Manifest (relevant code):
...
<uses-permission android:name="com.company.license.PERMISSION" />
...
Free App Code to check intent (relevant code):
Intent KeyApp = new Intent("com.company.license.action.AUTH_1");
KeyApp.putExtra("com.company.license.challenge", 1);
//If free app is installed first, an exception is thrown for not having the proper permission. If paid app is installed first, no exception is thrown
try {
startActivityForResult(KeyApp, COMMING_FROM_KEYAPP);
} catch (Exception e) {
cancelStartUp();
}
Paid App Manifest (relevant code):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.company.installer.1"
...
<permission
android:name="com.company.license.PERMISSION"
android:icon="#drawable/icon"
android:label="#string/app_name"
android:protectionLevel="normal" >
</permission>
<application
android:icon="#drawable/icon"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoDisplay" >
<activity
android:name="com.company.license.auth"
android:configChanges="keyboardHidden|orientation"
android:exported="true"
android:permission="com.company.license.PERMISSION"
android:theme="#style/Theme.Transparent" >
<intent-filter>
<action android:name="com.company.license.action.AUTH_1" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.company.installer.redirect"
android:configChanges="keyboardHidden|orientation"
android:exported="true"
android:theme="#style/Theme.Transparent" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Put the same <permission> element in both apps. Also, since this is specific to your two apps, I would use android:protectionLevel="signature" instead of normal -- this means the user will never need to approve the permission and nobody else will be able to request the permission. And, this recipe will allow installation in either order.
UPDATE: Note, however, that the use of custom permissions opens up potential vulnerabilities, due to Android's "first one in wins" approach.
UPDATE #2: And this is now no longer supported as of Android 5.0, as two apps cannot both have the same <permission> element unless they are signed by the same signing key.
I was able to work around the issue #CommonsWare mentioned in his Update #2. Simply by only declaring the permission in the app which will be installed first.
Explanation:
I have app A and app B, signed with different signatures. App A needs to use app B to login, but app A gets installed first and makes sure the user installs app B.
Because app B seems to be the (login)service I declared the custom permission in app B. App B has a (intent)service which other apps may use, as long as they use the permission and are in our whitelist. So app B had the service and permission declared.
But because app A is installed before app B I discovery I needed to add the permission as well to app A. Otherwise app A didn't seem to have the permission after installing app B. My best guess is that this is because the permission stuff is done at installation. And since app A didn't declare the permission, at install nothing happened. But then app B is installed which has the permission but app A still doesn't receive this permission.
But then I tested on Android 5 and ran into their unique permission changes. So I tested some flows and permission declarations and came up with a working solution:
Declare the custom permission in the app that gets installed first! Of course this only work when you know which app is going to be installed first. But in my case, where app A is dependant on app B ánd app A installs app B, this was the solution :)

Android - How to download data in the background at specified times

I'm sorry in advance for not having any code to post up, mainly because I can't for the life of me figure out how I need to do what I need to do.
Basically, at specified intervals during the day (ex. 5 P.M), I want my app to download some data from my server and store it on the device. This is to both reduce the load on my server from having data being downloaded every time the app is run, and to reduce the loading times for the user so that when they go to use the app, the latest data is already sitting on their device.
I have absolutely no clue how to do this. I know how to download data just fine, but now how to download in the background like I'm planning. Is it even possible?
I'm not asking for anyone to do it for me, but could someone please point me in the right direction.
Use the AlarmManager
This class provides access to the system alarm services. These allow you to schedule your application to be run at some point in the future. When an alarm goes off, the Intent that had been registered for it is broadcast by the system, automatically starting the target application if it is not already running. Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
Use it to start a Service
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
The API Demos includes an Alarm Service example (in the "App" section), which:
Demonstrates how you can schedule an alarm that causes a service to be started. This is useful when you want to schedule alarms that initiate long-running operations, such as retrieving recent e-mails.
In particular, see AlarmService.java for an example of using AlarmManager to schedule your Service to be woken later, and see AlarmService_Service.java for an example of how to respond to that alarm. The API Demo's AndroidManifest.xml contains the related service and activity definitions:
<service android:name=".app.AlarmService_Service" android:process=":remote" />
<activity android:name=".app.AlarmService" android:label="#string/activity_alarm_service">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
Write a Service.
Use the AlarmManager.
could someone please point me in the right direction.
AlarmManager, Service, AsyncTask, BroadcastReceiver
<receiver android:name=".receiver.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

Categories

Resources