Blog Infos
Author
Published
Topics
Published

Android 14 is already here, so I took the documentation, experts’ reviews, and other available resources to sort out all the important changes that will affect most application developers. Let’s examine new restrictions on background mode, changes in Foreground Service, new restrictions on the work of Intent and BroadcastReceiver. In this release, we have many restrictions, but we’ve also got new features.

Thanks for

 for his articles about Android 14. I based the articles on them.

Predictive Back Gesture in action

Demonstration of animation of using back navigation. Source

 

Already in Android 13, we were warned that in the next version of Android, we should expect updates of the Back Gesture and Predictive Back Gesture with animation in the form of a preview screen where we will move. Animation for that preview is still not working. If you want it to work, you should activate it in the developer’s settings.

Demonstration of animation of using back navigation

An example of your personal animation when doing the Back gesture

Also, the ability to create personal transition animations inside the application was added. For that, a method handleOnBackProgressed() was added in OnBackPressedCallback. This method is called with the progress of the Back Gesture, as well as the handleOnBackPressed() and handleOnBackCancelled() methods, which are called at the end of the Back Gesture’s animation and its cancellation, respectively. On the screen, you can see an example of implementing your custom animation using the Jetpack AppCompat 1.8.0 library.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val box = findViewById<View>(R.id.box)
        val screenWidth = 
            Resources.getSystem().displayMetrics.widthPixels
        val maxXShift = (screenWidth / 20)

        val callback = object : OnBackPressedCallback(
            enabled = true
        ) {

            override fun handleOnBackProgressed(
                backEvent: BackEvent
            ) {
                when (backEvent.swipeEdge) {
                    BackEvent.EDGE_LEFT ->
                        box.translationX = backEvent.progress *     
                            maxXShift
                    BackEvent.EDGE_RIGHT ->
                        box.translationX = -(backEvent.progress * 
                            maxXShift)
                }
                box.scaleX = 1F - (0.1F * backEvent.progress)
                box.scaleY = 1F - (0.1F * backEvent.progress)
            }

            override fun handleOnBackPressed() {
                // Back Gesture competed
            }

            
            override fun handleOnBackCancelled() {
                // Back Gesture cancelled 
                // Reset animation objects to initial state
            }
        }
        this.onBackPressedDispatcher.addCallback(callback)
    }
}

Also, instead of the overidePendingTransition() method, which is now marked as deprecated, you should call the new overrideActivityTransition() method. The existing method doesn’t work correctly with the Predictive Back, because it has a higher priority when executing the transition animation.

// New API
overrideActivityTransition(
    enterAnim = R.anim.open_trans,
    exitAnim = R.anim.exit_trans,
    backgroundColor = R.color.bgr_color
)

// deprecated
overridePendingTransition(R.anim.open_trans, R.anim.exit_trans)
Restriction on installation of old applications

One of the first changes announced in Android 14 will be the inability to install applications with targetSdk <= 23 (Android 6.0). Do not confuse it with minSdk.

The change is intended to stop the distribution of applications that don’t update to new versions of targetSdk and are distributed outside of Google Play, taking advantage of old Android vulnerabilities. In this way, applications can obtain all permissions during installation by bypassing the Runtime Permission mechanism.

When the user tries to install such an application, they will see an error, and in Logcat will appear a log with details.

INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 23, but found 7

Installation of applications with any targetSdk will be available via adb with a special flag to ignore restrictions.

adb install --bypass-low-target-sdk-block FILENAME.apk

In my opinion, this is the right restriction to fight the old software, and for those enthusiasts who want to do this, they left the opportunity via adb. I bet that with each new Android release, the minimum allowed targetSdkVersion will rise. In future, this policy may even not be related to new releases, but will extend to all versions of Android.

Internationalization

Now users will be able to change the regional setting regardless of the chosen in the system locale: temperature units, first day of the week, and system of calculation. Developers should consider this information when displaying information in applications.

Grammatical Inflection API

For languages in which the concept of gender exists, such as Russian, Italian, French, etc., the new version of Android introduced the Grammatical Inflection API. Now you can specify the gender of the user for an application through the GrammaticalInflectionManager, which will cause the Activity to be re-created as part of the configuration.

