이전 버전과 마찬가지로 Android 15에는 앱에 영향을 미칠 수 있는 동작 변경사항이 포함되어 있습니다. 다음 동작 변경사항은 Android 15 이상을 타겟팅하는 앱에만 적용됩니다. 앱이 Android 15 이상을 타겟팅한다면 이러한 동작을 올바르게 지원하도록 앱을 수정해야 합니다(적용되는 경우).
앱의 targetSdkVersion
과 관계없이 Android 15에서 실행되는 모든 앱에 영향을 미치는 동작 변경사항 목록도 검토해야 합니다.
핵심 기능
Android 15는 Android 시스템의 다양한 핵심 기능을 수정하거나 확장합니다.
포그라운드 서비스 변경사항
We are making the following changes to foreground services with Android 15.
- Data sync foreground service timeout behavior
- New media processing foreground service type
- Restrictions on
BOOT_COMPLETED
broadcast receivers launching foreground services - Restrictions on starting foreground services while an app holds the
SYSTEM_ALERT_WINDOW
permission
Data sync foreground service timeout behavior
Android 15 introduces a new timeout behavior to dataSync
for apps targeting
Android 15 (API level 35) or higher. This behavior also applies to the new
mediaProcessing
foreground service type.
The system permits an app's dataSync
services to run for a total of 6 hours
in a 24-hour period, after which the system calls the running service's
Service.onTimeout(int, int)
method (introduced in Android
15). At this time, the service has a few seconds to call
Service.stopSelf()
. When Service.onTimeout()
is called, the
service is no longer considered a foreground service. If the service does not
call Service.stopSelf()
, the system throws an internal exception. The
exception is logged in Logcat with the following message:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
To avoid problems with this behavior change, you can do one or more of the following:
- Have your service implement the new
Service.onTimeout(int, int)
method. When your app receives the callback, make sure to callstopSelf()
within a few seconds. (If you don't stop the app right away, the system generates a failure.) - Make sure your app's
dataSync
services don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer). - Only start
dataSync
foreground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background. - Instead of using a
dataSync
foreground service, use an alternative API.
If your app's dataSync
foreground services have run for 6 hours in the last
24, you cannot start another dataSync
foreground service unless the user
has brought your app to the foreground (which resets the timer). If you try to
start another dataSync
foreground service, the system throws
ForegroundServiceStartNotAllowedException
with an error message like "Time limit already exhausted for foreground service
type dataSync".
Testing
To test your app's behavior, you can enable data sync timeouts even if your app
is not targeting Android 15 (as long as the app is running on an Android 15
device). To enable timeouts, run the following adb
command:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
You can also adjust the timeout period, to make it easier to test how your
app behaves when the limit is reached. To set a new timeout period, run the
following adb
command:
adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds
New media processing foreground service type
Android 15 introduces a new foreground service type, mediaProcessing
. This
service type is appropriate for operations like transcoding media files. For
example, a media app might download an audio file and need to convert it to a
different format before playing it. You can use a mediaProcessing
foreground
service to make sure the conversion continues even while the app is in the
background.
The system permits an app's mediaProcessing
services to run for a total of 6
hours in a 24-hour period, after which the system calls the running service's
Service.onTimeout(int, int)
method (introduced in Android
15). At this time, the service has a few seconds to call
Service.stopSelf()
. If the service does not
call Service.stopSelf()
, the system throws an internal exception. The
exception is logged in Logcat with the following message:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"
To avoid having the exception, you can do one of the following:
- Have your service implement the new
Service.onTimeout(int, int)
method. When your app receives the callback, make sure to callstopSelf()
within a few seconds. (If you don't stop the app right away, the system generates a failure.) - Make sure your app's
mediaProcessing
services don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer). - Only start
mediaProcessing
foreground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background. - Instead of using a
mediaProcessing
foreground service, use an alternative API, like WorkManager.
If your app's mediaProcessing
foreground services have run for 6 hours in the
last 24, you cannot start another mediaProcessing
foreground service unless
the user has brought your app to the foreground (which resets the timer). If you
try to start another mediaProcessing
foreground service, the system throws
ForegroundServiceStartNotAllowedException
with an error message like "Time limit already exhausted for foreground service
type mediaProcessing".
For more information about the mediaProcessing
service type, see Changes to
foreground service types for Android 15: Media processing.
Testing
To test your app's behavior, you can enable media processing timeouts even if
your app is not targeting Android 15 (as long as the app is running on an
Android 15 device). To enable timeouts, run the following adb
command:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
You can also adjust the timeout period, to make it easier to test how your
app behaves when the limit is reached. To set a new timeout period, run the
following adb
command:
adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds
Restrictions on BOOT_COMPLETED
broadcast receivers launching foreground services
There are new restrictions on BOOT_COMPLETED
broadcast receivers launching
foreground services. BOOT_COMPLETED
receivers are not allowed to launch the
following types of foreground services:
dataSync
camera
mediaPlayback
phoneCall
mediaProjection
microphone
(this restriction has been in place formicrophone
since Android 14)
If a BOOT_COMPLETED
receiver tries to launch any of those types of foreground
services, the system throws ForegroundServiceStartNotAllowedException
.
Testing
To test your app's behavior, you can enable these new restrictions even if your
app is not targeting Android 15 (as long as the app is running on an Android 15
device). Run the following adb
command:
adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name
To send a BOOT_COMPLETED
broadcast without restarting the device,
run the following adb
command:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name
Restrictions on starting foreground services while an app holds the SYSTEM_ALERT_WINDOW
permission
이전에는 앱이 SYSTEM_ALERT_WINDOW
권한을 보유한 경우 앱이 현재 백그라운드에 있더라도 포그라운드 서비스를 실행할 수 있었습니다 (백그라운드 시작 제한 예외 참고).
앱이 Android 15를 타겟팅하는 경우 이제 이 예외가 더 좁아집니다. 이제 앱에 SYSTEM_ALERT_WINDOW
권한이 있어야 하며 또한 표시되는 오버레이 창이 있어야 합니다. 즉, 앱은 포그라운드 서비스를 시작하기 전에 TYPE_APPLICATION_OVERLAY
창을 먼저 실행하고 이 창을 표시해야 합니다.
앱이 이러한 새로운 요구사항을 충족하지 않고 백그라운드에서 포그라운드 서비스를 시작하려고 하며 다른 예외가 없는 경우 시스템에서 ForegroundServiceStartNotAllowedException
이 발생합니다.
앱이 SYSTEM_ALERT_WINDOW
권한을 선언하고 백그라운드에서 포그라운드 서비스를 실행하는 경우 이 변경사항의 영향을 받을 수 있습니다. 앱이 ForegroundServiceStartNotAllowedException
를 수신하면 앱의 작업 순서를 확인하고 앱이 백그라운드에서 포그라운드 서비스를 시작하려고 시도하기 전에 앱에 이미 활성 오버레이 창이 있는지 확인합니다. View.getWindowVisibility()
를 호출하여 오버레이 창이 현재 표시되는지 확인하거나 View.onWindowVisibilityChanged()
를 재정의하여 가시성이 변경될 때마다 알림을 받을 수 있습니다.
테스트
앱의 동작을 테스트하려면 앱이 Android 15를 타겟팅하지 않더라도 (앱이 Android 15 기기에서 실행되는 경우) 이러한 새로운 제한사항을 사용 설정하면 됩니다. 백그라운드에서 포그라운드 서비스를 시작하는 것에 관한 이러한 새로운 제한을 사용 설정하려면 다음 adb
명령어를 실행합니다.
adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name
앱이 방해 금지 모드의 전체 상태를 수정할 수 있는 경우에 대한 변경사항
Apps that target Android 15 (API level 35) and higher can no longer change the
global state or policy of Do Not Disturb (DND) on a device (either by modifying
user settings, or turning off DND mode). Instead, apps must contribute an
AutomaticZenRule
, which the system combines into a global policy with the
existing most-restrictive-policy-wins scheme. Calls to existing APIs that
previously affected global state (setInterruptionFilter
,
setNotificationPolicy
) result in the creation or update of an implicit
AutomaticZenRule
, which is toggled on and off depending on the call-cycle of
those API calls.
Note that this change only affects observable behavior if the app is calling
setInterruptionFilter(INTERRUPTION_FILTER_ALL)
and expects that call to
deactivate an AutomaticZenRule
that was previously activated by their owners.
OpenJDK API 변경사항
Android 15 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases.
Some of these changes can affect app compatibility for apps targeting Android 15 (API level 35):
Changes to string formatting APIs: Validation of argument index, flags, width, and precision are now more strict when using the following
String.format()
andFormatter.format()
APIs:String.format(String, Object[])
String.format(Locale, String, Object[])
Formatter.format(String, Object[])
Formatter.format(Locale, String, Object[])
For example, the following exception is thrown when an argument index of 0 is used (
%0
in the format string):IllegalFormatArgumentIndexException: Illegal format argument index = 0
In this case, the issue can be fixed by using an argument index of 1 (
%1
in the format string).Changes to component type of
Arrays.asList(...).toArray()
: When usingArrays.asList(...).toArray()
, the component type of the resulting array is now anObject
—not the type of the underlying array's elements. So the following code throws aClassCastException
:String[] elements = (String[]) Arrays.asList("one", "two").toArray();
For this case, to preserve
String
as the component type in the resulting array, you could useCollection.toArray(Object[])
instead:String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
Changes to language code handling: When using the
Locale
API, language codes for Hebrew, Yiddish, and Indonesian are no longer converted to their obsolete forms (Hebrew:iw
, Yiddish:ji
, and Indonesian:in
). When specifying the language code for one of these locales, use the codes from ISO 639-1 instead (Hebrew:he
, Yiddish:yi
, and Indonesian:id
).Changes to random int sequences: Following the changes made in https://bugs.openjdk.org/browse/JDK-8301574, the following
Random.ints()
methods now return a different sequence of numbers than theRandom.nextInt()
methods do:Generally, this change shouldn't result in app-breaking behavior, but your code shouldn't expect the sequence generated from
Random.ints()
methods to matchRandom.nextInt()
.
The new SequencedCollection
API can affect your app's compatibility
after you update compileSdk
in your app's build configuration to use
Android 15 (API level 35):
Collision with
MutableList.removeFirst()
andMutableList.removeLast()
extension functions inkotlin-stdlib
The
List
type in Java is mapped to theMutableList
type in Kotlin. Because theList.removeFirst()
andList.removeLast()
APIs have been introduced in Android 15 (API level 35), the Kotlin compiler resolves function calls, for examplelist.removeFirst()
, statically to the newList
APIs instead of to the extension functions inkotlin-stdlib
.If an app is re-compiled with
compileSdk
set to35
andminSdk
set to34
or lower, and then the app is run on Android 14 and lower, a runtime error is thrown:java.lang.NoSuchMethodError: No virtual method removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
The existing
NewApi
lint option in Android Gradle Plugin can catch these new API usages../gradlew lint
MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi] list.removeFirst()To fix the runtime exception and lint errors, the
removeFirst()
andremoveLast()
function calls can be replaced withremoveAt(0)
andremoveAt(list.lastIndex)
respectively in Kotlin. If you're using Android Studio Ladybug | 2024.1.3 or higher, it also provides a quick fix option for these errors.Consider removing
@SuppressLint("NewApi")
andlintOptions { disable 'NewApi' }
if the lint option has been disabled.Collision with other methods in Java
New methods have been added into the existing types, for example,
List
andDeque
. These new methods might not be compatible with the methods with the same name and argument types in other interfaces and classes. In the case of a method signature collision with incompatibility, thejavac
compiler outputs a build-time error. For example:Example error 1:
javac MyList.java
MyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List public void removeLast() { ^ return type void is not compatible with Object where E is a type-variable: E extends Object declared in interface ListExample error 2:
javac MyList.java
MyList.java:7: error: types Deque<Object> and List<Object> are incompatible; public class MyList implements List<Object>, Deque<Object> { both define reversed(), but with unrelated return types 1 errorExample error 3:
javac MyList.java
MyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible; public static class MyList implements List<Object>, MyInterface<Object> { class MyList inherits unrelated defaults for getFirst() from types List and MyInterface where E#1,E#2 are type-variables: E#1 extends Object declared in interface List E#2 extends Object declared in interface MyInterface 1 errorTo fix these build errors, the class implementing these interfaces should override the method with a compatible return type. For example:
@Override public Object getFirst() { return List.super.getFirst(); }
보안
Android 15에는 악성 앱으로부터 앱과 사용자를 보호할 수 있도록 시스템 보안을 촉진하는 변경사항이 포함되어 있습니다.
보안 처리된 백그라운드 활동 실행
Android 15는 악성 앱으로부터 사용자를 보호하고 사용자에게 악성 백그라운드 앱이 다른 앱을 포그라운드로 가져오거나 권한을 승격하거나 악용하는 행위 사용자 상호작용입니다. 이후 백그라운드 활동 실행이 제한되었습니다. Android 10 (API 수준 29).
스택의 상단 UID와 일치하지 않는 앱이 활동을 실행하지 못하도록 차단
악성 앱이 동일한 작업 내에서 다른 앱의 활동을 시작한 경우
위에 스스로 오버레이하여 해당 앱이 되는 것처럼 보이게 합니다. 이 '작업'은
하이재킹" 기존의 백그라운드 실행 제한을 우회하는 방법
동일한 시각적 작업 내에서 발생합니다 이 위험을 완화하기 위해 Android 15에서는
스택의 상단 UID와 일치하지 않는 앱이 실행되지 않도록 차단하는 플래그
있습니다. 앱의 모든 활동을 선택하려면
allowCrossUidActivitySwitchFromBelow
드림
속성의 AndroidManifest.xml
파일에 있습니다.
<application android:allowCrossUidActivitySwitchFromBelow="false" >
새 보안 조치는 다음 조건을 모두 충족하는 경우에 활성화됩니다.
- 출시를 실행하는 앱은 Android 15를 타겟팅합니다.
- 작업 스택 상단의 앱은 Android 15를 타겟팅합니다.
- 표시되는 모든 활동에 새 보호 조치가 적용됩니다.
보안 조치가 사용 설정되면 현재 기기가 아닌 앱이 홈으로 돌아가 사용자가 자신의 작업을 완료할 때 마지막으로 보이는 앱의 동작을 확인할 수 있습니다.
기타 변경사항
UID 일치에 관한 제한사항 외에도 다음과 같은 다른 변경사항도 있습니다. 포함:
- 크리에이터
PendingIntent
명이 다음과 같은 방법으로 백그라운드 활동 실행을 차단하도록 변경 기본값을 참고하세요. 이렇게 하면 앱에서 실수로 악의적인 행위자가 악용할 수 있는PendingIntent
PendingIntent
발신자가 아닌 한 앱을 포그라운드로 가져오지 마세요. 허용합니다. 이 변경사항은 악성 앱이 백그라운드에서 활동을 시작하는 기능 기본적으로 앱은 생성자가 허용하지 않는 한 작업 스택을 포그라운드로 가져올 수 있음 백그라운드 활동 실행 권한이 있거나 발신자가 백그라운드 활동이 있는 경우 시작 권한이 있어야 합니다- 작업 스택의 상단 활동이 작업을 완료하는 방식을 제어합니다. 만약 상위 활동이 작업을 완료하면 Android는 이전 작업으로 돌아갑니다. 마지막 활동입니다. 또한 상위 활동이 아닌 활동이 작업을 완료하면 Android는 홈 화면으로 돌아갑니다. 끝부분을 가리지 않는 있습니다.
- 다른 앱의 임의 활동을 내 앱으로 실행하지 못하도록 방지 작업을 해야 합니다. 이 변경사항은 다른 앱에서 비롯된 것처럼 보이는 활동을 말합니다.
- 보이지 않는 창이 백그라운드 활동에 고려되지 않도록 차단 출시를 클릭합니다. 이렇게 하면 악성 앱이 백그라운드를 악용하는 것을 방지할 수 있습니다. 사용자에게 원치 않는 콘텐츠 또는 악성 콘텐츠를 표시할 수 있습니다.
더 안전한 인텐트
Android 15 introduces new optional security measures to make intents safer and more robust. These changes are aimed at preventing potential vulnerabilities and misuse of intents that can be exploited by malicious apps. There are two main improvements to the security of intents in Android 15:
- Match target intent-filters: Intents that target specific components must accurately match the target's intent-filter specifications. If you send an intent to launch another app's activity, the target intent component needs to align with the receiving activity's declared intent-filters.
- Intents must have actions: Intents without an action will no longer match any intent-filters. This means that intents used to start activities or services must have a clearly defined action.
In order to check how your app responds to these changes, use
StrictMode
in your app. To see detailed
logs about Intent
usage violations, add the following method:
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
사용자 환경 및 시스템 UI
Android 15에는 더 일관되고 직관적인 사용자 환경을 제공하기 위한 몇 가지 변경사항이 포함되어 있습니다.
창 인셋 변경사항
There are two changes related to window insets in Android 15: edge-to-edge is enforced by default, and there are also configuration changes, such as the default configuration of system bars.
더 넓은 화면 적용
Apps are edge-to-edge by default on devices running Android 15 if the app is targeting Android 15 (API level 35).
This is a breaking change that might negatively impact your app's UI. The changes affect the following UI areas:
- Gesture handle navigation bar
- Transparent by default.
- Bottom offset is disabled so content draws behind the system navigation bar unless insets are applied.
setNavigationBarColor
andR.attr#navigationBarColor
are deprecated and don't affect gesture navigation.setNavigationBarContrastEnforced
andR.attr#navigationBarContrastEnforced
continue to have no effect on gesture navigation.
- 3-button navigation
- Opacity set to 80% by default, with color possibly matching the window background.
- Bottom offset disabled so content draws behind the system navigation bar unless insets are applied.
setNavigationBarColor
andR.attr#navigationBarColor
are set to match the window background by default. The window background must be a color drawable for this default to apply. This API is deprecated but continues to affect 3-button navigation.setNavigationBarContrastEnforced
andR.attr#navigationBarContrastEnforced
is true by default, which adds an 80% opaque background across 3-button navigation.
- Status bar
- Transparent by default.
- The top offset is disabled so content draws behind the status bar unless insets are applied.
setStatusBarColor
andR.attr#statusBarColor
are deprecated and have no effect on Android 15.setStatusBarContrastEnforced
andR.attr#statusBarContrastEnforced
are deprecated but still have an effect on Android 15.
- Display cutout
layoutInDisplayCutoutMode
of non-floating windows must beLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
.SHORT_EDGES
,NEVER
, andDEFAULT
are interpreted asALWAYS
so that users don't see a black bar caused by the display cutout and appear edge-to-edge.
The following example shows an app before and after targeting Android 15 (API level 35), and before and after applying insets.
What to check if your app is already edge-to-edge
If your app is already edge-to-edge and applies insets, you are mostly unimpacted, except in the following scenarios. However, even if you think you aren't impacted, we recommend you test your app.
- You have a non-floating window, such as an
Activity
that usesSHORT_EDGES
,NEVER
orDEFAULT
instead ofLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
. If your app crashes on launch, this might be due to your splashscreen. You can either upgrade the core splashscreen dependency to 1.2.0-alpha01 or later or setwindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
. - There might be lower-traffic screens with occluded UI. Verify these
less-visited screens don't have occluded UI. Lower-traffic screens include:
- Onboarding or sign-in screens
- Settings pages
What to check if your app is not already edge-to-edge
If your app is not already edge-to-edge, you are most likely impacted. In addition to the scenarios for apps that are already edge-to-edge, you should consider the following:
- If your app uses Material 3 Components (
androidx.compose.material3
) in compose, such asTopAppBar
,BottomAppBar
, andNavigationBar
, these components are likely not impacted because they automatically handle insets. - If your app is using Material 2 Components (
androidx.compose.material
) in Compose, these components don't automatically handle insets. However, you can get access to the insets and apply them manually. In androidx.compose.material 1.6.0 and later, use thewindowInsets
parameter to apply the insets manually forBottomAppBar
,TopAppBar
,BottomNavigation
, andNavigationRail
. Likewise, use thecontentWindowInsets
parameter forScaffold
. - If your app uses views and Material Components
(
com.google.android.material
), most views-based Material Components such asBottomNavigationView
,BottomAppBar
,NavigationRailView
, orNavigationView
, handle insets and require no additional work. However, you need to addandroid:fitsSystemWindows="true"
if usingAppBarLayout
. - For custom composables, apply the insets manually as padding. If your
content is within a
Scaffold
, you can consume insets using theScaffold
padding values. Otherwise, apply padding using one of theWindowInsets
. - If your app is using views and
BottomSheet
,SideSheet
or custom containers, apply padding usingViewCompat.setOnApplyWindowInsetsListener
. ForRecyclerView
, apply padding using this listener and also addclipToPadding="false"
.
What to check if your app must offer custom background protection
If your app must offer custom background protection to 3-button navigation or
the status bar, your app should place a composable or view behind the system bar
using WindowInsets.Type#tappableElement()
to get the 3-button
navigation bar height or WindowInsets.Type#statusBars
.
Additional edge-to-edge resources
See the Edge to Edge Views and Edge to Edge Compose guides for additional considerations on applying insets.
Deprecated APIs
The following APIs are deprecated but not disabled:
R.attr#enforceStatusBarContrast
R.attr#navigationBarColor
(for 3 button navigation, with 80% alpha)Window#isStatusBarContrastEnforced
Window#setNavigationBarColor
(for 3 button navigation, with 80% alpha)Window#setStatusBarContrastEnforced
The following APIs are deprecated and disabled:
R.attr#navigationBarColor
(for gesture navigation)R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#setDecorFitsSystemWindows
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#setNavigationBarColor
(for gesture navigation)Window#setNavigationBarDividerColor
Window#setStatusBarColor
안정적인 구성
앱이 Android 15 (API 수준 35) 이상을 타겟팅하면 Configuration
에서 더 이상 시스템 표시줄을 제외하지 않습니다. 레이아웃 계산에 Configuration
클래스의 화면 크기를 사용하는 경우 필요에 따라 적절한 ViewGroup
, WindowInsets
또는 WindowMetricsCalculator
과 같은 더 나은 대안으로 대체해야 합니다.
Configuration
는 API 1부터 사용할 수 있습니다. 일반적으로 Activity.onConfigurationChanged
에서 가져옵니다. 창 밀도, 방향, 크기와 같은 정보를 제공합니다. Configuration
에서 반환된 창 크기의 중요한 특징 중 하나는 이전에 시스템 표시줄이 제외되었다는 점입니다.
구성 크기는 일반적으로 /res/layout-h500dp
와 같은 리소스 선택에 사용되며 여전히 유효한 사용 사례입니다. 그러나 레이아웃 계산에 이 방식을 사용하는 것은 항상 권장되지 않습니다. 이 경우 지금 바로 벗어나야 합니다. Configuration
사용을 사용 사례에 따라 더 적합한 것으로 대체해야 합니다.
레이아웃을 계산하는 데 사용하는 경우 CoordinatorLayout
또는 ConstraintLayout
와 같은 적절한 ViewGroup
를 사용하세요. 시스템 탐색 메뉴의 높이를 결정하는 데 사용한다면 WindowInsets
을 사용하세요. 앱 창의 현재 크기를 확인하려면 computeCurrentWindowMetrics
를 사용하세요.
다음 목록은 이 변경사항의 영향을 받는 필드를 설명합니다.
Configuration.screenWidthDp
및screenHeightDp
크기에서 더 이상 시스템 표시줄이 제외되지 않습니다.Configuration.smallestScreenWidthDp
는screenWidthDp
및screenHeightDp
의 변경사항의 간접적인 영향을 받습니다.Configuration.orientation
은 정사각형에 가까운 기기에서screenWidthDp
및screenHeightDp
의 변경에 간접적으로 영향을 받습니다.Display.getSize(Point)
는Configuration
의 변경사항의 간접적인 영향을 받습니다. 이 기능은 API 수준 30부터 지원 중단되었습니다.Display.getMetrics()
는 API 수준 33부터 이미 이렇게 작동했습니다.
우아한 텍스트 높이 속성의 기본값은 true입니다.
For apps targeting Android 15 (API level 35), the
elegantTextHeight
TextView
attribute
becomes true
by default, replacing the compact font used by default with some
scripts that have large vertical metrics with one that is much more readable.
The compact font was introduced to prevent breaking layouts; Android 13 (API
level 33) prevents many of these breakages by allowing the text layout to
stretch the vertical height utilizing the fallbackLineSpacing
attribute.
In Android 15, the compact font still remains in the system, so your app can set
elegantTextHeight
to false
to get the same behavior as before, but it is
unlikely to be supported in upcoming releases. So, if your app supports the
following scripts: Arabic, Lao, Myanmar, Tamil, Gujarati, Kannada, Malayalam,
Odia, Telugu or Thai, test your app by setting elegantTextHeight
to true
.
복잡한 문자 도형의 TextView 너비 변경
이전 버전의 Android에서는 복잡한 도형을 사용하는 일부 필기체 글꼴이나 언어에서 이전 또는 다음 문자의 영역에 문자를 그릴 수 있습니다.
이러한 문자가 시작 또는 끝 위치에서 잘리는 경우도 있었습니다.
Android 15부터 TextView
는 이러한 문자를 위한 공간을 그리기에 충분한 너비를 할당하고 앱이 왼쪽에 추가 패딩을 요청하여 클리핑을 방지할 수 있도록 합니다.
이 변경사항은 TextView
가 너비를 결정하는 방식에 영향을 미치므로 앱이 Android 15 (API 수준 35) 이상을 타겟팅하는 경우 TextView
는 기본적으로 더 많은 너비를 할당합니다. TextView
에서 setUseBoundsForWidth
API를 호출하여 이 동작을 사용 설정 또는 사용 중지할 수 있습니다.
왼쪽 패딩을 추가하면 기존 레이아웃이 정렬되지 않을 수 있으므로 Android 15 이상을 타겟팅하는 앱에서도 기본적으로 패딩이 추가되지 않습니다.
하지만 setShiftDrawingOffsetForStartOverhang
를 호출하여 추가 패딩을 추가하여 잘림을 방지할 수 있습니다.
다음 예는 이러한 변경사항이 일부 글꼴 및 언어의 텍스트 레이아웃을 개선하는 방법을 보여줍니다.
EditText의 언어 인식 기본 행 높이
In previous versions of Android, the text layout stretched the height of the
text to meet the line height of the font that matched the current locale. For
example, if the content was in Japanese, because the line height of the Japanese
font is slightly larger than the one of a Latin font, the height of the text
became slightly larger. However, despite these differences in line heights, the
EditText
element was sized uniformly, regardless
of the locale being used, as illustrated in the following image:
For apps targeting Android 15 (API level 35), a minimum line height is now
reserved for EditText
to match the reference font for the specified Locale, as
shown in the following image:
If needed, your app can restore the previous behavior by specifying the
useLocalePreferredLineHeightForMinimum
attribute
to false
, and your app can set custom minimum vertical metrics using the
setMinimumFontMetrics
API in Kotlin and Java.
카메라 및 미디어
Android 15에서는 Android 15 이상을 타겟팅하는 앱의 카메라 및 미디어 동작을 다음과 같이 변경합니다.
오디오 포커스 요청 제한사항
Apps that target Android 15 (API level 35) must be the top app or running a
foreground service in order to request audio focus. If an app
attempts to request focus when it does not meet one of these requirements, the
call returns AUDIOFOCUS_REQUEST_FAILED
.
You can learn more about audio focus at Manage audio focus.
업데이트된 비 SDK 제한사항
Android 15 includes updated lists of restricted non-SDK interfaces based on collaboration with Android developers and the latest internal testing. Whenever possible, we make sure that public alternatives are available before we restrict non-SDK interfaces.
If your app does not target Android 15, some of these changes might not immediately affect you. However, while it's possible for your app to access some non-SDK interfaces depending on your app's target API level, using any non-SDK method or field always carries a high risk of breaking your app.
If you are unsure if your app uses non-SDK interfaces, you can test your app to find out. If your app relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives. Nevertheless, we understand that some apps have valid use cases for using non-SDK interfaces. If you can't find an alternative to using a non-SDK interface for a feature in your app, you should request a new public API.
To learn more about the changes in this release of Android, see Updates to non-SDK interface restrictions in Android 15. To learn more about non-SDK interfaces generally, see Restrictions on non-SDK interfaces.