Different AndroidManifest files for different API levels - android

I am creating an app where I need to collect status bar notifications. Users are prompted to allow either my implementation of NotificationListenerService (API >= 18) or AccessibilityService (other devices) and they are redirected to settings screen.
When I am on API < 18 the user is redirected to Accessibility settings screen, he allows the Accessibility service and everything is OK. However, when the user is on 18>=, even if the user is redirected to Notification settings he still can navigate to Accessibility settings to allow also the Accessibility Service. Both of my services are then registering notifications and notifying me about that.
Obviously I can check from which service the message is coming and react accordingly but I would prefer some cleaner solution. I don't want the user to be able to allow both services (they both appear in settings).
Is there a way to do something like defining separate manifest files for different API levels or declare <uses-sdk> inside <application> tag so they will be used for different API levels? And of course, we cannot create services programmatically - we have to declare them in manifest.

Step #1: Create a boolean resource in res/values/, named is18, set to false, and a second boolean resource named isLessThan18, set to true.
Step #2: Create a boolean resource in res/values-v18/, named is18, set to true, and a second boolean resource named isLessThan18, set to false.
Step #3: Use android:enabled="#boolean/is18" for your <service> element for your NotificationListenerService.
Step #4: Use android:enabled="#boolean/isLessThan18" for your <service> element for your AccessibilityService.
This will enable only one service per device, with the proper one dictated by the API level.

Related

Android autofill: dispatchProvideAutofillStructure() not laid out

I have configured my app to support Android Oreo with compileSdkVersion 26. I've also set up android:autofillHints="phone" for my phone number input field. When I tap on the field, I can see "Autofill" popping up. However, when I tap on "Autofill", "Contents can't be autofilled" toast appears and I see the following trace in logcat:
RemoteFillService Not handling { when=-3ms what=3 target=com.android.internal.os.HandlerCaller$MyHandler } as service for ComponentInfo{com.google.android.gms/com.google.android.gms.autofill.service.AutofillService} is already destroyed
View dispatchProvideAutofillStructure(): not laid out, ignoring
How should I fix this? I've confirmed that I have the phone number configured in Settings > System > Languages & input > Advanced > Input assistance > Autofill service.
UPDATE with a sample XML: In API 26 emulator settings, I can select "Autofill with Google". Using the Design tab of Android Studio, I added a "Phone" type EditText, and then manually inserted android:autofillHints="phone" in the XML element:
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="phone"
android:autofillHints="phone" />
Logcat peculiarities described above can be observed using this XML.
I'm the Android Frameworks engineer leading the Autofill Framework project, so I'll answer some questions:
The "Contents can't be autofilled" message typically means the Autofill Service does not know how to autofill the screen. When you're adding autofill support to your app, it's often easier to use an Autofill Service you can control first, rather than a "real" service like a password manager. As mentioned in a previous reply, we provide a sample service that can be used for this purpose.
When you long-press a text field and select AUTOFILL, you are in fact "forcing" an autofill request as mentioned in another reply (i.e., behind the scenes the text field is calling AutofillManager.requestAutofill()). If the Autofill Service knows how to autofill your screen, you shouldn't need to do that, as the autofill suggestions would show up right away once you focus the input field.
You shouldn't need to set importantForAutofill or call AutofillManager.cancel() in your case.
So, my recommendation is to try to use the sample Autofill Service implementation to test your app first. Most likely, the first time you access your app the autofill popup won't be shown because the service does not have data for it. But once your app triggers the save UI (for example, after you manually enter the phone number and the activity finishes) and you tap save, that data should be available the next time you launch the activity.
Hope that helps,
-- Felipe
This may well be the issue - as
as service for ComponentInfo{com.google.android.gms/com.google.android.gms.autofill.service.AutofillService} is already destroyed
Ensuring data is available
In some special cases, you need to take
additional steps to make sure that the data is available to the
Autofill Framework to save. For example, an activity can present a
layout with standard text views, but then destroy the layout and
replace it with one without child views, such as GLSurfaceView.
In this case, the data in the original layout is not available to the
framework. To make the data available to the framework, you should
call commit() on the AutofillManager object before replacing the
original layout.
You'll need to fix some of these issues within your java code.
Add IMPORTANT_FOR_AUTOFILL_AUTO and check that autofill isenabled().
You may need to manage some of the settings within the java force the Autofill request:
Sometimes, you may need to force an autofill request to occur in response to a user action. .../...
public void eventHandler(View view) {
AutofillManager afm = context.getSystemService(AutofillManager.class);
if (afm != null) {
afm.requestAutofill();
}
}
Do you have an app on you phone that implements an Autofill service? I tried it with "Autofill with Google" service, and could got my phone number autofilled without problems (with emulator running SDK 26). You will need a service part for get the autofill working. See this example.
Get the latest OS image. After downloading and installing the update that became available on 2017-09-21 for my Google Pixel XL device, autofill works perfectly. So, it suffices to have android:autofillHints="phone" in XML, no other changes are required to enable the autofill feature.
The "Contents can't be autofilled" - this was caused for me because i did not agree to the auto fill service. So go into your android settings in Oreo and above and search for "autofill" . find your service (mine was default googles) and there should be a prompt to agree to its service. toggle it off and one if it does not appear. Afterwards i was able to use autofill.

At what point does the system check for the Android Manifest?