// Specify user's gender for grammar
val gIM: GrammaticalInflectionManager = сontext.getSystemService()
gIM.setRequestedApplicationGrammaticalGender(
  Configuration.GRAMMATICAL_GENDER_FEMININE
)

Now in resources, you can create separate strings for different genders.

Nonlinear text increment

In Android it is recommended to set the text size in sp, a special unit that takes into account the text scale specified by the user in the system settings. The downside is that the entire text was enlarged, and if the small text became readable, the larger titles became unreadable due to cropping.

Android 14 introduces a new text scaling system according to the Web Content Accessibility Guidelines (WCAG). Now a non-linear font scaling will be applied. This means that the larger text will not increase as much as the smaller one. In addition, the maximum text size was increased. On Pixel 7 Pro with Android 13, the maximum value was 130%; in Android 14 it is 200%.

Comparison of text sizes in Android 13 and Android 14 on Pixel 7 Pro

To correctly convert pixels to sp and back, you need to use TypedValue.applyDimension() and TypedValue.deriveDimension(). These APIs take into account nonlinear text scaling features, as opposed to simply multiplying the text size in SP by the scaling factor that can be obtained in Configuration.fontScale and DisplayMetrics.scaledDensity.

// Convert 10 SP to PX
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10F, displayMetrics)

// Convert 50 PX to SP
TypedValue.deriveDimension(TypedValue.COMPLEX_UNIT_SP, 50F, displayMetrics)
Share Sheet

Android 14 has updated the design and features of Share Sheet, a systemic dialogue that you can see when sharing text, pictures, or other content.

On Pixel 7 Pro in the Direct Share section, instead of 4 elements on Android 13, 5 were placed in a fresh version of the OS. They also changed the ranking system of what you see in this section. Use ShortcutManagerCompat.pushDynamicShortcut() when you send a message to the user, and call addCapabilityBinding() with the actions.intent.SEND_MESSAGE value when you create ShortcutInfo. In my opinion, the fact that they didn’t add constants for this solution is very strange.

ShortcutManagerCompat.pushDynamicShortcut(context,
    ShortcutInfoCompat.Builder(context, id)
        // Configure Shortcut
        .addCapabilityBinding("actions.intent.SEND_MESSAGE")
        .build()
)

Updated Share Sheet in Android 14. Source

 

Now in the standard system UI it will be possible to add additional actions as a ChooserAction object, containing the icon, title and PendingIntent, that will be sent when you select an action. There is no limit for the number of your personal actions.

There is also another special action, which is intended to edit the sent content. To create it you also need to use ChooserActions.

All created additional actions must be added to the Intent through the special new EXTRA. You can see how to do it below.

Job Offers

Job Offers


    Senior Android Engineer

    Carly Solutions GmbH
    Munich
    • Full Time
    apply now

    Senior Android Developer

    SumUp
    Berlin
    • Full Time
    apply now

OUR VIDEO RECOMMENDATION

No results found.

Jobs

val intent: Intent = // Create Inent и put content for sharing

val modifyAction: ChooserAction = 
    ChooserAction.Builder(modifyIcon, "Modify Share", modifyActionIntent).build()
// Specify action to edit content
intent.putExtra(EXTRA_CHOOSER_MODIFY_SHARE_ACTION, modifyAction)


// Additional actions that can be done with content
val customActions: Array<ChooserAction> = arrayOf(
  ChooserAсtion.Builder(copyIcon, "Copy", copyIntent).build(),
  ChooserAсtion.Builder(albumIcon, "Create Album", createAlbumIntent).build(),
  ChooserAсtion.Builder(createLinkIcon, "Create link", createLinkIntent).build()
)
// Add additional actions that can be done with content
inent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, customActions)


// Create Intent for Share Sheet
val chooserIntent = Intent.createChooser(customActions, "Share 1 image")
// Launch Share Sheet
context.startActivity(chooserIntent)

It would be great if they added some standard actions out of the box, as it was in Android 13, but at the time of the release of this article, I couldn’t find any such actions.

SCHEDULE_EXACT_ALARM is disabled by default

For applications with targetSdk 33+

In Android 12 a new SCHEDULE_EXACT_ALARM permission was introduced for using the API AlarmManager, associated with the exact time of alarm going off. In Android 13 appeared the new USE_EXACT_ALARMS permission. In Android 14 no new permission was added, but they changed the work of SCHEDULE_EXACT_ALARM. Now it will not be issued to applications with targetSdk 33 and higher. Permission will be granted in cases of a device update or backup restoration, but not for the new installations. Exceptions include applications signed with a system certificate and apps with special privileges, as well as those applications for which battery optimization is disabled.

Foreground Service type is required

In Android 10, for all Foreground services, appeared the possibility to announce the type of service that specifies the purpose of its launch. In Android 14, it becomes mandatory to specify the type for all Services that can be launched as Foreground, and in modern Android, this is almost all cases. To cover all the options of using Foreground Service they added new types of services, and each of them has a special permission.

<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Permission to launch Foreground Service -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <!-- Permission to launch Foreground Service with dataSync type -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

    <application>
        <service
            android:name=".SyncService"
            android:foregroundServiceType="dataSync"
        />
    </application>
</manifest>

This new feature will make it clear whether operations performed in the Service fall under the permitted categories. The system will be able to have a better understanding of what the application does and whether it is something suspicious. Google strongly recommends using WorkManager and other special APIs and, in case they don’t suit you, implementing ForegroundService.

Google Play will also check the Foreground Service during the build uploading phase. Any application with Android 14 support (targetSdk>= 34) must confirm that the Service with the announced task type is needed to run the application. Otherwise, you won’t be allowed to publish in the store.

To launch the Foreground Service in addition to adding the permission to launch the Foreground Service you will also need to add the permission to launch a specific type of service. All these permissions are of the normal type, i.e., the permissions are issued automatically when you install the application, and you don’t have to request them separately. In addition to the permission, there are other requirements, for example, for the Service that works with the camera, it is necessary that AndroidManifest also has a CAMERA permission. More information about types and connected permisions can be found in official documentation

All types are associated with a specific use case, except the following:

  • systemExempted — special type, designed for system applications and alarm clocks, which are determined by the presence of SCHEDULE_EXACT_ALARM and USE_EXACT_ALARM permissions.
  • specialUse type is used when all other types of Foreground Service don’t suit you. Its declaration, in addition to type and permission, requires specifying the reason for using this type in a special property in AndroidManifest. Write your ideas on how you can use these new types in the comments.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />

    <application>

        <service
            android:name=".SpecialService"
            android:foregroundServiceType="specialUse">
            <property
                android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
                android:value="Reason to use special service type" />
        </service>
    </application>
</manifest>
  • shortService type is intended to perform operations that cannot be interrupted or delayed. This type doesn’t require additional permissions but has several special restrictions: limited lifetime (up to 3 minutes), inability to launch other Foreground Service, inability to restart when the application’s process is stopped by the system, etc.

The lifetime of the Service is counted from the moment of call of the startForeground(). Service is expected to be finished by calling stopSelf() or stopForeground(). When the runtime expires, a new callback method will be called in the Service — onTimeout(). This callback warns you that you have one last opportunity to stop the Service. Otherwise, ANR occurs even if the application performs other operations in the Foreground Service. Disabling battery optimization doesn’t affect the limit for Service lifetime.

Lifetime extensions of Short Foreground Service are possible. If the application can launch the Foreground Service it can restart the Short Foreground Service. Short Service restart will increase the Service lifetime by 3 minutes.

Limitations on Implicit Intent

Android 14 continues to push best practices to prevent malware from exploiting internal application components. Now Implicit Intents will only be delivered to exported application components; for not exported ones, Explicit Intents should be used.

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="dev.androidbroadcast.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
// Drop the exception in case if targetSdk 34+
context.startActivity(Intent("dev.androidbroadcast.action.APP_ACTION"))

// Make the Intent clear by specifying the application package
val explicitIntent = 
    Intent("dev.androidbroadcast.action.APP_ACTION")
        // Specifying the application package where the component is located    
        // In case of your application, package of your application
        .setPackage(context.packageName)
context.startActivity(explicitIntent)

The second change to the Intent mechanism is that any mutable PendingIntent that uses Implicit Intent will now result in an exception being thrown.

BroadcastReceiver changes