Does the Android Manifest check for the available components to be used before an application starts running, or does the system check for the Android Manifest every time a new component is being instantiated? By components I mean activities, services, etc...
What is the process involved?
Also, can an application still go back and forth to check on the android manifest even after it is running to check on xml activity attributes such as the android:name, android:label, or even intent filters, for different purposes such as to see whether a component to be used has already been defined?
Well to say it in a simple way-
Manifest contains permission like- "SD card read/write permission". So, while installing an app if you don't have a SD card than your won't get installed.
Again manifest contains "minimum SDK version"- which checks what OS version you have in your mobile, if your mobile OS version is less than the minimum version defined in manifest than the app won't install in your mobile.
In the manifest you have a list of all the activities and services too. So, without adding these in the manifest- your activities/services wont work.
So, these sort of checking and permissions are in manifest - the information the system must have before it can run any of the app's code.
Hope i have been able to keep it short and simple :-D
The manifest is a part of the app - it gets packaged with the app in its installation APK.
The manifest tells the system what APIs the application will use. When the app is installed, the system tells the user what sets of potentially sensitive APIs the application will use (as listed int he manifest) and if the user allows the app to be installed the system then assumes that the use of those APIs is permitted.
The OS will not permit the app to use other sensitive APIs that the app did not declare in the manifest.
Android Manifest file contains important information like the Java package name of the application, permissions, descriptions about activities,services... The system must have these information before running the app code.By this reason, the system doesn´t check the Android Manifest in runtime.
More here:
Android Manifest - Android Developer

What is the purpose of disabling an Android service in the manifest?

In Android it is possible to create a Service to do background tasks, etc by creating a subclass of Service. It order to use the Service it must be specified in the manifest for the app:
All services must be represented by elements in the manifest file. Any that are not declared there will not be seen by the system and will never be run.
One of the parameters for a Service in the manifest is the 'enabled' option:
Whether or not the service can be instantiated by the system — "true" if it can be, and "false" if not.
What is the purpose in declaring a Service to be disabled - if I didn't want the Service surely I just wouldn't write it / add it to the manifest in the first place?
The only use I can see for disabling a Service in the manifest, and it seems of limited value, is if it's a Service used only for debugging, and I want it disabled for production. Am I missing something?
The android:enabled attribute set to a boolean value defined in a resource file. The purpose of this attribute is to enable or disable the service on devices running on different Android OS version.
For example, to disable the service on devices running Android 4.3 or lower include menifest attribute android:enabled="#bool/atLeastKitKat".
In addition to including this attribute in the manifest, you need to do the following:
In your bool.xml resources file under res/values/, add this line:
<bool name="atLeastKitKat">false</bool>
In your bool.xml resources file under res/values-v19/, add this line:
<bool name="atLeastKitKat">true</bool>
if I didn't want the Service surely I just wouldn't write it / add it to the manifest in the first place?
In the very specific case of a Service, I agree that it would be rare for you to want to disable it. One possibility would be for a service that plugs into the system (e.g., input method editor, accessibility service) that you only want to enable at runtime (via PackageManager and setComponentEnabledSetting()) if the user make an in-app purchase that unlocks the feature. I am sure that there are other Service scenarios for this, though none are leaping to mind at this early hour of the day (yawn!).
However, I suspect that Service "inherits" its android:enabled setting by virtue of being one of the Android component types, along with activities, providers, and receivers. Other scenarios for android:enabled will be a bit more common with other component types. For example, it is considered good form to have your BOOT_COMPLETED receiver be disabled until you know that you need it. So, for example, if the BOOT_COMPLETED receiver is only used to resume a download interrupted by a reboot, you only need that receiver enabled if you are doing a download. At all other times, you may as well leave it disabled, so you don't waste the user's time during "normal" reboots.

why acitivies have to be registered in manifest file

we worked for exam with our friends. I tried to explain manifest file, talking about how to do things. But I see that I did know why to register activities to androidManifest.xml. Still do not know :). Does anyone have an idea?
The manifest file is used by the system to know what kind of components do the application have. Without registering your Activities/Services/Receivers/Content Providers the system would have to scan and parse the whole apk every time someone wants to use a specific component to find it. This would be really slow, that's why there is the AndroidManifest.xml, which is a small file, and it can be parsed fast to find the required component.
Manifest file describes the following features...
Version Number and Version Code:
This is useful, when you are uploading the application in Google play or go for upgrade the existing published apk.
2.minSdk and targetSdk:
mentioned your min and max version number your application supports.
3.application tag:
used to set the first activity or home activity when you launch an application from laucher.
4.activity tag:
the list of all activities in the application declared as child tag in application tag for the easier navigation to activity manager.
When we switch one activity to another activity, the activity manager checks whether this activity is declared in manifest file or not. If not found throws exception.
Uses: Developer can have look at all the activities at a glance (By Manifest file)
5.Filter tags: By intent filters in activity tag, User can open any kind of application activity.
Uses permission and Uses features:
All application resources are declared here.
example: Internet connectivity is needed for your application, Uses WIFI in your application.

Android App should NOT launch on receiving Intent

I have written an Android Application and the generated .APK file I uploaded in Android Market. So, a User can download that apk and install in his device.How can I restrict my apk to launch , if he calls from other application through Intent. That means my application should not respond to any intents from other outside Applications.
Is there any possible way to restrict my application's launch from intents from other application.?
I will be waitinig for reply.
Thanks in Advance,
Try setting android:exported="false" to all activities defined at AndroidManifest.xml
That's from activity element description:
android:exported Whether or not the activity can be launched by components of other applications — "true" if it can be, and "false" if not. If "false", the activity can be launched only by components of the same application or applications with the same user ID.
The default value depends on whether the activity contains intent filters. The absence of any filters means that the activity can be invoked only by specifying its exact class name. This implies that the activity is intended only for application-internal use (since others would not know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the activity is intended for external use, so the default value is "true". This attribute is not the only way to limit an activity's exposure to other applications. You can also use a permission to limit the external entities that can invoke the activity (see the permission attribute).
Also here are good paragraphs about application permissions https://developer.android.com/training/articles/security-tips.html I guess you can use that to restrict access to your app.

Categories

Resources