In addition, the behavior for Intent that is delivered to context-registered (registered in code) BroadcastReceiver is changed for all applications, regardless of targetSdk. All Intents they may receive will NOT be delivered when the application is in a cached state, i.e., minimized and the user hasn’t used it for some time. Intent delivery will happen when the application becomes active again. In addition, when sending multiple identical Intentents, only one of them can be delivered. The BroadcastReceivers registered in AndroidManifest will continue to work as before.

Also BroadcastReceiver registration from the code has become stricter. Now it is necessary to specify whether or not they are exported by analogy, as is done for all components in the AndroidManifest. When registering you will need to specify the RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag. The change only works for applications with support for Android 14.

class DataReceiver: BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // Process data
    }
}

val intentFilter = IntentFilter() // configure IntentFilter
context.registerReceiver(DataReceiver(), intentFilter, Context.RECEIVER_NOT_EXPORTED)
JobScheduler updates

JobScheduler got the ability to launch long tasks for data transfers between the device and the server. This type of task is called a user-initiated data transfer job. This type of Job can only be launched when the application is visible to the user or when the application can launch an Activity from the background.

To launch a user-initiated data transfer job, you must specify the RUN_USER_INITIATED_JOBS permission in AndroidManifest and add a Service that extends the JobService class. When creating JobInfo you need to call setUserInitiated() method with true as an argument. A pre-requirement for launching JobInfo is to display a system notification. You should do it when calling onStartJob().

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" />

    <application>
        <service
            android:name="dev.androidbroadcast.CustomTransferService"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE" />
    </application>
</manifest>
val networkRequest = NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
    // Additional network request requirement
    .build()

val jobInfo = JobInfo.Builder(1, ComponentName(context, CustomTransferService::class.java))
    .setUserInitiated(true)
    .setRequiredNetwork(networkRequest)
    .setEstimatedNetworkBytes(ONE_GIGABYTE, ZERO_BYTES)
    // ...
    .build()

val jobScheduler: JobScheduler = checkNotNull(context.getSystemService())
jobScheduler.schedule(jobInfo)
class CustomTransferService : JobService() {

    override fun onStartJob(job: JobParameters): Boolean {
        if (job.jobId == JOB_ID) {
            // Showing a notification
            setNotification(job, NOTIF_ID, newNotification(), JobService.JOB_END_NOTIFICATION_POLICY_REMOVE)
            val success = doDataTransfer()
            jobFinished(job, wantsReschedule = !success)
            return false
        }
        error("Job isn't handled")
    }
}

For a successful start, it will be necessary to fulfill all the launch conditions. Additionally, the system needs to have the resources for its execution. An important difference of a user-initiated data transfer job is that it is not subject to App Standby Buckets quotas for starting a Job. Under certain conditions, the system can still stop the task if it considers it necessary. Before that, the onStopJob() method will be called, in which you are advised to save the current progress of the network operation so that after a restart you don’t have to do the work from the beginning but just complete the necessary part.

class CustomTransferService : JobService() {

    override fun onStopJob(job: JobParameters): Boolean {
        if (job.jobId == JOB_ID) {
            // Saving data transfer progress
            return true
        }
    }
}

From the API, it seems that the User Initiated tag can be made for any type of Job, but the documentation of the method says that in Android 14, it should be called only in combination with setRequiredNetwork() or setRequiredNetworkType(). Perhaps in future versions of Android, we will see more types of explicitly tagged tasks that can be initiated by the user.

At the time of Android 14’s release, Jetpack WorkManager, Google’s recommended replacement for JobScheduler, hadn’t explicitly added this feature to its API. This may happen in future releases, or the change will be used under the hood of existing WorkManager API.

Partial access to photos and videos

Similar to iOS, Android 14 provides partial access to photos and videos. Now, when you request media, the user will see a dialog that asks to select either to provide access to all media or to provide access only to individual photos/videos. This new feature will work for all applications, regardless of their targetSdk.OS

On the left — Android 14; on the right — iOS 14. Source

Android 13 already introduced separate permissions for photo access and video access. Now there will be another additional permission READ_MEDIA_VISUAL_USER_SELECTED that allows you to repeatedly re-request a selection for individual photos/videos. The new permission should be used in addition to the existing READ_MEDIA_IMAGES and READ_MEDIA_VIDEO to support the new behavior. Declaring it means that your application supports this reselection.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

    <!-- Devices running Android 13 (API level 33) or higher -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- To handle the reselection within the app on Android 14 -->
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

</manifest>

Access to individual media will be granted temporarily, but the documentation doesn’t describe for how long. If the new permission isn’t declared, the partial access will be revoked immediately when the application goes into the background or the user kills the application. Something similar to how a temporary one-time permission works. Therefore, you cannot store the states of obtaining READ_MEDIA_VISUAL_USER_SELECTED permission, and you need to check them every time.

When you update your device to Android 14, if the application has full access to the user’s photos/videos by obtaining the appropriate permissions, it will maintain the same level of access to this data.

The documentation says that adding a new permission and mechanism will not affect the work of your application. But in future it should be modified taking into account that the user may want to add new photos to the selection. Some applications are even designed to work with the entire media library and will certainly need to be reworked. As a user, I see it as a big improvement because all sorts of messengers and social networks will no longer be able to access everything I have in the gallery.

If your application needs to access photos/videos while running in the background, it is strongly recommended to support the new permission for further correct operation; otherwise, you may regularly have these permissions revoked in Android 14.

Improvements for app stores

Android 14 makes life easier for third-party stores by adding new APIs to PackageInstaller. Let’s start with the restrictions on installing applications. Now it can happen at any time by calling the corresponding API. Android U added the Install Constraints API, which allows you to specify conditions under which you can perform installation.

PackageInstaller.InstallConstraints.Builder()
    // The application isn’t visible to the user
    .setAppNotForegroundRequired()
    // No interaction with the application
    .setAppNotInteractingRequired()
    // The application is visible but not in the foreground
    .setAppNotTopVisibleRequired()
    // The device isn't used
    .setDeviceIdleRequired()
    // No current phone call
    .setNotInCallRequired()
    .build()

Then you can check whether the specified applications meet the requirements using checkInstallConstraints() method

val packageInstaller: PackageInstaller = //...
packageInstaller.checkInstallConstraints(
    packageNames = listOf("dev.androidbroadcast"),
    constraints,
    Executors.newSingleThreadExecutor()
) { result: PackageInstaller.InstallConstraintsResult ->
    if (result.areAllConstraintsSatisfied()) {
        // install APK files
    }
}

You can also call the blocking waitForInstallConstraints() method, which will wait until the conditions for the specified applications are met.

packageInstaller.waitForInstallConstraints(
    listOf("dev.androidbroadcast"),
    constraints,
    intentSender,
    timeout = Duration.ofHours(1).toMillis()
)

You can defer the update until the conditions are met by using commitSessionAfterInstallConstraintsAreMet() method

packageInstaller.commitSessionAfterInstallConstraintsAreMet(
    sessionId,
    intentSender,
    constraints,
    timeout = Duration.ofHours(1).toMillis()
)

Now, before installing multiple APKs via the PackageSession API, you can get the user’s permission to do so. You need to call the new requestUserPreapproval() method. This allows you to work conveniently with the App Bundle without having to repeatedly obtain permission to install individual APKs. Thus, updates from the store for multiple applications will require a single user approval.

val sessionId: Int = packageInstaller.createSession(
    PackageInstaller.SessionParams(SessionParams.MODE_INHERIT_EXISTING)
)
val pendingIntent: PendingIntent = // ...

val session: Session = packageInstaller.openSession(sessionId)
// Call the system dialog to request permission from the user
// intentSender determines where the result will be sent
session.requestUserPreapproval(
    PreapprovalDetails.Builder()
        .setIcon(iconBitmap)
        .setLabel(message)
        .setLocale(locale)
        .build(),
    pendingIntent.intentSender
)
// Wait for the user’s permission, and then the session starts
session.commit(intentSender)

To protect the user from updating applications from an unexpected store, the setRequestUpdateOwnership() method was introduced in the PackageInstaller API. It requires the user to confirm that they really want to change the installer application. This usually happens when you install applications from one application, for example, Google Play, but try to update them from another app store. From what I’ve been able to figure out, this feature is intended for critical packages: Google Play Services, Health Connect, Chrome WebView.

Warning when updating an application. Source

When a user tries to update an application from a different installer, they will see a dialog with a warning that normally the application should be updated from a different source. The user will need to confirm the update.

Screenshot detection

To detect screenshots in Android 14, a special API appears in Activity. It calls Callback after the screenshot was taken. The API can only detect screenshots that were taken by the user on the device using a special key combination. If the screen is captured during the test using special commands or via ADB, callback will not work. For the API to work, you will need to add the DETECT_SCREEN_CAPTURE permission to AndroidManifest. Then register a callback in onStart(), and remember to remove it in onStop(). Otherwise, you can use Jetpack Lifecycle.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
</manifest>
class MainActivity : Activity() {

    private val mainExecutor = MainEcxector()
    
    private val screenshotCallback = ScreenCaptureCallback {
        // A screenshot was taken
    }

    override fun onStart() {
        super.onStart()
        registerScreenCaptureCallback(mainExecutor, screenshotCallback)
    }

    override fun onStop() {
        super.onStop()
        unregisterScreenCaptureCallback(screenshotCallback)
    }
}
Separate permission to show full-screen system notifications

Full-screen notification using an example of an alarm clock. Source

Android 11 introduced full-screen notifications that will be visible on the lock screen and when full-screen applications are running. This format was intended to show such important notifications as incoming calls and alarms. Starting with Android 14, only the applications for which it was intended will be able to obtain the existing USE_FULL_SCREEN_INTENT permission. Google Play will monitor this when moderating builds. After updating your Android 14 device, all applications that already use this permission will be able to do so further, but when downloading a new build to Google Play, you will have to remove it if you don’t meet the policy.

It is also important to remember that the user will always be able to revoke the permission, so before showing a full-screen notification, it’s important to check the availability of this feature by calling NotificationManager.canUseFullScreenIntent(). To ask the user to grant you this permission, you can use a new Intent with ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT, which will open a screen where the user can grant the permission.

val intent = Intent(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT)
try {
     context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
     // Activity cannot be started
}
Data Safety from Google Play on Android system

In 2023, Google Play made it mandatory to fill in information about ensuring the security of the data the application works with. Now this information will be visible not only on the application page in store but also in the system. In Android 14, when your application requests a permission to access user’s location in the system dialog, the user will be able to see why the application needs to access their location and with whom that data will be shared. This section will be displayed only if the application shares location with third-party services.

Data Safety in Android 14. Source

If the application changes the sharing of the user’s location with other services, the user will receive a monthly notice about these changes. When opened, the user will see an Update Location Sharing section with a list of all applications that have changed the corresponding rules.

Data Safety change notification

The change is intended to make the sharing of data transparent for users. Applications will no longer be able to change the rules unnoticed by the user. It would be great to receive such notifications not only about the location but also about all other types of data.

Foreground Service Samsung

A small but important change — Google has started to actively work with vendors to standardize the behavior of applications in the background in the Android-based operating systems from different manufacturers. Samsung has already stated that One UI 6.0 based on Android 14 will guarantee Foreground Services to work in accordance with the documentation and new policy. For now, we can only hope that these aren’t just empty words and that the situation will change for the better.

Other changes

There have been a lot of changes in Android 14, but some of them are small and will affect a few, so let’s go through them quickly:

 

val options = ActivityOptions.makeBasic()
    .setPendingIntentBackgroundActivityStartMode(
         ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
    )

val pendingIntent = 
    PendingIntent.getActivity(context, REQUEST_CODE, intent, options)

pendingIntent.send()
  • When binding a Service from an active application, you will have to explicitly specify that the background application can launch an Activity by adding BIND_ALLOW_ACTIVITY_STARTS flag when calling the bindService() method
context.bindService(intent, serviceConnection, Context.BIND_ALLOW_ACTIVITY_STARTS)
  • For the Path API the ability to obtain an iterator and traverse its segments was added
// Create path
val path = Path().apply {
    moveTo(1.0f, 1.0f)
    lineTo(2.0f, 2.0f)
    close()
}

val pathIterator: PathIterator = path.pathIterator
for (segment in pathIterator) {
    println("segment: ${segment.verb}, ${segment.points}")
}
  • Now you can also use Path interpolation. This will be useful for animating between two Paths.
val interpolatedResult = Path()
if (path.isInterpolatable(otherPath)) {
    path.interpolate(otherPath, t = .5f, interpolatedResult)
}
  • Android notifications associated with Foreground Service or with an ongoing tag can no longer be removed. Changes occurred with the advent of Task Manager. In Android 14, almost all notifications can be removed. Exceptions are ongoing notifications, call notifications and some notifications from Android Enterprise. These notifications cannot be removed neither from the lock screen nor by pressing the Delete All button.
  • The rules for running tasks in the background have become stricter. A few seconds after the application enters the cached state, any background work is prohibited, except for the APIs designed for this: WorkManager, JobScheduler, or Foreground Service. The background work of the application becomes unavailable much faster than it does in Android 13.
  • Android 14 continues to add features from the latest OpenJDK. This time there were updates from the library and features of the Java 17 language: multiline literals, pattern matching in instanceof, sealed classes, etc. The features will be ported to Android 12 and 13 thanks to a modular update system. If any of you have been waiting for these features, write about it in the comments. Everyone I know seems to be happy with JDK 8 and Kotlin
  • Fixed Zip files vulnerability exploit
  • All Android 14-enabled applications that use dynamic code loading will only be able to do so with read-only files
val jar = File("DYNAMICALLY_LOADED_FILE.jar")
// Make the file read-only
jar.setReadOnly()
// Loading the code
val cl = PathClassLoader(jar, parentClassLoader)
  • All applications on Android 14 will now be able to stop background processes only within the same application. If you try to stop another application’s process, nothing will happen, only a message will appear in LogCat
  • CredentialManager and HealthConnect have become system services in Android, but it’s still recommended to use these APIs through appropriate Jetpack libraries
  • It become possible to mark View to limit their visibility only to Accessibility Service that assists users with disabilities
view.setAccessibilityDataSensitive(View.ACCESSIBILITY_DATA_SENSITIVE_YES)
  • For devices that are releasing with Android 14, hardware support for the AV1 codec and Identity Credential will be required. It will allow driving licenses to be stored on devices.
  • A new role has been added for applications — NOTES. This role is designed for applications that are used for taking notes. Applications with this note will by default start when an Intent with the CREATE_NOTE action is sent
  • Annotactions @CriticalNative and @FastNative have become a public part of Android SDK. They are used for marking native methods to accelerate JNI work in ART
  • Android Beam support was completely removed from the Android SDK
  • Lossless audio transition over USB is now supported. Audiophiles will be happy. Google is working with partners to make this feature available on devices.
  • Hardware acceleration of the rendering buffer has appeared in Canvas
  • New chipsets launching with support for Android 14 or higher must not support 32-bit NDK ABIs.
  • Cross-device SDK has become part of the Android SDK
  • Support for 10-bit HDR images was added, allowing to save more information about colors and contrast. The format is called Ultra HDR. Google camera and Google Photos will support it
  • New Mainline modules were added: Health Connect, module for managing flags feature, Cronet, Device Lock Controller, Remote Key Provisioner and Root Certificate
  • Improved support for handwriting. This feature will be used on tablets
  • Satellite calling support
  • The VirtualDeviceManager system service was released. It will be used for creating and managing virtual devices. Do not confuse it with emulators in Android Studio
Conclusion

Every year, Android adds less and less new features, and works more to improve the Android SDK and make rules for working with standard components of the Android system stricter. Many new APIs have been developing within Jetpack for a long time. They are not tied to the Android version and are updated independently. The Android SDK itself has become a bridge between OS and Jetpack, and developers are increasingly using the latter, Kotlin libraries and other third-party solutions.

Share your opinion about the new version of Android in the comments. What you like and what you don’t. Maybe you can even tell me about what I missed.

This article was previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Grammatical Inflection API provides a more personalized, natural-sounding user experience for users speaking languages…
READ MORE
blog
Check out Part 1 if you haven’t already to read more about Android 14’s…
READ MORE
blog
Android 14 introduces a privacy-preserving screenshot detection API to create a more standardized screenshot…
READ MORE
blog
Introducing Android14’s Regional Preferences API, which allows users to set their regional preferences. With…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu