diff options
339 files changed, 6401 insertions, 3489 deletions
diff --git a/Android.bp b/Android.bp index 995fe3e2465e..1ee7405b42ab 100644 --- a/Android.bp +++ b/Android.bp @@ -209,6 +209,7 @@ java_defaults { "core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl", "core/java/android/hardware/usb/IUsbManager.aidl", "core/java/android/hardware/usb/IUsbSerialReader.aidl", + "core/java/android/net/ICaptivePortal.aidl", "core/java/android/net/IConnectivityManager.aidl", "core/java/android/hardware/ISensorPrivacyListener.aidl", "core/java/android/hardware/ISensorPrivacyManager.aidl", @@ -772,7 +773,7 @@ java_defaults { "android.hardware.vibrator-V1.2-java", "android.hardware.vibrator-V1.3-java", "android.hardware.wifi-V1.0-java-constants", - "networkstack-aidl-interfaces-java", + "networkstack-aidl-framework-java", "netd_aidl_parcelables-java", "devicepolicyprotosnano", ], @@ -893,10 +894,8 @@ aidl_interface { srcs: [ "core/java/android/net/ApfCapabilitiesParcelable.aidl", "core/java/android/net/DhcpResultsParcelable.aidl", - "core/java/android/net/ICaptivePortal.aidl", "core/java/android/net/INetworkMonitor.aidl", "core/java/android/net/INetworkMonitorCallbacks.aidl", - "core/java/android/net/IIpMemoryStore.aidl", "core/java/android/net/INetworkStackConnector.aidl", "core/java/android/net/INetworkStackStatusCallback.aidl", "core/java/android/net/InitialConfigurationParcelable.aidl", @@ -915,6 +914,16 @@ aidl_interface { "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl", "core/java/android/net/ip/IIpClient.aidl", "core/java/android/net/ip/IIpClientCallbacks.aidl", + ], + api_dir: "aidl/networkstack", +} + +aidl_interface { + name: "networkstack-aidl-framework", + local_include_dir: "core/java", + srcs: [ + "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl", + "core/java/android/net/IIpMemoryStore.aidl", "core/java/android/net/ipmemorystore/**/*.aidl", ], api_dir: "aidl/networkstack", diff --git a/api/current.txt b/api/current.txt index 15c4fdfed178..fe86cbe48375 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2222,6 +2222,7 @@ package android { field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053 field public static final int Theme = 16973829; // 0x1030005 field public static final int ThemeOverlay = 16974407; // 0x1030247 + field public static final int ThemeOverlay_DeviceDefault_Accent_DayNight = 16974564; // 0x10302e4 field public static final int ThemeOverlay_Material = 16974408; // 0x1030248 field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249 field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b @@ -2233,6 +2234,7 @@ package android { field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009 field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a field public static final int Theme_DeviceDefault = 16974120; // 0x1030128 + field public static final int Theme_DeviceDefault_DayNight = 16974563; // 0x10302e3 field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136 field public static final int Theme_DeviceDefault_DialogWhenLarge_NoActionBar = 16974135; // 0x1030137 @@ -13064,6 +13066,10 @@ package android.database.sqlite { method public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String, String); method @Deprecated public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String[], String, String); method public int delete(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable String, @Nullable String[]); + method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); + method public boolean getDistinct(); + method public java.util.Map<java.lang.String,java.lang.String> getProjectionMap(); + method public boolean getStrict(); method public String getTables(); method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String); method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String); @@ -23408,7 +23414,7 @@ package android.media { method @NonNull public android.media.AudioPresentation.Builder setProgramId(int); } - public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting { + public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection { ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException; method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method @Deprecated public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler); @@ -23443,6 +23449,8 @@ package android.media { method public void release(); method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method @Deprecated public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener); + method public boolean setMicrophoneDirection(int); + method public boolean setMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float); method public int setNotificationMarkerPosition(int); method public int setPositionNotificationPeriod(int); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); @@ -26092,6 +26100,15 @@ package android.media { field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN; } + public interface MicrophoneDirection { + method public boolean setMicrophoneDirection(int); + method public boolean setMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float); + field public static final int MIC_DIRECTION_BACK = 2; // 0x2 + field public static final int MIC_DIRECTION_EXTERNAL = 3; // 0x3 + field public static final int MIC_DIRECTION_FRONT = 1; // 0x1 + field public static final int MIC_DIRECTION_UNSPECIFIED = 0; // 0x0 + } + public final class MicrophoneInfo { method @NonNull public String getAddress(); method public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getChannelMapping(); @@ -41588,6 +41605,7 @@ package android.service.notification { field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR; field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions"; field public static final String KEY_IMPORTANCE = "key_importance"; + field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria"; field public static final String KEY_TEXT_REPLIES = "key_text_replies"; field public static final String KEY_USER_SENTIMENT = "key_user_sentiment"; } @@ -41645,12 +41663,14 @@ package android.service.notification { method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int); method public final android.os.IBinder onBind(android.content.Intent); method public void onNotificationDirectReplied(@NonNull String); - method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); + method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean); method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int); + method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, String); method public void onNotificationsSeen(java.util.List<java.lang.String>); method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int); + method public final void unsnoozeNotification(String); field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; field public static final int SOURCE_FROM_APP = 0; // 0x0 field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1 @@ -49247,6 +49267,7 @@ package android.view { ctor public ContextThemeWrapper(android.content.Context, android.content.res.Resources.Theme); method public void applyOverrideConfiguration(android.content.res.Configuration); method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean); + method public void setTheme(@Nullable android.content.res.Resources.Theme); } public final class Display { diff --git a/api/system-current.txt b/api/system-current.txt index 357f6a4a3607..142068cdb48f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -309,6 +309,7 @@ package android.app { method @Deprecated @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, String, int[]); method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...); method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]); + method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int); method public static int opToDefaultMode(@NonNull String); method @Nullable public static String opToPermission(@NonNull String); method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int); @@ -3409,13 +3410,13 @@ package android.media { public final class AudioFocusInfo implements android.os.Parcelable { method public int describeContents(); - method public android.media.AudioAttributes getAttributes(); - method public String getClientId(); + method @NonNull public android.media.AudioAttributes getAttributes(); + method @NonNull public String getClientId(); method public int getClientUid(); method public int getFlags(); method public int getGainRequest(); method public int getLossReceived(); - method public String getPackageName(); + method @NonNull public String getPackageName(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR; } @@ -3475,7 +3476,7 @@ package android.media { field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff } - public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting { + public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection { ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException; } @@ -3933,7 +3934,7 @@ package android.net { method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean); - method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.os.Bundle); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.net.Network, android.os.Bundle); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); @@ -6350,7 +6351,8 @@ package android.service.contentcapture { method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); - method public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method @Deprecated public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; } @@ -6521,6 +6523,15 @@ package android.service.euicc { package android.service.notification { + public final class Adjustment implements android.os.Parcelable { + ctor protected Adjustment(android.os.Parcel); + field public static final String KEY_PEOPLE = "key_people"; + } + + public final class NotificationStats implements android.os.Parcelable { + ctor protected NotificationStats(android.os.Parcel); + } + public final class SnoozeCriterion implements android.os.Parcelable { ctor public SnoozeCriterion(String, CharSequence, CharSequence); ctor protected SnoozeCriterion(android.os.Parcel); @@ -9307,7 +9318,8 @@ package android.view.accessibility { package android.view.autofill { public final class AutofillManager { - method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method @Deprecated public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method public void setAugmentedAutofillWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); } } diff --git a/api/test-current.txt b/api/test-current.txt index 47d38a7d2f3a..16098c1a80fa 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -516,13 +516,20 @@ package android.content.pm { method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); method @Nullable public abstract String[] getNamesForUids(int[]); method public abstract String getPermissionControllerPackageName(); + method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle); method @NonNull public abstract String getServicesSystemSharedLibraryPackageName(); method @NonNull public abstract String getSharedSystemSharedLibraryPackageName(); method public String getWellbeingPackageName(); method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle); field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage"; field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption"; + field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40 + field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 + field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80 + field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2 + field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000 field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services"; @@ -802,6 +809,7 @@ package android.location { public class LocationManager { method public String[] getBackgroundThrottlingWhitelist(); + method public String[] getIgnoreSettingsWhitelist(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(android.location.LocationRequest, android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, android.os.UserHandle); @@ -936,7 +944,7 @@ package android.net { } public class ConnectivityManager { - method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.os.Bundle); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.net.Network, android.os.Bundle); field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; } @@ -2103,7 +2111,8 @@ package android.service.contentcapture { method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); - method public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method @Deprecated public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; } @@ -2692,7 +2701,8 @@ package android.view.autofill { } public final class AutofillManager { - method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method @Deprecated public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>); + method public void setAugmentedAutofillWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes"; field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0 field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1 @@ -2738,7 +2748,15 @@ package android.view.contentcapture { public final class ContentCaptureManager { method public boolean isContentCaptureFeatureEnabled(); method public void setContentCaptureFeatureEnabled(boolean); + field public static final String DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY = "idle_flush_frequency"; + field public static final String DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL = "logging_level"; + field public static final String DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE = "log_history_size"; + field public static final String DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE = "max_buffer_size"; field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled"; + field public static final String DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY = "text_change_flush_frequency"; + field public static final int LOGGING_LEVEL_DEBUG = 1; // 0x1 + field public static final int LOGGING_LEVEL_OFF = 0; // 0x0 + field public static final int LOGGING_LEVEL_VERBOSE = 2; // 0x2 } public final class ViewNode extends android.app.assist.AssistStructure.ViewNode { diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 46917e4f6062..a6c7cae9bdb6 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -110,13 +110,30 @@ BootAnimation::BootAnimation(sp<Callbacks> callbacks) } else { mShuttingDown = true; } + ALOGD("%sAnimationStartTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", + elapsedRealtime()); +} + +BootAnimation::~BootAnimation() { + if (mAnimation != nullptr) { + releaseAnimation(mAnimation); + mAnimation = nullptr; + } + ALOGD("%sAnimationStopTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", + elapsedRealtime()); } void BootAnimation::onFirstRef() { status_t err = mSession->linkToComposerDeath(this); SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err)); if (err == NO_ERROR) { - run("BootAnimation", PRIORITY_DISPLAY); + // Load the animation content -- this can be slow (eg 200ms) + // called before waitForSurfaceFlinger() in main() to avoid wait + ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms", + mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); + preloadAnimation(); + ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms", + mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); } } @@ -306,6 +323,20 @@ status_t BootAnimation::readyToRun() { mFlingerSurface = s; mTargetInset = -1; + return NO_ERROR; +} + +bool BootAnimation::preloadAnimation() { + findBootAnimationFile(); + if (!mZipFileName.isEmpty()) { + mAnimation = loadAnimation(mZipFileName); + return (mAnimation != nullptr); + } + + return false; +} + +void BootAnimation::findBootAnimationFile() { // If the device has encryption turned on or is in process // of being encrypted we show the encrypted boot animation. char decrypt[PROPERTY_VALUE_MAX]; @@ -320,7 +351,7 @@ status_t BootAnimation::readyToRun() { for (const char* f : encryptedBootFiles) { if (access(f, R_OK) == 0) { mZipFileName = f; - return NO_ERROR; + return; } } } @@ -332,10 +363,9 @@ status_t BootAnimation::readyToRun() { for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) { if (access(f, R_OK) == 0) { mZipFileName = f; - return NO_ERROR; + return; } } - return NO_ERROR; } bool BootAnimation::threadLoop() @@ -790,8 +820,6 @@ bool BootAnimation::preloadZip(Animation& animation) } } - mCallbacks->init(animation.parts); - zip->endIteration(cookie); return true; @@ -799,13 +827,25 @@ bool BootAnimation::preloadZip(Animation& animation) bool BootAnimation::movie() { - Animation* animation = loadAnimation(mZipFileName); - if (animation == NULL) + if (mAnimation == nullptr) { + mAnimation = loadAnimation(mZipFileName); + } + + if (mAnimation == nullptr) return false; + // mCallbacks->init() may get called recursively, + // this loop is needed to get the same results + for (const Animation::Part& part : mAnimation->parts) { + if (part.animation != nullptr) { + mCallbacks->init(part.animation->parts); + } + } + mCallbacks->init(mAnimation->parts); + bool anyPartHasClock = false; - for (size_t i=0; i < animation->parts.size(); i++) { - if(validClock(animation->parts[i])) { + for (size_t i=0; i < mAnimation->parts.size(); i++) { + if(validClock(mAnimation->parts[i])) { anyPartHasClock = true; break; } @@ -846,7 +886,7 @@ bool BootAnimation::movie() bool clockFontInitialized = false; if (mClockEnabled) { clockFontInitialized = - (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR); + (initFont(&mAnimation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR); mClockEnabled = clockFontInitialized; } @@ -855,7 +895,7 @@ bool BootAnimation::movie() mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL); } - playAnimation(*animation); + playAnimation(*mAnimation); if (mTimeCheckThread != nullptr) { mTimeCheckThread->requestExit(); @@ -863,10 +903,11 @@ bool BootAnimation::movie() } if (clockFontInitialized) { - glDeleteTextures(1, &animation->clockFont.texture.name); + glDeleteTextures(1, &mAnimation->clockFont.texture.name); } - releaseAnimation(animation); + releaseAnimation(mAnimation); + mAnimation = nullptr; return false; } diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 19616cb790c7..dc19fb09ef1d 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -115,6 +115,7 @@ public: }; explicit BootAnimation(sp<Callbacks> callbacks); + virtual ~BootAnimation(); sp<SurfaceComposerClient> session() const; @@ -155,6 +156,8 @@ private: void releaseAnimation(Animation*) const; bool parseAnimationDesc(Animation&); bool preloadZip(Animation &animation); + void findBootAnimationFile(); + bool preloadAnimation(); void checkExit(); @@ -182,6 +185,7 @@ private: SortedVector<String8> mLoadedFiles; sp<TimeCheckThread> mTimeCheckThread = nullptr; sp<Callbacks> mCallbacks; + Animation* mAnimation = nullptr; }; // --------------------------------------------------------------------------- diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index a52a5e92a840..6c7b3e51ff8d 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -44,14 +44,16 @@ int main() sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool(); + // create the boot animation object (may take up to 200ms for 2MB zip) + sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks()); + waitForSurfaceFlinger(); - // create the boot animation object - sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks()); + boot->run("BootAnimation", PRIORITY_DISPLAY); + ALOGV("Boot animation set up. Joining pool."); IPCThreadState::self()->joinThreadPool(); } - ALOGV("Boot animation exit"); return 0; } diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp index 80ed80776829..13f5c8ae5fd8 100644 --- a/cmds/statsd/src/FieldValue.cpp +++ b/cmds/statsd/src/FieldValue.cpp @@ -19,6 +19,7 @@ #include "FieldValue.h" #include "HashableDimensionKey.h" #include "math.h" +#include "statslog.h" namespace android { namespace os { @@ -122,6 +123,24 @@ bool isAttributionUidField(const FieldValue& value) { return false; } +int32_t getUidIfExists(const FieldValue& value) { + bool isUid = false; + // the field is uid field if the field is the uid field in attribution node or marked as + // is_uid in atoms.proto + if (isAttributionUidField(value)) { + isUid = true; + } else { + auto it = android::util::AtomsInfo::kAtomsWithUidField.find(value.mField.getTag()); + if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { + int uidField = it->second; // uidField is the field number in proto + isUid = value.mField.getDepth() == 0 && value.mField.getPosAtDepth(0) == uidField && + value.mValue.getType() == INT; + } + } + + return isUid ? value.mValue.int_value : -1; +} + bool isAttributionUidField(const Field& field, const Value& value) { int f = field.getField() & 0xff007f; if (f == 0x10001 && value.getType() == INT) { diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h index a5d00ac4e72b..6729e052b5ee 100644 --- a/cmds/statsd/src/FieldValue.h +++ b/cmds/statsd/src/FieldValue.h @@ -386,6 +386,9 @@ bool HasPositionALL(const FieldMatcher& matcher); bool isAttributionUidField(const FieldValue& value); +/* returns uid if the field is uid field, or -1 if the field is not a uid field */ +int getUidIfExists(const FieldValue& value); + void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output); bool isAttributionUidField(const Field& field, const Value& value); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index fb603b9ce163..c542b6215c88 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -159,7 +159,7 @@ StatsService::StatsService(const sp<Looper>& handlerLooper) } })) { - mUidMap = new UidMap(); + mUidMap = UidMap::getInstance(); mPullerManager = new StatsPullerManager(); StatsPuller::SetUidMap(mUidMap); mConfigManager = new ConfigManager(); diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp index 8d7369935ea4..019a9f7e5f9a 100644 --- a/cmds/statsd/src/anomaly/AlarmTracker.cpp +++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp @@ -78,8 +78,8 @@ void AlarmTracker::informAlarmsFired( } if (!mSubscriptions.empty()) { VLOG("AlarmTracker triggers the subscribers."); - triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey, - mSubscriptions); + triggerSubscribers(mAlarmConfig.id(), 0 /*metricId N/A*/, DEFAULT_METRIC_DIMENSION_KEY, + 0 /* metricValue N/A */, mConfigKey, mSubscriptions); } firedAlarms.erase(mInternalAlarm); mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp index ee111cddcfd7..d1dcb5df7838 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp @@ -207,7 +207,8 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt(); } -void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key) { +void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, int64_t metricId, + const MetricDimensionKey& key, int64_t metricValue) { // TODO(b/110563466): Why receive timestamp? RefractoryPeriod should always be based on // real time right now. if (isInRefractoryPeriod(timestampNs, key)) { @@ -225,7 +226,7 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDime if (!mSubscriptions.empty()) { ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.", mAlert.id(), key.toString().c_str()); - informSubscribers(key); + informSubscribers(key, metricId, metricValue); } else { ALOGI("An anomaly has occurred! (But no subscriber for that alert.)"); } @@ -238,11 +239,11 @@ void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, const MetricDime } void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs, - const int64_t& currBucketNum, + const int64_t& currBucketNum, int64_t metricId, const MetricDimensionKey& key, const int64_t& currentBucketValue) { if (detectAnomaly(currBucketNum, key, currentBucketValue)) { - declareAnomaly(timestampNs, key); + declareAnomaly(timestampNs, metricId, key, currentBucketValue); } } @@ -255,8 +256,9 @@ bool AnomalyTracker::isInRefractoryPeriod(const int64_t& timestampNs, return false; } -void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) { - triggerSubscribers(mAlert.id(), key, mConfigKey, mSubscriptions); +void AnomalyTracker::informSubscribers(const MetricDimensionKey& key, int64_t metric_id, + int64_t metricValue) { + triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions); } } // namespace statsd diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h index 927e2df1b53a..e9414735b82b 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.h +++ b/cmds/statsd/src/anomaly/AnomalyTracker.h @@ -67,14 +67,16 @@ public: const int64_t& currentBucketValue); // Informs incidentd about the detected alert. - void declareAnomaly(const int64_t& timestampNs, const MetricDimensionKey& key); + void declareAnomaly(const int64_t& timestampNs, int64_t metricId, const MetricDimensionKey& key, + int64_t metricValue); // Detects if, based on past buckets plus the new currentBucketValue (which generally // represents the partially-filled current bucket), an anomaly has happened, and if so, // declares an anomaly and informs relevant subscribers. // Also advances to currBucketNum-1. void detectAndDeclareAnomaly(const int64_t& timestampNs, const int64_t& currBucketNum, - const MetricDimensionKey& key, const int64_t& currentBucketValue); + int64_t metricId, const MetricDimensionKey& key, + const int64_t& currentBucketValue); // Init the AlarmMonitor which is shared across anomaly trackers. virtual void setAlarmMonitor(const sp<AlarmMonitor>& alarmMonitor) { @@ -176,7 +178,7 @@ protected: virtual void resetStorage(); // Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred. - void informSubscribers(const MetricDimensionKey& key); + void informSubscribers(const MetricDimensionKey& key, int64_t metricId, int64_t metricValue); FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets); FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets); diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp index 3acfd171848e..2b56810170e5 100644 --- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp @@ -65,7 +65,9 @@ void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey, // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now. if (itr->second != nullptr && timestampNs >= (int64_t)NS_PER_SEC * itr->second->timestampSec) { - declareAnomaly(timestampNs, dimensionKey); + declareAnomaly(timestampNs, mAlert.metric_id(), dimensionKey, + mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - + itr->second->timestampSec); } if (mAlarmMonitor != nullptr) { mAlarmMonitor->remove(itr->second); @@ -100,7 +102,9 @@ void DurationAnomalyTracker::informAlarmsFired(const int64_t& timestampNs, // Now declare each of these alarms to have fired. for (const auto& kv : matchedAlarms) { - declareAnomaly(timestampNs, kv.first); + declareAnomaly( + timestampNs, mAlert.metric_id(), kv.first, + mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - kv.second->timestampSec); mAlarms.erase(kv.first); firedAlarms.erase(kv.second); // No one else can also own it, so we're done with it. } diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp index 6b46b8b3b900..548a6869436d 100644 --- a/cmds/statsd/src/anomaly/subscriber_util.cpp +++ b/cmds/statsd/src/anomaly/subscriber_util.cpp @@ -30,9 +30,8 @@ namespace android { namespace os { namespace statsd { -void triggerSubscribers(const int64_t rule_id, - const MetricDimensionKey& dimensionKey, - const ConfigKey& configKey, +void triggerSubscribers(int64_t ruleId, int64_t metricId, const MetricDimensionKey& dimensionKey, + int64_t metricValue, const ConfigKey& configKey, const std::vector<Subscription>& subscriptions) { VLOG("informSubscribers called."); if (subscriptions.empty()) { @@ -50,13 +49,14 @@ void triggerSubscribers(const int64_t rule_id, } switch (subscription.subscriber_information_case()) { case Subscription::SubscriberInformationCase::kIncidentdDetails: - if (!GenerateIncidentReport(subscription.incidentd_details(), rule_id, configKey)) { + if (!GenerateIncidentReport(subscription.incidentd_details(), ruleId, metricId, + dimensionKey, metricValue, configKey)) { ALOGW("Failed to generate incident report."); } break; case Subscription::SubscriberInformationCase::kPerfettoDetails: if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(), - subscription.id(), rule_id, configKey)) { + subscription.id(), ruleId, configKey)) { ALOGW("Failed to generate perfetto traces."); } break; @@ -66,7 +66,7 @@ void triggerSubscribers(const int64_t rule_id, break; case Subscription::SubscriberInformationCase::kPerfprofdDetails: if (!CollectPerfprofdTraceAndUploadToDropbox(subscription.perfprofd_details(), - rule_id, configKey)) { + ruleId, configKey)) { ALOGW("Failed to generate perfprofd traces."); } break; @@ -76,7 +76,6 @@ void triggerSubscribers(const int64_t rule_id, } } - } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/anomaly/subscriber_util.h b/cmds/statsd/src/anomaly/subscriber_util.h index dba8981a72aa..1df3c8991f94 100644 --- a/cmds/statsd/src/anomaly/subscriber_util.h +++ b/cmds/statsd/src/anomaly/subscriber_util.h @@ -24,10 +24,9 @@ namespace android { namespace os { namespace statsd { -void triggerSubscribers(const int64_t rule_id, - const MetricDimensionKey& dimensionKey, - const ConfigKey& configKey, - const std::vector<Subscription>& subscriptions); +void triggerSubscribers(const int64_t ruleId, const int64_t metricId, + const MetricDimensionKey& dimensionKey, int64_t metricValue, + const ConfigKey& configKey, const std::vector<Subscription>& subscriptions); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c707d8f4c35a..d7ab6e5f89bb 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -303,6 +303,8 @@ message Atom { RoleHolder role_holder = 10049; DangerousPermissionState dangerous_permission_state = 10050; TrainInfo train_info = 10051; + TimeZoneDataInfo time_zone_data_info = 10052; + SDCardInfo sdcard_info = 10053; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -3262,6 +3264,28 @@ message BatteryCycleCount { optional int32 cycle_count = 1; } +/** + * Logs that an SD card is mounted and information about it, its type (public or private) and the + * size in bytes. + * Pulled from: + * StatsCompanionService + */ + +message SDCardInfo { + + enum Type { + UNKNOWN = 0; + TYPE_PUBLIC = 1; + TYPE_PRIVATE = 2; + OTHERS = 3; + } + + // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal. + optional Type type = 1; + // Total size of the sd card in bytes. + optional int64 size_bytes = 2; +} + /* * Logs when a connection becomes available and lost. * Logged in StatsCompanionService.java @@ -5596,3 +5620,11 @@ message AssistGestureProgressReported { // [0,100] progress for the assist gesture. optional int32 progress = 1; } + +/* + * Information about the time zone data on a device. + */ +message TimeZoneDataInfo { + // A version identifier for the data set on device. e.g. "2018i" + optional string tzdb_version = 1; +} diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 98f810fd9a2c..1513834b6724 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -234,6 +234,12 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {.puller = new StatsCompanionServicePuller(android::util::DANGEROUS_PERMISSION_STATE)}}, // TrainInfo. {android::util::TRAIN_INFO, {.puller = new TrainInfoPuller()}}, + // TimeZoneDataInfo. + {android::util::TIME_ZONE_DATA_INFO, + {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}}, + // SDCardInfo + {android::util::SDCARD_INFO, + {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 5707de544648..e84f88d407d3 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -303,7 +303,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked( if (prev != mCurrentFullCounters->end()) { countWholeBucket += prev->second; } - tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, + tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey, countWholeBucket); } diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index 837d532f7e09..63017936b1db 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -485,8 +485,8 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked( gaugeVal = value.long_value; } for (auto& tracker : mAnomalyTrackers) { - tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, - gaugeVal); + tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, + eventKey, gaugeVal); } } } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index bc7c8727284f..3cf378d7d7ce 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -697,8 +697,8 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn wholeBucketVal += prev->second; } for (auto& tracker : mAnomalyTrackers) { - tracker->detectAndDeclareAnomaly( - eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal); + tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey, + wholeBucketVal); } } } diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h index ccb1d4359e89..081e61ed21fa 100644 --- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h @@ -155,8 +155,8 @@ protected: const int64_t& currentBucketValue) { for (auto& anomalyTracker : mAnomalyTrackers) { if (anomalyTracker != nullptr) { - anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mEventKey, - currentBucketValue); + anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mTrackerId, + mEventKey, currentBucketValue); } } } diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp index 5cf012638dce..d4b57dd68134 100644 --- a/cmds/statsd/src/packages/UidMap.cpp +++ b/cmds/statsd/src/packages/UidMap.cpp @@ -73,6 +73,11 @@ UidMap::UidMap() : mBytesUsed(0) {} UidMap::~UidMap() {} +sp<UidMap> UidMap::getInstance() { + static sp<UidMap> sInstance = new UidMap(); + return sInstance; +} + bool UidMap::hasApp(int uid, const string& packageName) const { lock_guard<mutex> lock(mMutex); @@ -336,6 +341,61 @@ size_t UidMap::getBytesUsed() const { return mBytesUsed; } +void UidMap::writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings, + bool includeInstaller, const std::set<int32_t>& interestingUids, + std::set<string>* str_set, ProtoOutputStream* proto) { + lock_guard<mutex> lock(mMutex); + + writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller, interestingUids, + str_set, proto); +} + +void UidMap::writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings, + bool includeInstaller, + const std::set<int32_t>& interestingUids, + std::set<string>* str_set, ProtoOutputStream* proto) { + proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp); + for (const auto& kv : mMap) { + if (!interestingUids.empty() && + interestingUids.find(kv.first.first) == interestingUids.end()) { + continue; + } + uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_SNAPSHOT_PACKAGE_INFO); + if (str_set != nullptr) { + str_set->insert(kv.first.second); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH, + (long long)Hash64(kv.first.second)); + if (includeVersionStrings) { + str_set->insert(kv.second.versionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH, + (long long)Hash64(kv.second.versionString)); + } + if (includeInstaller) { + str_set->insert(kv.second.installer); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH, + (long long)Hash64(kv.second.installer)); + } + } else { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second); + if (includeVersionStrings) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING, + kv.second.versionString); + } + if (includeInstaller) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER, + kv.second.installer); + } + } + + proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, + (long long)kv.second.versionCode); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first); + proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted); + proto->end(token); + } +} + void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set, bool includeVersionStrings, bool includeInstaller, ProtoOutputStream* proto) { @@ -381,43 +441,9 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::s // Write snapshot from current uid map state. uint64_t snapshotsToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS); - proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp); - for (const auto& kv : mMap) { - uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | - FIELD_ID_SNAPSHOT_PACKAGE_INFO); - - if (str_set != nullptr) { - str_set->insert(kv.first.second); - proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH, - (long long)Hash64(kv.first.second)); - if (includeVersionStrings) { - str_set->insert(kv.second.versionString); - proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH, - (long long)Hash64(kv.second.versionString)); - } - if (includeInstaller) { - str_set->insert(kv.second.installer); - proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH, - (long long)Hash64(kv.second.installer)); - } - } else { - proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second); - if (includeVersionStrings) { - proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING, - kv.second.versionString); - } - if (includeInstaller) { - proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER, - kv.second.installer); - } - } - - proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, - (long long)kv.second.versionCode); - proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first); - proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted); - proto->end(token); - } + writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller, + std::set<int32_t>() /*empty uid set means including every uid*/, + str_set, proto); proto->end(snapshotsToken); int64_t prevMin = getMinimumTimestampNs(); diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h index 75ff507ef09a..a7c5fb27375c 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -91,6 +91,8 @@ public: UidMap(); ~UidMap(); static const std::map<std::string, uint32_t> sAidToUidMapping; + + static sp<UidMap> getInstance(); /* * All three inputs must be the same size, and the jth element in each array refers to the same * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j]. @@ -152,12 +154,25 @@ public: std::set<int32_t> getAppUid(const string& package) const; + // Write current PackageInfoSnapshot to ProtoOutputStream. + // interestingUids: If not empty, only write the package info for these uids. If empty, write + // package info for all uids. + // str_set: if not null, add new string to the set and write str_hash to proto + // if null, write string to proto. + void writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings, bool includeInstaller, + const std::set<int32_t>& interestingUids, std::set<string>* str_set, + ProtoOutputStream* proto); + private: std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const; string normalizeAppName(const string& appName) const; void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output); + void writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings, + bool includeInstaller, const std::set<int32_t>& interestingUids, + std::set<string>* str_set, ProtoOutputStream* proto); + mutable mutex mMutex; mutable mutex mIsolatedMutex; diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 09b8fed60dcc..623d8bc06e38 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -457,3 +457,17 @@ message StatsdStatsReport { } repeated LogLossStats detected_log_loss = 16; } + +message AlertTriggerDetails { + message MetricValue { + optional int64 metric_id = 1; + optional DimensionsValue dimension_in_what = 2; + optional DimensionsValue dimension_in_condition = 3; + optional int64 value = 4; + } + oneof value { + MetricValue trigger_metric = 1; + EventMetricData trigger_event = 2; + } + optional UidMapping.PackageInfoSnapshot package_info = 3; +} diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp index 42cac0cc4122..0ed2d75802da 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp +++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp @@ -16,7 +16,10 @@ #define DEBUG false #include "Log.h" +#include "FieldValue.h" #include "IncidentdReporter.h" +#include "packages/UidMap.h" +#include "stats_log_util.h" #include <android/os/IIncidentManager.h> #include <android/os/IncidentReportArgs.h> @@ -43,8 +46,18 @@ const int FIELD_ID_CONFIG_KEY = 3; const int FIELD_ID_CONFIG_KEY_UID = 1; const int FIELD_ID_CONFIG_KEY_ID = 2; +const int FIELD_ID_TRIGGER_DETAILS = 4; +const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1; +const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1; +const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2; +const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3; +const int FIELD_ID_METRIC_VALUE_VALUE = 4; + +const int FIELD_ID_PACKAGE_INFO = 3; + namespace { -void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uint8_t>* protoData) { +void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey, + int64_t metricValue, const ConfigKey& configKey, vector<uint8_t>* protoData) { ProtoOutputStream headerProto; headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id); uint64_t token = @@ -53,6 +66,58 @@ void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uin headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId()); headerProto.end(token); + token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS); + + // MetricValue trigger_metric = 1; + uint64_t metricToken = + headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC); + // message MetricValue { + // optional int64 metric_id = 1; + headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_METRIC_ID, (long long)metricId); + // optional DimensionsValue dimension_in_what = 2; + uint64_t dimToken = + headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT); + writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto); + headerProto.end(dimToken); + + // optional DimensionsValue dimension_in_condition = 3; + dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION); + writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto); + headerProto.end(dimToken); + + // optional int64 value = 4; + headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue); + + // } + headerProto.end(metricToken); + + // write relevant uid package info + std::set<int32_t> uids; + + for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) { + int uid = getUidIfExists(dim); + // any uid <= 2000 are predefined AID_* + if (uid > 2000) { + uids.insert(uid); + } + } + + for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) { + int uid = getUidIfExists(dim); + if (uid > 2000) { + uids.insert(uid); + } + } + + if (!uids.empty()) { + uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO); + UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids, + nullptr /*string set*/, &headerProto); + headerProto.end(token); + } + + headerProto.end(token); + protoData->resize(headerProto.size()); size_t pos = 0; auto iter = headerProto.data(); @@ -65,7 +130,8 @@ void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uin } } // namespace -bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id, +bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId, + const MetricDimensionKey& dimensionKey, int64_t metricValue, const ConfigKey& configKey) { if (config.section_size() == 0) { VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id, @@ -76,7 +142,7 @@ bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_ IncidentReportArgs incidentReport; vector<uint8_t> protoData; - getProtoData(rule_id, configKey, &protoData); + getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey, &protoData); incidentReport.addHeader(protoData); for (int i = 0; i < config.section_size(); i++) { diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h index 1b83fe23de8f..e78a4d98dcd8 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.h +++ b/cmds/statsd/src/subscriber/IncidentdReporter.h @@ -16,6 +16,7 @@ #pragma once +#include "HashableDimensionKey.h" #include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert, IncidentdDetails @@ -26,7 +27,8 @@ namespace statsd { /** * Calls incidentd to trigger an incident report and put in dropbox for uploading. */ -bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id, +bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId, + const MetricDimensionKey& dimensionKey, int64_t metricValue, const ConfigKey& configKey); } // namespace statsd diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp index 960fbdab1c15..c10703c36b98 100644 --- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp +++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp @@ -90,7 +90,8 @@ void detectAndDeclareAnomalies(AnomalyTracker& tracker, const std::shared_ptr<DimToValMap>& bucket, const int64_t& eventTimestamp) { for (const auto& kv : *bucket) { - tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, kv.first, kv.second); + tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, 0 /*metric_id*/, kv.first, + kv.second); } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5f778da44a1c..e55c96443198 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -71,6 +71,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Parcelable; import android.os.PersistableBundle; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; import android.os.StrictMode; @@ -2297,7 +2298,7 @@ public class Activity extends ContextThemeWrapper public final void requestShowKeyboardShortcuts() { Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS); intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME); - sendBroadcastAsUser(intent, UserHandle.SYSTEM); + sendBroadcastAsUser(intent, Process.myUserHandle()); } /** @@ -2306,7 +2307,7 @@ public class Activity extends ContextThemeWrapper public final void dismissKeyboardShortcutsHelper() { Intent intent = new Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS); intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME); - sendBroadcastAsUser(intent, UserHandle.SYSTEM); + sendBroadcastAsUser(intent, Process.myUserHandle()); } @Override diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index f76f7b9a7fc7..13eec580ec14 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -4291,12 +4291,35 @@ public class AppOpsManager { /** * Like {@link #noteProxyOp(String, String)} but instead * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. + * + * <p>This API requires the package with the {@code proxiedPackageName} to belongs to + * {@link Binder#getCallingUid()}. */ public int noteProxyOpNoThrow(String op, String proxiedPackageName) { return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName); } /** + * Like {@link #noteProxyOp(String, String)} but instead + * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. + * + * <p>This API requires package with the {@code proxiedPackageName} to belong to + * {@code proxiedUid}. + * + * @param op The op to note + * @param proxiedPackageName The package to note the op for or {@code null} if the op should be + * noted for the "android" package + * @param proxiedUid The uid the package belongs to + * + * @hide + */ + @SystemApi + public int noteProxyOpNoThrow(@NonNull String op, @Nullable String proxiedPackageName, + int proxiedUid) { + return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName, proxiedUid); + } + + /** * Report that an application has started executing a long-running operation. Note that you * must pass in both the uid and name of the application to be checked; this function will * verify that these two match, and if not, return {@link #MODE_IGNORED}. If this call @@ -4495,17 +4518,30 @@ public class AppOpsManager { * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. * @hide */ - public int noteProxyOpNoThrow(int op, String proxiedPackageName) { + public int noteProxyOpNoThrow(int op, String proxiedPackageName, int proxiedUid) { logOperationIfNeeded(op, mContext.getOpPackageName(), proxiedPackageName); try { return mService.noteProxyOperation(op, Process.myUid(), mContext.getOpPackageName(), - Binder.getCallingUid(), proxiedPackageName); + proxiedUid, proxiedPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** + * Like {@link #noteProxyOp(int, String)} but instead + * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. + * + * <p>This API requires the package with {@code proxiedPackageName} to belongs to + * {@link Binder#getCallingUid()}. + * + * @hide + */ + public int noteProxyOpNoThrow(int op, String proxiedPackageName) { + return noteProxyOpNoThrow(op, proxiedPackageName, Binder.getCallingUid()); + } + + /** * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. * @hide diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 87bf5ed7db65..f116e133e338 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.pm.ServiceInfo.ForegroundServiceType; import android.content.res.Configuration; import android.os.Build; import android.os.IBinder; @@ -735,7 +736,7 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * @see {@link android.content.pm.ServiceInfo} for the set of FOREGROUND_SERVICE_TYPE flags. */ public final void startForeground(int id, @NonNull Notification notification, - int foregroundServiceType) { + @ForegroundServiceType int foregroundServiceType) { try { mActivityManager.setServiceForeground( new ComponentName(this, mClassName), mToken, id, diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index cca8bd00b646..c12a92f44fa2 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -106,7 +106,6 @@ import android.net.IpMemoryStore; import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; -import android.net.NetworkStack; import android.net.NetworkWatchlistManager; import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; @@ -336,13 +335,6 @@ final class SystemServiceRegistry { } }); - registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class, - new StaticServiceFetcher<NetworkStack>() { - @Override - public NetworkStack createService() { - return new NetworkStack(); - }}); - registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class, new CachedServiceFetcher<IpMemoryStore>() { @Override @@ -1137,7 +1129,11 @@ final class SystemServiceRegistry { IBinder b = ServiceManager .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE); IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b); - return new ContentCaptureManager(outerContext, service); + if (service != null) { + // When feature is disabled, we return a null manager to apps so the + // performance impact is practically zero + return new ContentCaptureManager(outerContext, service); + } } return null; }}); diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index a554882123f1..46316e1a254b 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -229,7 +229,11 @@ public class UiModeManager { * <strong>Note:</strong> On API 22 and below, changes to the night mode * are only effective when the {@link Configuration#UI_MODE_TYPE_CAR car} * or {@link Configuration#UI_MODE_TYPE_DESK desk} mode is enabled on a - * device. Starting in API 23, changes to night mode are always effective. + * device. On API 23 through API 28, changes to night mode are always effective. + * <p> + * Starting in API 29, when the device is in car mode and this method is called, night mode + * will change, but the new setting is not persisted and the previously persisted setting + * will be restored when the device exits car mode. * <p> * Changes to night mode take effect globally and will result in a configuration change * (and potentially an Activity lifecycle event) being applied to all running apps. diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java index 94a2a3eaae7f..97efa01e982b 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -465,8 +465,6 @@ public final class UsageStats implements Parcelable { mActivities.put(instanceId, eventType); break; case ACTIVITY_STOPPED: - mActivities.put(instanceId, eventType); - break; case ACTIVITY_DESTROYED: // remove activity from the map. mActivities.delete(instanceId); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 957a48494892..25bfba26256f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -49,7 +49,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.net.NetworkStack; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -3647,11 +3646,10 @@ public abstract class Context { public static final String NETD_SERVICE = "netd"; /** - * Use with {@link #getSystemService(String)} to retrieve a - * {@link NetworkStack} for communicating with the network stack + * Use with {@link android.os.ServiceManager.getService()} to retrieve a + * {@link NetworkStackClient} IBinder for communicating with the network stack * @hide - * @see #getSystemService(String) - * @see NetworkStack + * @see NetworkStackClient */ public static final String NETWORK_STACK_SERVICE = "network_stack"; diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java index 9f5c877e7081..6fe6e991fb1e 100644 --- a/core/java/android/content/PermissionChecker.java +++ b/core/java/android/content/PermissionChecker.java @@ -108,8 +108,7 @@ public final class PermissionChecker { packageName = packageNames[0]; } - if (appOpsManager.noteProxyOpNoThrow(op, packageName) - != AppOpsManager.MODE_ALLOWED) { + if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid) != AppOpsManager.MODE_ALLOWED) { return PERMISSION_DENIED_APP_OP; } @@ -120,6 +119,9 @@ public final class PermissionChecker { * Checks whether your app has a given permission and whether the app op * that corresponds to this permission is allowed. * + * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as + * {@link Process#myUid()}. + * * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 36ffb0ea94d0..14e77258c65e 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -295,8 +295,6 @@ interface IPackageManager { void restoreDefaultApps(in byte[] backup, int userId); byte[] getIntentFilterVerificationBackup(int userId); void restoreIntentFilterVerification(in byte[] backup, int userId); - byte[] getPermissionGrantBackup(int userId); - void restorePermissionGrants(in byte[] backup, int userId); /** * Report the set of 'Home' activity candidates, plus (if any) which of them diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3ea78df6ae39..00419212544a 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2943,6 +2943,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi public static final int FLAG_PERMISSION_USER_SET = 1 << 0; /** @@ -2953,6 +2954,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi public static final int FLAG_PERMISSION_USER_FIXED = 1 << 1; /** @@ -2976,6 +2978,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3; /** @@ -3005,6 +3008,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6; /** @@ -3014,6 +3018,7 @@ public abstract class PackageManager { * * @hide */ + @TestApi public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7; /** @@ -3795,6 +3800,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi @RequiresPermission(anyOf = { android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS @@ -3815,6 +3821,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi @RequiresPermission(anyOf = { android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 60475de351cf..4a2f800552f6 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -151,6 +151,7 @@ public class ServiceInfo extends ComponentInfo * @hide */ @IntDef(flag = true, prefix = { "FOREGROUND_SERVICE_TYPE_" }, value = { + FOREGROUND_SERVICE_TYPE_MANIFEST, FOREGROUND_SERVICE_TYPE_NONE, FOREGROUND_SERVICE_TYPE_DATA_SYNC, FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, @@ -180,10 +181,10 @@ public class ServiceInfo extends ComponentInfo } /** - * Return the current foreground service type. - * @return the current foreground service type. + * Return foreground service type specified in the manifest.. + * @return foreground service type specified in the manifest. */ - public int getForegroundServiceType() { + public @ForegroundServiceType int getForegroundServiceType() { return mForegroundServiceType; } diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index 5722e7b25fbf..ea489c456f3d 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -77,6 +77,14 @@ public class SQLiteQueryBuilder { } /** + * Get if the query is marked as DISTINCT, as last configured by + * {@link #setDistinct(boolean)}. + */ + public boolean getDistinct() { + return mDistinct; + } + + /** * Returns the list of tables being queried * * @return the list of tables being queried @@ -167,6 +175,14 @@ public class SQLiteQueryBuilder { } /** + * Gets the projection map for the query, as last configured by + * {@link #setProjectionMap(Map)}. + */ + public Map<String, String> getProjectionMap() { + return mProjectionMap; + } + + /** * Sets a projection greylist of columns that will be allowed through, even * when {@link #setStrict(boolean)} is enabled. This provides a way for * abusive custom columns like {@code COUNT(*)} to continue working. @@ -178,6 +194,16 @@ public class SQLiteQueryBuilder { } /** + * Gets the projection greylist for the query, as last configured by + * {@link #setProjectionGreylist(List)}. + * + * @hide + */ + public List<Pattern> getProjectionGreylist() { + return mProjectionGreylist; + } + + /** * Sets the cursor factory to be used for the query. You can use * one factory for all queries on a database but it is normally * easier to specify the factory when doing this query. @@ -189,6 +215,14 @@ public class SQLiteQueryBuilder { } /** + * Sets the cursor factory to be used for the query, as last configured by + * {@link #setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory)}. + */ + public SQLiteDatabase.CursorFactory getCursorFactory() { + return mFactory; + } + + /** * When set, the selection is verified against malicious arguments. * When using this class to create a statement using * {@link #buildQueryString(boolean, String, String[], String, String, String, String, String)}, @@ -214,6 +248,14 @@ public class SQLiteQueryBuilder { } /** + * Get if the query is marked as strict, as last configured by + * {@link #setStrict(boolean)}. + */ + public boolean getStrict() { + return mStrict; + } + + /** * Build an SQL query string from the given clauses. * * @param distinct true if you want each row to be unique, false otherwise. diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 68d36de19963..6d195ae47449 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3936,15 +3936,16 @@ public class ConnectivityManager { * * <p>This endpoint is exclusively for use by the NetworkStack and is protected by the * corresponding permission. + * @param network Network on which the captive portal was detected. * @param appExtras Extras to include in the app start intent. * @hide */ @SystemApi @TestApi @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) - public void startCaptivePortalApp(Bundle appExtras) { + public void startCaptivePortalApp(Network network, Bundle appExtras) { try { - mService.startCaptivePortalAppInternal(appExtras); + mService.startCaptivePortalAppInternal(network, appExtras); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 872671fa5697..87c62d2f10a7 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -168,7 +168,7 @@ interface IConnectivityManager void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAvoidUnvalidated(in Network network); void startCaptivePortalApp(in Network network); - void startCaptivePortalAppInternal(in Bundle appExtras); + void startCaptivePortalAppInternal(in Network network, in Bundle appExtras); boolean getAvoidBadWifi(); int getMultipathPreference(in Network Network); diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl index 41f969acad6f..c94cdde15aa8 100644 --- a/core/java/android/net/INetworkMonitor.aidl +++ b/core/java/android/net/INetworkMonitor.aidl @@ -34,6 +34,7 @@ oneway interface INetworkMonitor { void start(); void launchCaptivePortalApp(); + void notifyCaptivePortalAppFinished(int response); void forceReevaluation(int uid); void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config); void notifyDnsResponse(int returnCode); diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl index 514658549651..2c61511feb72 100644 --- a/core/java/android/net/INetworkMonitorCallbacks.aidl +++ b/core/java/android/net/INetworkMonitorCallbacks.aidl @@ -26,5 +26,4 @@ oneway interface INetworkMonitorCallbacks { void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config); void showProvisioningNotification(String action, String packageName); void hideProvisioningNotification(); - void logCaptivePortalLoginEvent(int eventId, String packageName); }
\ No newline at end of file diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java index ca49438390e9..dbb894f92f55 100644 --- a/core/java/android/net/NetworkStack.java +++ b/core/java/android/net/NetworkStack.java @@ -15,46 +15,17 @@ */ package android.net; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; - -import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.SystemService; import android.annotation.TestApi; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.net.dhcp.DhcpServingParamsParcel; -import android.net.dhcp.IDhcpServerCallbacks; -import android.net.ip.IIpClientCallbacks; -import android.os.Binder; -import android.os.IBinder; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; -import android.util.Slog; - -import com.android.internal.annotations.GuardedBy; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; /** - * Service used to communicate with the network stack, which is running in a separate module. + * + * Constants for client code communicating with the network stack service. * @hide */ -@SystemService(Context.NETWORK_STACK_SERVICE) @SystemApi @TestApi public class NetworkStack { - private static final String TAG = NetworkStack.class.getSimpleName(); - /** * Permission granted only to the NetworkStack APK, defined in NetworkStackStub with signature * protection level. @@ -65,235 +36,5 @@ public class NetworkStack { public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; - private static final int NETWORKSTACK_TIMEOUT_MS = 10_000; - - @NonNull - @GuardedBy("mPendingNetStackRequests") - private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>(); - @Nullable - @GuardedBy("mPendingNetStackRequests") - private INetworkStackConnector mConnector; - - private volatile boolean mNetworkStackStartRequested = false; - - private interface NetworkStackCallback { - void onNetworkStackConnected(INetworkStackConnector connector); - } - - /** @hide */ - public NetworkStack() { } - - /** - * Create a DHCP server according to the specified parameters. - * - * <p>The server will be returned asynchronously through the provided callbacks. - * @hide - */ - public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params, - final IDhcpServerCallbacks cb) { - requestConnector(connector -> { - try { - connector.makeDhcpServer(ifName, params, cb); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - }); - } - - /** - * Create an IpClient on the specified interface. - * - * <p>The IpClient will be returned asynchronously through the provided callbacks. - * @hide - */ - public void makeIpClient(String ifName, IIpClientCallbacks cb) { - requestConnector(connector -> { - try { - connector.makeIpClient(ifName, cb); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - }); - } - - /** - * Create a NetworkMonitor. - * - * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks. - * @hide - */ - public void makeNetworkMonitor( - NetworkParcelable network, String name, INetworkMonitorCallbacks cb) { - requestConnector(connector -> { - try { - connector.makeNetworkMonitor(network, name, cb); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - }); - } - - private class NetworkStackConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - registerNetworkStackService(service); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - // TODO: crash/reboot the system ? - Slog.wtf(TAG, "Lost network stack connector"); - } - }; - - private void registerNetworkStackService(@NonNull IBinder service) { - final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service); - - ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */, - DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); - - final ArrayList<NetworkStackCallback> requests; - synchronized (mPendingNetStackRequests) { - requests = new ArrayList<>(mPendingNetStackRequests); - mPendingNetStackRequests.clear(); - mConnector = connector; - } - - for (NetworkStackCallback r : requests) { - r.onNetworkStackConnected(connector); - } - } - - /** - * Start the network stack. Should be called only once on device startup. - * - * <p>This method will start the network stack either in the network stack process, or inside - * the system server on devices that do not support the network stack module. The network stack - * connector will then be delivered asynchronously to clients that requested it before it was - * started. - * @hide - */ - public void start(Context context) { - mNetworkStackStartRequested = true; - // Try to bind in-process if the library is available - IBinder connector = null; - try { - final Class service = Class.forName( - "com.android.server.NetworkStackService", - true /* initialize */, - context.getClassLoader()); - connector = (IBinder) service.getMethod("makeConnector", Context.class) - .invoke(null, context); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService"); - // TODO: crash/reboot system here ? - return; - } catch (ClassNotFoundException e) { - // Normal behavior if stack is provided by the app: fall through - } - - // In-process network stack. Add the service to the service manager here. - if (connector != null) { - registerNetworkStackService(connector); - return; - } - // Start the network stack process. The service will be added to the service manager in - // NetworkStackConnection.onServiceConnected(). - final Intent intent = new Intent(INetworkStackConnector.class.getName()); - final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); - intent.setComponent(comp); - - if (comp == null) { - Slog.wtf(TAG, "Could not resolve the network stack with " + intent); - // TODO: crash/reboot system server ? - return; - } - - final PackageManager pm = context.getPackageManager(); - int uid = -1; - try { - uid = pm.getPackageUid(comp.getPackageName(), UserHandle.USER_SYSTEM); - } catch (PackageManager.NameNotFoundException e) { - Slog.wtf("Network stack package not found", e); - // Fall through - } - - if (uid != Process.NETWORK_STACK_UID) { - throw new SecurityException("Invalid network stack UID: " + uid); - } - - final int hasPermission = - pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName()); - if (hasPermission != PERMISSION_GRANTED) { - throw new SecurityException( - "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK); - } - - if (!context.bindServiceAsUser(intent, new NetworkStackConnection(), - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) { - Slog.wtf(TAG, - "Could not bind to network stack in-process, or in app with " + intent); - // TODO: crash/reboot system server if no network stack after a timeout ? - } - } - - /** - * For non-system server clients, get the connector registered by the system server. - */ - private INetworkStackConnector getRemoteConnector() { - // Block until the NetworkStack connector is registered in ServiceManager. - // <p>This is only useful for non-system processes that do not have a way to be notified of - // registration completion. Adding a callback system would be too heavy weight considering - // that the connector is registered on boot, so it is unlikely that a client would request - // it before it is registered. - // TODO: consider blocking boot on registration and simplify much of the logic in this class - IBinder connector; - try { - final long before = System.currentTimeMillis(); - while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) { - Thread.sleep(20); - if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { - Slog.e(TAG, "Timeout waiting for NetworkStack connector"); - return null; - } - } - } catch (InterruptedException e) { - Slog.e(TAG, "Error waiting for NetworkStack connector", e); - return null; - } - - return INetworkStackConnector.Stub.asInterface(connector); - } - - private void requestConnector(@NonNull NetworkStackCallback request) { - // TODO: PID check. - final int caller = Binder.getCallingUid(); - if (caller != Process.SYSTEM_UID && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)) { - // Don't even attempt to obtain the connector and give a nice error message - throw new SecurityException( - "Only the system server should try to bind to the network stack."); - } - - if (!mNetworkStackStartRequested) { - // The network stack is not being started in this process, e.g. this process is not - // the system server. Get a remote connector registered by the system server. - final INetworkStackConnector connector = getRemoteConnector(); - synchronized (mPendingNetStackRequests) { - mConnector = connector; - } - request.onNetworkStackConnected(connector); - return; - } - - final INetworkStackConnector connector; - synchronized (mPendingNetStackRequests) { - connector = mConnector; - if (connector == null) { - mPendingNetStackRequests.add(request); - return; - } - } - - request.onNetworkStackConnected(connector); - } + private NetworkStack() {} } diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index cc241b3b7756..ec6da24dc2b1 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -61,6 +61,7 @@ public class GraphicsEnvironment { private static final String SYSTEM_DRIVER_VERSION_NAME = ""; private static final long SYSTEM_DRIVER_VERSION_CODE = 0; private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; + private static final String PROPERTY_GFX_DRIVER_BUILD_DATE = "ro.gfx.driver.build_date"; private static final String ANGLE_RULES_FILE = "a4a_rules.json"; private static final String ANGLE_TEMP_RULES = "debug.angle.rules"; private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID"; @@ -79,8 +80,9 @@ public class GraphicsEnvironment { setupGpuLayers(context, coreSettings, pm, packageName); setupAngle(context, coreSettings, pm, packageName); if (!chooseDriver(context, coreSettings, pm, packageName)) { + final String driverBuildDate = SystemProperties.get(PROPERTY_GFX_DRIVER_BUILD_DATE); setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE, - packageName); + driverBuildDate == null ? "" : driverBuildDate, packageName); } } @@ -574,8 +576,8 @@ public class GraphicsEnvironment { final PackageInfo driverPackageInfo; try { - driverPackageInfo = - pm.getPackageInfo(driverPackageName, PackageManager.MATCH_SYSTEM_ONLY); + driverPackageInfo = pm.getPackageInfo(driverPackageName, + PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "driver package '" + driverPackageName + "' not installed"); return false; @@ -655,9 +657,6 @@ public class GraphicsEnvironment { return false; } - setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode, - packageName); - final StringBuilder sb = new StringBuilder(); sb.append(driverAppInfo.nativeLibraryDir) .append(File.pathSeparator); @@ -669,6 +668,12 @@ public class GraphicsEnvironment { if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths); setDriverPath(paths); + final String driverBuildDate = driverAppInfo.metaData == null + ? "" + : driverAppInfo.metaData.getString("driver_build_date"); + setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode, + driverBuildDate == null ? "" : driverBuildDate, packageName); + return true; } @@ -710,7 +715,7 @@ public class GraphicsEnvironment { private static native void setDebugLayersGLES(String layers); private static native void setDriverPath(String path); private static native void setGpuStats(String driverPackageName, String driverVersionName, - long driverVersionCode, String appPackageName); + long driverVersionCode, String driverBuildDate, String appPackageName); private static native void setAngleInfo(String path, String appPackage, String devOptIn, FileDescriptor rulesFd, long rulesOffset, long rulesLength); private static native boolean getShouldUseAngle(String packageName); diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index 89967c325dd2..d62bc6c5a872 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -51,6 +51,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; @@ -85,9 +86,11 @@ public final class PermissionControllerManager { private static final Object sLock = new Object(); - /** App global remote service used by all {@link PermissionControllerManager managers} */ + /** + * Global remote services (per user) used by all {@link PermissionControllerManager managers} + */ @GuardedBy("sLock") - private static RemoteService sRemoteService; + private static SparseArray<RemoteService> sRemoteServices = new SparseArray<>(1); /** * The key for retrieving the result from the returned bundle. @@ -203,6 +206,7 @@ public final class PermissionControllerManager { } private final @NonNull Context mContext; + private final @NonNull RemoteService mRemoteService; /** * Create a new {@link PermissionControllerManager}. @@ -213,14 +217,18 @@ public final class PermissionControllerManager { */ public PermissionControllerManager(@NonNull Context context) { synchronized (sLock) { - if (sRemoteService == null) { + RemoteService remoteService = sRemoteServices.get(context.getUserId(), null); + if (remoteService == null) { Intent intent = new Intent(SERVICE_INTERFACE); intent.setPackage(context.getPackageManager().getPermissionControllerPackageName()); ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0); - sRemoteService = new RemoteService(context.getApplicationContext(), - serviceInfo.getComponentInfo().getComponentName()); + remoteService = new RemoteService(context.getApplicationContext(), + serviceInfo.getComponentInfo().getComponentName(), context.getUser()); + sRemoteServices.put(context.getUserId(), remoteService); } + + mRemoteService = remoteService; } mContext = context; @@ -255,7 +263,7 @@ public final class PermissionControllerManager { + " required"); } - sRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(sRemoteService, + mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService, request, doDryRun, reason, mContext.getPackageName(), executor, callback)); } @@ -276,7 +284,7 @@ public final class PermissionControllerManager { checkNotNull(executor); checkNotNull(callback); - sRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(sRemoteService, + mRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(mRemoteService, user, executor, callback)); } @@ -294,8 +302,8 @@ public final class PermissionControllerManager { checkNotNull(backup); checkNotNull(user); - sRemoteService.scheduleAsyncRequest( - new PendingRestoreRuntimePermissionBackup(sRemoteService, backup, user)); + mRemoteService.scheduleAsyncRequest( + new PendingRestoreRuntimePermissionBackup(mRemoteService, backup, user)); } /** @@ -318,8 +326,8 @@ public final class PermissionControllerManager { checkNotNull(executor); checkNotNull(callback); - sRemoteService.scheduleRequest( - new PendingRestoreDelayedRuntimePermissionBackup(sRemoteService, packageName, + mRemoteService.scheduleRequest( + new PendingRestoreDelayedRuntimePermissionBackup(mRemoteService, packageName, user, executor, callback)); } @@ -338,8 +346,8 @@ public final class PermissionControllerManager { checkNotNull(packageName); checkNotNull(callback); - sRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(sRemoteService, - packageName, callback, handler == null ? sRemoteService.getHandler() : handler)); + mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService, + packageName, callback, handler == null ? mRemoteService.getHandler() : handler)); } /** @@ -356,7 +364,7 @@ public final class PermissionControllerManager { checkNotNull(packageName); checkNotNull(permissionName); - sRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName, + mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName, permissionName)); } @@ -379,9 +387,9 @@ public final class PermissionControllerManager { checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED); checkNotNull(callback); - sRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(sRemoteService, + mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService, permissionNames, flags, callback, - handler == null ? sRemoteService.getHandler() : handler)); + handler == null ? mRemoteService.getHandler() : handler)); } /** @@ -402,7 +410,7 @@ public final class PermissionControllerManager { checkNotNull(executor); checkNotNull(callback); - sRemoteService.scheduleRequest(new PendingGetPermissionUsagesRequest(sRemoteService, + mRemoteService.scheduleRequest(new PendingGetPermissionUsagesRequest(mRemoteService, countSystem, numMillis, executor, callback)); } @@ -424,8 +432,8 @@ public final class PermissionControllerManager { checkNotNull(executor); checkNotNull(callback); - sRemoteService.scheduleRequest(new PendingIsApplicationQualifiedForRoleRequest( - sRemoteService, roleName, packageName, executor, callback)); + mRemoteService.scheduleRequest(new PendingIsApplicationQualifiedForRoleRequest( + mRemoteService, roleName, packageName, executor, callback)); } /** @@ -441,11 +449,12 @@ public final class PermissionControllerManager { * * @param context A context to use * @param componentName The component of the service to connect to + * @param user User the remote service should be connected as */ - RemoteService(@NonNull Context context, @NonNull ComponentName componentName) { - super(context, SERVICE_INTERFACE, componentName, UserHandle.myUserId(), - service -> Log.e(TAG, "RuntimePermPresenterService " + service + " died"), - false, false, 1); + RemoteService(@NonNull Context context, @NonNull ComponentName componentName, + @NonNull UserHandle user) { + super(context, SERVICE_INTERFACE, componentName, user.getIdentifier(), + service -> Log.e(TAG, "RemoteService " + service + " died"), false, false, 1); } /** @@ -624,7 +633,7 @@ public final class PermissionControllerManager { * * <p>Needs to be called when canceling this task as it might be hung. */ - void interruptRead() { + void interruptWrite() { IoUtils.closeQuietly(mLocalPipe); } @@ -806,18 +815,19 @@ public final class PermissionControllerManager { @Override public void run(@NonNull IPermissionController service) { + mBackupSender.execute(mBackup); + ParcelFileDescriptor remotePipe = mBackupSender.getRemotePipe(); try { service.restoreRuntimePermissionBackup(mUser, remotePipe); } catch (RemoteException e) { Log.e(TAG, "Error sending runtime permission backup", e); mBackupSender.cancel(false); + mBackupSender.interruptWrite(); } finally { // Remote pipe end is duped by binder call. Local copy is not needed anymore IoUtils.closeQuietly(remotePipe); } - - mBackupSender.execute(mBackup); } } diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java new file mode 100644 index 000000000000..92dbab33a2f0 --- /dev/null +++ b/core/java/android/permission/PermissionManagerInternal.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.permission; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.UserHandle; + +/** + * Internal interfaces to be used by other components within the system server. + * + * <p>Only for use within the system server. + * + * @hide + */ +public abstract class PermissionManagerInternal { + /** + * Get the state of the runtime permissions as xml file. + * + * @param user The user the data should be extracted for + * + * @return The state as a xml file + */ + public abstract @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user); + + /** + * Restore a permission state previously backed up via {@link #backupRuntimePermissions}. + * + * <p>If not all state can be restored, the un-restoreable state will be delayed and can be + * re-tried via {@link #restoreDelayedRuntimePermissions}. + * + * @param backup The state as an xml file + * @param user The user the data should be restored for + */ + public abstract void restoreRuntimePermissions(@NonNull byte[] backup, + @NonNull UserHandle user); + + /** + * Try to apply permission backup of a package that was previously not applied. + * + * @param packageName The package that is newly installed + * @param user The user the package is installed for + * + * @see #restoreRuntimePermissions + */ + public abstract void restoreDelayedRuntimePermissions(@NonNull String packageName, + @NonNull UserHandle user); +} diff --git a/core/java/android/provider/BaseColumns.java b/core/java/android/provider/BaseColumns.java index f594c19d8eca..00c9e72df880 100644 --- a/core/java/android/provider/BaseColumns.java +++ b/core/java/android/provider/BaseColumns.java @@ -16,17 +16,18 @@ package android.provider; -public interface BaseColumns -{ +import android.database.Cursor; + +public interface BaseColumns { /** * The unique ID for a row. - * <P>Type: INTEGER (long)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String _ID = "_id"; /** * The count of rows in a directory. - * <P>Type: INTEGER</P> */ + // @Column(Cursor.FIELD_TYPE_INTEGER) public static final String _COUNT = "_count"; } diff --git a/core/java/android/provider/Column.java b/core/java/android/provider/Column.java new file mode 100644 index 000000000000..1364fb86cbd6 --- /dev/null +++ b/core/java/android/provider/Column.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.provider; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Denotes that a field is a {@link ContentProvider} column. It can be used as a + * key for {@link ContentValues} when inserting or updating data, or as a + * projection when querying. + * + * @hide + */ +@Documented +@Retention(RUNTIME) +@Target({FIELD}) +public @interface Column { + /** + * The {@link Cursor#getType(int)} of the data stored in this column. + */ + int value(); + + /** + * This column is read-only and cannot be defined during insert or updates. + */ + boolean readOnly() default false; +} diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 0b3842080a75..1b10bef76067 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -857,8 +857,6 @@ public final class MediaStore { * this path. Instead of trying to open this path directly, apps should * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain * access. - * <p> - * Type: TEXT * * @deprecated Apps may not have filesystem permissions to directly * access this path. Instead of trying to open this path @@ -869,6 +867,7 @@ public final class MediaStore { * {@link android.os.Build.VERSION_CODES#Q} or higher. */ @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) public static final String DATA = "_data"; /** @@ -883,44 +882,44 @@ public final class MediaStore { * If you require the hash of a specific item, you can call * {@link ContentResolver#canonicalize(Uri)}, which will block until the * hash is calculated. - * <p> - * Type: BLOB + * * @removed */ @Deprecated + @Column(value = Cursor.FIELD_TYPE_BLOB, readOnly = true) public static final String HASH = "_hash"; /** * The size of the file in bytes - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String SIZE = "_size"; /** * The display name of the file - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String DISPLAY_NAME = "_display_name"; /** * The title of the content - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String TITLE = "title"; /** * The time the file was added to the media provider * Units are seconds since 1970. - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DATE_ADDED = "date_added"; /** * The time the file was last modified * Units are seconds since 1970. * NOTE: This is for internal use by the media scanner. Do not modify this field. - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DATE_MODIFIED = "date_modified"; /** @@ -938,9 +937,8 @@ public final class MediaStore { * {@code format} of {@code audio/ogg} would be ignored. * <p> * This is a read-only column that is automatically computed. - * <p> - * Type: TEXT */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String MIME_TYPE = "mime_type"; /** @@ -948,35 +946,34 @@ public final class MediaStore { * Used to pass the new file's object handle through the media scanner * from MTP to the media provider * For internal use only by MTP, media scanner and media provider. - * <P>Type: INTEGER</P> * @hide */ + @Deprecated + // @Column(Cursor.FIELD_TYPE_INTEGER) public static final String MEDIA_SCANNER_NEW_OBJECT_ID = "media_scanner_new_object_id"; /** * Non-zero if the media file is drm-protected - * <P>Type: INTEGER (boolean)</P> * @hide */ @UnsupportedAppUsage + @Deprecated + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String IS_DRM = "is_drm"; /** * Flag indicating if a media item is pending, and still being inserted * by its owner. - * <p> - * Type: BOOLEAN * * @see MediaColumns#IS_PENDING * @see MediaStore#setIncludePending(Uri) * @see MediaStore#createPending(Context, PendingParams) */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String IS_PENDING = "is_pending"; /** * Flag indicating if a media item is trashed. - * <p> - * Type: BOOLEAN * * @see MediaColumns#IS_TRASHED * @see MediaStore#setIncludeTrashed(Uri) @@ -985,57 +982,54 @@ public final class MediaStore { * @removed */ @Deprecated + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String IS_TRASHED = "is_trashed"; /** * The time the file should be considered expired. Units are seconds * since 1970. Typically only meaningful in the context of * {@link #IS_PENDING} or {@link #IS_TRASHED}. - * <p> - * Type: INTEGER * @removed */ @Deprecated + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String DATE_EXPIRES = "date_expires"; /** * The width of the image/video in pixels. */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String WIDTH = "width"; /** * The height of the image/video in pixels. */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String HEIGHT = "height"; /** * Package name that contributed this media. The value may be * {@code NULL} if ownership cannot be reliably determined. - * <p> - * This is a read-only column that is automatically computed. - * <p> - * Type: TEXT */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String OWNER_PACKAGE_NAME = "owner_package_name"; /** * The primary directory name this media exists under. The value may be * {@code NULL} if the media doesn't have a primary directory name. - * <p> - * Type: TEXT * * @see PendingParams#setPrimaryDirectory(String) */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String PRIMARY_DIRECTORY = "primary_directory"; /** * The secondary directory name this media exists under. The value may * be {@code NULL} if the media doesn't have a secondary directory name. - * <p> - * Type: TEXT * * @see PendingParams#setSecondaryDirectory(String) */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String SECONDARY_DIRECTORY = "secondary_directory"; /** @@ -1046,11 +1040,8 @@ public final class MediaStore { * <p> * Each "document ID" is created once for each new resource. Different * renditions of that resource are expected to have different IDs. - * <p> - * This is a read-only column that is automatically computed. - * <p> - * Type: TEXT */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String DOCUMENT_ID = "document_id"; /** @@ -1061,11 +1052,8 @@ public final class MediaStore { * <p> * This "instance ID" changes with each save operation of a specific * "document ID". - * <p> - * This is a read-only column that is automatically computed. - * <p> - * Type: TEXT */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String INSTANCE_ID = "instance_id"; /** @@ -1077,11 +1065,8 @@ public final class MediaStore { * For example, when you save a PSD document as a JPEG, then convert the * JPEG to GIF format, the "original document ID" of both the JPEG and * GIF files is the "document ID" of the original PSD file. - * <p> - * This is a read-only column that is automatically computed. - * <p> - * Type: TEXT */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ORIGINAL_DOCUMENT_ID = "original_document_id"; } @@ -1172,43 +1157,46 @@ public final class MediaStore { public interface FileColumns extends MediaColumns { /** * The MTP storage ID of the file - * <P>Type: INTEGER</P> * @hide */ @UnsupportedAppUsage + @Deprecated + // @Column(Cursor.FIELD_TYPE_INTEGER) public static final String STORAGE_ID = "storage_id"; /** * The MTP format code of the file - * <P>Type: INTEGER</P> * @hide */ @UnsupportedAppUsage + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String FORMAT = "format"; /** * The index of the parent directory of the file - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String PARENT = "parent"; /** * The MIME type of the file * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String MIME_TYPE = "mime_type"; /** * The title of the content * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String TITLE = "title"; /** * The media type (audio, video, image or playlist) * of the file, or 0 for not a media file - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String MEDIA_TYPE = "media_type"; /** @@ -1241,6 +1229,7 @@ public final class MediaStore { * Column indicating if the file is part of Downloads collection. * @hide */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_DOWNLOAD = "is_download"; } } @@ -1260,23 +1249,20 @@ public final class MediaStore { public interface DownloadColumns extends MediaColumns { /** * Uri indicating where the file has been downloaded from. - * <p> - * Type: TEXT */ + @Column(Cursor.FIELD_TYPE_STRING) String DOWNLOAD_URI = "download_uri"; /** * Uri indicating HTTP referer of {@link #DOWNLOAD_URI}. - * <p> - * Type: TEXT */ + @Column(Cursor.FIELD_TYPE_STRING) String REFERER_URI = "referer_uri"; /** * The description of the download. - * <p> - * Type: Text */ + @Column(Cursor.FIELD_TYPE_STRING) String DESCRIPTION = "description"; } @@ -1442,29 +1428,28 @@ public final class MediaStore { public interface ImageColumns extends MediaColumns { /** * The description of the image - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String DESCRIPTION = "description"; /** * The picasa id of the image - * <P>Type: TEXT</P> * * @deprecated this value was only relevant for images hosted on * Picasa, which are no longer supported. */ @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) public static final String PICASA_ID = "picasa_id"; /** * Whether the video should be published as public or private - * <P>Type: INTEGER</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String IS_PRIVATE = "isprivate"; /** * The latitude where the image was captured. - * <P>Type: DOUBLE</P> * * @deprecated location details are no longer indexed for privacy * reasons, and this value is now always {@code null}. @@ -1472,11 +1457,11 @@ public final class MediaStore { * {@link ExifInterface#getLatLong(float[])}. */ @Deprecated + @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true) public static final String LATITUDE = "latitude"; /** * The longitude where the image was captured. - * <P>Type: DOUBLE</P> * * @deprecated location details are no longer indexed for privacy * reasons, and this value is now always {@code null}. @@ -1484,40 +1469,40 @@ public final class MediaStore { * {@link ExifInterface#getLatLong(float[])}. */ @Deprecated + @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true) public static final String LONGITUDE = "longitude"; /** * The date & time that the image was taken in units * of milliseconds since jan 1, 1970. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DATE_TAKEN = "datetaken"; /** * The orientation for the image expressed as degrees. * Only degrees 0, 90, 180, 270 will work. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String ORIENTATION = "orientation"; /** * The mini thumb id. - * <P>Type: INTEGER</P> * * @deprecated all thumbnails should be obtained via * {@link MediaStore.Images.Thumbnails#getThumbnail}, as this * value is no longer supported. */ @Deprecated + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; /** * The primary bucket ID of this media item. This can be useful to * present the user a first-level clustering of related media items. * This is a read-only column that is automatically computed. - * <p> - * Type: INTEGER */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String BUCKET_ID = "bucket_id"; /** @@ -1525,9 +1510,8 @@ public final class MediaStore { * useful to present the user a first-level clustering of related * media items. This is a read-only column that is automatically * computed. - * <p> - * Type: TEXT */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; /** @@ -1541,9 +1525,8 @@ public final class MediaStore { * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} * will have the same {@link #GROUP_ID} because the first portion of * their filenames is identical. - * <p> - * Type: INTEGER */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String GROUP_ID = "group_id"; } @@ -1848,8 +1831,6 @@ public final class MediaStore { * apps should use * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain * access. - * <p> - * Type: TEXT * * @deprecated Apps may not have filesystem permissions to directly * access this path. Instead of trying to open this path @@ -1860,39 +1841,45 @@ public final class MediaStore { * {@link android.os.Build.VERSION_CODES#Q} or higher. */ @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) public static final String DATA = "_data"; /** * The original image for the thumbnal - * <P>Type: INTEGER (ID from Images table)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String IMAGE_ID = "image_id"; /** * The kind of the thumbnail - * <P>Type: INTEGER (One of the values below)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String KIND = "kind"; public static final int MINI_KIND = ThumbnailConstants.MINI_KIND; public static final int FULL_SCREEN_KIND = ThumbnailConstants.FULL_SCREEN_KIND; public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND; + /** * The blob raw data of thumbnail - * <P>Type: DATA STREAM</P> + * + * @deprecated this column never existed internally, and could never + * have returned valid data. */ + @Deprecated + @Column(Cursor.FIELD_TYPE_BLOB) public static final String THUMB_DATA = "thumb_data"; /** * The width of the thumbnal - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String WIDTH = "width"; /** * The height of the thumbnail - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String HEIGHT = "height"; } } @@ -1909,79 +1896,80 @@ public final class MediaStore { /** * A non human readable key calculated from the TITLE, used for * searching, sorting and grouping - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String TITLE_KEY = "title_key"; /** * The duration of the audio file, in ms - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DURATION = "duration"; /** * The position, in ms, playback was at when playback for this file * was last stopped. - * <P>Type: INTEGER (long)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String BOOKMARK = "bookmark"; /** * The id of the artist who created the audio file, if any - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String ARTIST_ID = "artist_id"; /** * The artist who created the audio file, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST = "artist"; /** * The artist credited for the album that contains the audio file - * <P>Type: TEXT</P> * @hide */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ALBUM_ARTIST = "album_artist"; /** * Whether the song is part of a compilation - * <P>Type: TEXT</P> * @hide */ + @Deprecated + // @Column(Cursor.FIELD_TYPE_STRING) public static final String COMPILATION = "compilation"; /** * A non human readable key calculated from the ARTIST, used for * searching, sorting and grouping - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST_KEY = "artist_key"; /** * The composer of the audio file, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String COMPOSER = "composer"; /** * The id of the album the audio file is from, if any - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String ALBUM_ID = "album_id"; /** * The album the audio file is from, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ALBUM = "album"; /** * A non human readable key calculated from the ALBUM, used for * searching, sorting and grouping - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ALBUM_KEY = "album_key"; /** @@ -1990,63 +1978,63 @@ public final class MediaStore { * disc number. For multi-disc sets, this number will * be 1xxx for tracks on the first disc, 2xxx for tracks * on the second disc, etc. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String TRACK = "track"; /** * The year the audio file was recorded, if any - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String YEAR = "year"; /** * Non-zero if the audio file is music - * <P>Type: INTEGER (boolean)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_MUSIC = "is_music"; /** * Non-zero if the audio file is a podcast - * <P>Type: INTEGER (boolean)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_PODCAST = "is_podcast"; /** * Non-zero if the audio file may be a ringtone - * <P>Type: INTEGER (boolean)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_RINGTONE = "is_ringtone"; /** * Non-zero if the audio file may be an alarm - * <P>Type: INTEGER (boolean)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_ALARM = "is_alarm"; /** * Non-zero if the audio file may be a notification sound - * <P>Type: INTEGER (boolean)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_NOTIFICATION = "is_notification"; /** * Non-zero if the audio file is an audiobook - * <P>Type: INTEGER (boolean)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String IS_AUDIOBOOK = "is_audiobook"; /** * The genre of the audio file, if any - * <P>Type: TEXT</P> * Does not exist in the database - only used by the media scanner for inserts. * @hide */ + @Deprecated + // @Column(Cursor.FIELD_TYPE_STRING) public static final String GENRE = "genre"; /** * The resource URI of a localized title, if any - * <P>Type: TEXT</P> * Conforms to this pattern: * Scheme: {@link ContentResolver.SCHEME_ANDROID_RESOURCE} * Authority: Package Name of ringtone title provider @@ -2054,6 +2042,7 @@ public final class MediaStore { * Second Path Segment: Resource ID of title * @hide */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String TITLE_RESOURCE_URI = "title_resource_uri"; } @@ -2142,6 +2131,7 @@ public final class MediaStore { * @deprecated Apps may not have filesystem permissions to directly * access this path. */ + @Deprecated public static @Nullable Uri getContentUriForPath(@NonNull String path) { return getContentUri(getVolumeName(new File(path))); } @@ -2202,8 +2192,8 @@ public final class MediaStore { public interface GenresColumns { /** * The name of the genre - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String NAME = "name"; } @@ -2287,14 +2277,14 @@ public final class MediaStore { /** * The ID of the audio file - * <P>Type: INTEGER (long)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String AUDIO_ID = "audio_id"; /** * The ID of the genre - * <P>Type: INTEGER (long)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String GENRE_ID = "genre_id"; } } @@ -2305,8 +2295,8 @@ public final class MediaStore { public interface PlaylistsColumns { /** * The name of the playlist - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String NAME = "name"; /** @@ -2317,8 +2307,6 @@ public final class MediaStore { * apps should use * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain * access. - * <p> - * Type: TEXT * * @deprecated Apps may not have filesystem permissions to directly * access this path. Instead of trying to open this path @@ -2329,21 +2317,22 @@ public final class MediaStore { * {@link android.os.Build.VERSION_CODES#Q} or higher. */ @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) public static final String DATA = "_data"; /** * The time the file was added to the media provider * Units are seconds since 1970. - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DATE_ADDED = "date_added"; /** * The time the file was last modified * Units are seconds since 1970. * NOTE: This is for internal use by the media scanner. Do not modify this field. - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DATE_MODIFIED = "date_modified"; } @@ -2426,6 +2415,7 @@ public final class MediaStore { /** * The ID within the playlist. */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String _ID = "_id"; /** @@ -2436,20 +2426,20 @@ public final class MediaStore { /** * The ID of the audio file - * <P>Type: INTEGER (long)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String AUDIO_ID = "audio_id"; /** * The ID of the playlist - * <P>Type: INTEGER (long)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String PLAYLIST_ID = "playlist_id"; /** * The order of the songs in the playlist - * <P>Type: INTEGER (long)></P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String PLAY_ORDER = "play_order"; /** @@ -2465,25 +2455,27 @@ public final class MediaStore { public interface ArtistColumns { /** * The artist who created the audio file, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST = "artist"; /** * A non human readable key calculated from the ARTIST, used for * searching, sorting and grouping - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST_KEY = "artist_key"; /** * The number of albums in the database for this artist */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String NUMBER_OF_ALBUMS = "number_of_albums"; /** * The number of albums in the database for this artist */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String NUMBER_OF_TRACKS = "number_of_tracks"; } @@ -2551,34 +2543,34 @@ public final class MediaStore { /** * The id for the album - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String ALBUM_ID = "album_id"; /** * The album on which the audio file appears, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ALBUM = "album"; /** * The artist whose songs appear on this album - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST = "artist"; /** * The number of songs on this album - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String NUMBER_OF_SONGS = "numsongs"; /** * This column is available when getting album info via artist, * and indicates the number of songs on the album by the given * artist. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist"; /** @@ -2586,8 +2578,8 @@ public final class MediaStore { * on this album were released. This will often * be the same as {@link #LAST_YEAR}, but for compilation albums * they might differ. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String FIRST_YEAR = "minyear"; /** @@ -2595,20 +2587,19 @@ public final class MediaStore { * on this album were released. This will often * be the same as {@link #FIRST_YEAR}, but for compilation albums * they might differ. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String LAST_YEAR = "maxyear"; /** * A non human readable key calculated from the ALBUM, used for * searching, sorting and grouping - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ALBUM_KEY = "album_key"; /** * Cached album art. - * <P>Type: TEXT</P> * * @deprecated Apps may not have filesystem permissions to directly * access this path. Instead of trying to open this path @@ -2619,6 +2610,7 @@ public final class MediaStore { * {@link android.os.Build.VERSION_CODES#Q} or higher. */ @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) public static final String ALBUM_ART = "album_art"; } @@ -2676,6 +2668,43 @@ public final class MediaStore { // Not instantiable. private Radio() { } } + + /** + * This class provides utility methods to obtain thumbnails for various + * {@link Audio} items. + * + * @deprecated Callers should migrate to using + * {@link ContentResolver#loadThumbnail}, since it offers + * richer control over requested thumbnail sizes and + * cancellation behavior. + * @hide + */ + @Deprecated + public static class Thumbnails implements BaseColumns { + /** + * Path to the thumbnail file on disk. + * <p> + * Note that apps may not have filesystem permissions to directly + * access this path. Instead of trying to open this path directly, + * apps should use + * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain + * access. + * + * @deprecated Apps may not have filesystem permissions to directly + * access this path. Instead of trying to open this path + * directly, apps should use + * {@link ContentResolver#loadThumbnail} + * to gain access. This value will always be + * {@code NULL} for apps targeting + * {@link android.os.Build.VERSION_CODES#Q} or higher. + */ + @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) + public static final String DATA = "_data"; + + @Column(Cursor.FIELD_TYPE_INTEGER) + public static final String ALBUM_ID = "album_id"; + } } public static final class Video { @@ -2693,61 +2722,60 @@ public final class MediaStore { /** * The duration of the video file, in ms - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DURATION = "duration"; /** * The artist who created the video file, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST = "artist"; /** * The album the video file is from, if any - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ALBUM = "album"; /** * The resolution of the video file, formatted as "XxY" - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String RESOLUTION = "resolution"; /** * The description of the video recording - * <P>Type: TEXT</P> */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String DESCRIPTION = "description"; /** * Whether the video should be published as public or private - * <P>Type: INTEGER</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String IS_PRIVATE = "isprivate"; /** * The user-added tags associated with a video - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String TAGS = "tags"; /** * The YouTube category of the video - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String CATEGORY = "category"; /** * The language of the video - * <P>Type: TEXT</P> */ + @Column(Cursor.FIELD_TYPE_STRING) public static final String LANGUAGE = "language"; /** * The latitude where the video was captured. - * <P>Type: DOUBLE</P> * * @deprecated location details are no longer indexed for privacy * reasons, and this value is now always {@code null}. @@ -2755,11 +2783,11 @@ public final class MediaStore { * {@link ExifInterface#getLatLong(float[])}. */ @Deprecated + @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true) public static final String LATITUDE = "latitude"; /** * The longitude where the video was captured. - * <P>Type: DOUBLE</P> * * @deprecated location details are no longer indexed for privacy * reasons, and this value is now always {@code null}. @@ -2767,33 +2795,33 @@ public final class MediaStore { * {@link ExifInterface#getLatLong(float[])}. */ @Deprecated + @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true) public static final String LONGITUDE = "longitude"; /** * The date & time that the video was taken in units * of milliseconds since jan 1, 1970. - * <P>Type: INTEGER</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String DATE_TAKEN = "datetaken"; /** * The mini thumb id. - * <P>Type: INTEGER</P> * * @deprecated all thumbnails should be obtained via * {@link MediaStore.Images.Thumbnails#getThumbnail}, as this * value is no longer supported. */ @Deprecated + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; /** * The primary bucket ID of this media item. This can be useful to * present the user a first-level clustering of related media items. * This is a read-only column that is automatically computed. - * <p> - * Type: INTEGER */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String BUCKET_ID = "bucket_id"; /** @@ -2801,9 +2829,8 @@ public final class MediaStore { * useful to present the user a first-level clustering of related * media items. This is a read-only column that is automatically * computed. - * <p> - * Type: TEXT */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; /** @@ -2817,9 +2844,8 @@ public final class MediaStore { * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} * will have the same {@link #GROUP_ID} because the first portion of * their filenames is identical. - * <p> - * Type: INTEGER */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String GROUP_ID = "group_id"; /** @@ -2827,29 +2853,29 @@ public final class MediaStore { * video should start playing at the next time it is opened. If the value is null or * out of the range 0..DURATION-1 then the video should start playing from the * beginning. - * <P>Type: INTEGER</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String BOOKMARK = "bookmark"; /** * The standard of color aspects - * <P>Type: INTEGER</P> * @hide */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String COLOR_STANDARD = "color_standard"; /** * The transfer of color aspects - * <P>Type: INTEGER</P> * @hide */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String COLOR_TRANSFER = "color_transfer"; /** * The range of color aspects - * <P>Type: INTEGER</P> * @hide */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String COLOR_RANGE = "color_range"; } @@ -3016,8 +3042,6 @@ public final class MediaStore { /** * Path to the thumbnail file on disk. - * <p> - * Type: TEXT * * @deprecated Apps may not have filesystem permissions to directly * access this path. Instead of trying to open this path @@ -3028,18 +3052,19 @@ public final class MediaStore { * {@link android.os.Build.VERSION_CODES#Q} or higher. */ @Deprecated + @Column(Cursor.FIELD_TYPE_STRING) public static final String DATA = "_data"; /** * The original image for the thumbnal - * <P>Type: INTEGER (ID from Video table)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String VIDEO_ID = "video_id"; /** * The kind of the thumbnail - * <P>Type: INTEGER (One of the values below)</P> */ + @Column(Cursor.FIELD_TYPE_INTEGER) public static final String KIND = "kind"; public static final int MINI_KIND = ThumbnailConstants.MINI_KIND; @@ -3048,14 +3073,14 @@ public final class MediaStore { /** * The width of the thumbnal - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String WIDTH = "width"; /** * The height of the thumbnail - * <P>Type: INTEGER (long)</P> */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) public static final String HEIGHT = "height"; } } diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index d2f98599e9a6..b60fbc593b1c 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -34,6 +34,7 @@ import android.os.Looper; import android.os.RemoteException; import android.service.autofill.AutofillService; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.view.contentcapture.ContentCaptureContext; @@ -49,7 +50,9 @@ import com.android.internal.os.IResultReceiver; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * A service used to capture the content of the screen to provide contextual data in other areas of @@ -164,6 +167,19 @@ public abstract class ContentCaptureService extends Service { } /** + * @deprecated use {@link #setContentCaptureWhitelist(Set, Set)} instead + */ + @Deprecated + public final void setContentCaptureWhitelist(@Nullable List<String> packages, + @Nullable List<ComponentName> activities) { + setContentCaptureWhitelist(toSet(packages), toSet(activities)); + } + + private <T> ArraySet<T> toSet(@Nullable List<T> set) { + return set == null ? null : new ArraySet<T>(set); + } + + /** * Explicitly limits content capture to the given packages and activities. * * <p>To reset the whitelist, call it passing {@code null} to both arguments. @@ -171,24 +187,29 @@ public abstract class ContentCaptureService extends Service { * <p>Useful when the service wants to restrict content capture to a category of apps, like * chat apps. For example, if the service wants to support view captures on all activities of * app {@code ChatApp1} and just activities {@code act1} and {@code act2} of {@code ChatApp2}, - * it would call: {@code setContentCaptureWhitelist(Arrays.asList("ChatApp1"), - * Arrays.asList(new ComponentName("ChatApp2", "act1"), + * it would call: {@code setContentCaptureWhitelist(Sets.newArraySet("ChatApp1"), + * Sets.newArraySet(new ComponentName("ChatApp2", "act1"), * new ComponentName("ChatApp2", "act2")));} */ - public final void setContentCaptureWhitelist(@Nullable List<String> packages, - @Nullable List<ComponentName> activities) { + public final void setContentCaptureWhitelist(@Nullable Set<String> packages, + @Nullable Set<ComponentName> activities) { final IContentCaptureServiceCallback callback = mCallback; if (callback == null) { Log.w(TAG, "setContentCaptureWhitelist(): no server callback"); return; } + try { - callback.setContentCaptureWhitelist(packages, activities); + callback.setContentCaptureWhitelist(toList(packages), toList(activities)); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } + private <T> ArrayList<T> toList(@Nullable Set<T> set) { + return set == null ? null : new ArrayList<T>(set); + } + /** * Called when the Android system connects to service. * diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java index 93189b310485..2961426278dc 100644 --- a/core/java/android/service/notification/Adjustment.java +++ b/core/java/android/service/notification/Adjustment.java @@ -15,6 +15,7 @@ */ package android.service.notification; +import android.annotation.SystemApi; import android.app.Notification; import android.os.Bundle; import android.os.Parcel; @@ -36,13 +37,13 @@ public final class Adjustment implements Parcelable { * See {@link android.app.Notification.Builder#addPerson(String)}. * @hide */ + @SystemApi public static final String KEY_PEOPLE = "key_people"; /** * Parcelable {@code ArrayList} of {@link SnoozeCriterion}. These criteria may be visible to * users. If a user chooses to snooze a notification until one of these criterion, the * assistant will be notified via * {@link NotificationAssistantService#onNotificationSnoozedUntilContext}. - * @hide */ public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria"; /** @@ -111,7 +112,11 @@ public final class Adjustment implements Parcelable { mUser = user; } - private Adjustment(Parcel in) { + /** + * @hide + */ + @SystemApi + protected Adjustment(Parcel in) { if (in.readInt() == 1) { mPackage = in.readString(); } else { diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index e93b1580bc66..a69724860634 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -21,6 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SdkConstant; +import android.annotation.SystemApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.admin.DevicePolicyManager; @@ -103,7 +104,6 @@ public abstract class NotificationAssistantService extends NotificationListenerS * * @param sbn the notification to snooze * @param snoozeCriterionId the {@link SnoozeCriterion#getId()} representing a device context. - * @hide */ abstract public void onNotificationSnoozedUntilContext(StatusBarNotification sbn, String snoozeCriterionId); @@ -111,12 +111,13 @@ public abstract class NotificationAssistantService extends NotificationListenerS /** * A notification was posted by an app. Called before post. * + * <p>Note: this method is only called if you don't override + * {@link #onNotificationEnqueued(StatusBarNotification, NotificationChannel)}.</p> + * * @param sbn the new notification * @return an adjustment or null to take no action, within 100ms. */ - public Adjustment onNotificationEnqueued(StatusBarNotification sbn) { - return null; - } + abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn); /** * A notification was posted by an app. Called before post. @@ -240,12 +241,11 @@ public abstract class NotificationAssistantService extends NotificationListenerS /** * Inform the notification manager about un-snoozing a specific notification. * <p> - * This should only be used for notifications snoozed by this listener using - * {@link #snoozeNotification(String, String)}. Once un-snoozed, you will get a + * This should only be used for notifications snoozed because of a contextual snooze suggestion + * you provided via {@link Adjustment#KEY_SNOOZE_CRITERIA}. Once un-snoozed, you will get a * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the * notification. * @param key The key of the notification to snooze - * @hide */ public final void unsnoozeNotification(String key) { if (!isBound()) return; diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java index 814b4772a395..ebfabbfda326 100644 --- a/core/java/android/service/notification/NotificationStats.java +++ b/core/java/android/service/notification/NotificationStats.java @@ -16,6 +16,7 @@ package android.service.notification; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.app.RemoteInput; import android.os.Parcel; import android.os.Parcelable; @@ -98,7 +99,11 @@ public final class NotificationStats implements Parcelable { public NotificationStats() { } - private NotificationStats(Parcel in) { + /** + * @hide + */ + @SystemApi + protected NotificationStats(Parcel in) { mSeen = in.readByte() != 0; mExpanded = in.readByte() != 0; mDirectReplied = in.readByte() != 0; diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java index c77500a9fd70..696e048ffed8 100644 --- a/core/java/android/view/ContextThemeWrapper.java +++ b/core/java/android/view/ContextThemeWrapper.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.Nullable; import android.annotation.StyleRes; import android.annotation.UnsupportedAppUsage; import android.content.Context; @@ -23,6 +24,7 @@ import android.content.ContextWrapper; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; +import android.os.Build; /** * A context wrapper that allows you to modify or replace the theme of the @@ -31,7 +33,7 @@ import android.content.res.Resources; public class ContextThemeWrapper extends ContextWrapper { @UnsupportedAppUsage private int mThemeResource; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768723) private Resources.Theme mTheme; @UnsupportedAppUsage private LayoutInflater mInflater; @@ -146,6 +148,15 @@ public class ContextThemeWrapper extends ContextWrapper { } } + /** + * Set the configure the current theme. If null is provided then the default Theme is returned + * on the next call to {@link #getTheme()} + * @param theme Theme to consume in the wrapper, a value of null resets the theme to the default + */ + public void setTheme(@Nullable Resources.Theme theme) { + mTheme = theme; + } + /** @hide */ @Override @UnsupportedAppUsage diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index f93ac4ce7d16..a6b40ed55ac5 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -78,6 +78,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Set; //TODO: use java.lang.ref.Cleaner once Android supports Java 9 import sun.misc.Cleaner; @@ -1780,6 +1781,18 @@ public final class AutofillManager { } /** + * @deprecated use {@link #setAugmentedAutofillWhitelist(Set, Set)} instead. + * @hide + */ + @SystemApi + @TestApi + @Deprecated + public void setAugmentedAutofillWhitelist(@Nullable List<String> packages, + @Nullable List<ComponentName> activities) { + // TODO(b/123100824): implement + } + + /** * Explicitly limits augmented autofill to the given packages and activities. * * <p>To reset the whitelist, call it passing {@code null} to both arguments. @@ -1799,8 +1812,8 @@ public final class AutofillManager { */ @SystemApi @TestApi - public void setAugmentedAutofillWhitelist(@Nullable List<String> packages, - @Nullable List<ComponentName> activities) { + public void setAugmentedAutofillWhitelist(@Nullable Set<String> packages, + @Nullable Set<ComponentName> activities) { // TODO(b/123100824): implement } diff --git a/core/java/android/view/contentcapture/ContentCaptureHelper.java b/core/java/android/view/contentcapture/ContentCaptureHelper.java index 508880feb3c3..1cf27fc56a8c 100644 --- a/core/java/android/view/contentcapture/ContentCaptureHelper.java +++ b/core/java/android/view/contentcapture/ContentCaptureHelper.java @@ -15,16 +15,29 @@ */ package android.view.contentcapture; +import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL; +import static android.view.contentcapture.ContentCaptureManager.LOGGING_LEVEL_DEBUG; +import static android.view.contentcapture.ContentCaptureManager.LOGGING_LEVEL_OFF; +import static android.view.contentcapture.ContentCaptureManager.LOGGING_LEVEL_VERBOSE; + +import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Build; +import android.provider.DeviceConfig; +import android.util.Log; +import android.view.contentcapture.ContentCaptureManager.LoggingLevel; /** - * Helpe class for this package. + * Helper class for this package and server's. + * + * @hide */ -final class ContentCaptureHelper { +public final class ContentCaptureHelper { - // TODO(b/121044306): define a way to dynamically set them(for example, using settings?) - static final boolean VERBOSE = false; - static final boolean DEBUG = true; // STOPSHIP if not set to false + private static final String TAG = ContentCaptureHelper.class.getSimpleName(); + + public static boolean sVerbose = false; + public static boolean sDebug = true; /** * Used to log text that could contain PII. @@ -34,6 +47,61 @@ final class ContentCaptureHelper { return text == null ? null : text.length() + "_chars"; } + /** + * Gets the value of a device config property from the Content Capture namespace. + */ + public static int getIntDeviceConfigProperty(@NonNull String key, int defaultValue) { + final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, key); + if (value == null) return defaultValue; + + try { + return Integer.parseInt(value); + } catch (Exception e) { + Log.w(TAG, "error parsing value (" + value + ") of property " + key + ": " + e); + return defaultValue; + } + } + + /** + * Sets the value of the static logging level constants based on device config. + */ + public static void setLoggingLevel() { + final int defaultLevel = Build.IS_DEBUGGABLE ? LOGGING_LEVEL_DEBUG : LOGGING_LEVEL_OFF; + final int level = getIntDeviceConfigProperty(DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL, + defaultLevel); + Log.i(TAG, "Setting logging level to " + getLoggingLevelAsString(level)); + sVerbose = sDebug = false; + switch (level) { + case LOGGING_LEVEL_VERBOSE: + sVerbose = true; + // fall through + case LOGGING_LEVEL_DEBUG: + sDebug = true; + return; + case LOGGING_LEVEL_OFF: + // You log nothing, Jon Snow! + return; + default: + Log.w(TAG, "setLoggingLevel(): invalud level: " + level); + } + } + + /** + * Gets a user-friendly value for a content capture logging level. + */ + public static String getLoggingLevelAsString(@LoggingLevel int level) { + switch (level) { + case LOGGING_LEVEL_OFF: + return "OFF"; + case LOGGING_LEVEL_DEBUG: + return "DEBUG"; + case LOGGING_LEVEL_VERBOSE: + return "VERBOSE"; + default: + return "UNKNOWN-" + level; + } + } + private ContentCaptureHelper() { throw new UnsupportedOperationException("contains only static methods"); } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 634443d78b49..99063083e229 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -15,9 +15,10 @@ */ package android.view.contentcapture; -import static android.view.contentcapture.ContentCaptureHelper.DEBUG; -import static android.view.contentcapture.ContentCaptureHelper.VERBOSE; +import static android.view.contentcapture.ContentCaptureHelper.sDebug; +import static android.view.contentcapture.ContentCaptureHelper.sVerbose; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -38,16 +39,11 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.SyncResultReceiver; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; -/* - * NOTE: all methods in this class should return right away, or do the real work in a handler - * thread. - * - * Hence, the only field that must be thread-safe is mEnabled, which is called at the beginning - * of every method. - */ /** - * TODO(b/123577059): add javadocs / implement + * TODO(b/123577059): add javadocs / mention it can be null */ @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE) public final class ContentCaptureManager { @@ -85,12 +81,81 @@ public final class ContentCaptureManager { public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled"; + /** + * Maximum number of events that are buffered before sent to the app. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE = "max_buffer_size"; + + /** + * Frequency (in ms) of buffer flushes when no events are received. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY = "idle_flush_frequency"; + + /** + * Frequency (in ms) of buffer flushes when no events are received and the last one was a + * text change event. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY = + "text_change_flush_frequency"; + + /** + * Size of events that are logging on {@code dump}. + * + * <p>Set it to {@code 0} or less to disable history. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE = "log_history_size"; + + /** + * Sets the logging level for {@code logcat} statements. + * + * <p>Valid values are: {@link #LOGGING_LEVEL_OFF}, {@value #LOGGING_LEVEL_DEBUG}, and + * {@link #LOGGING_LEVEL_VERBOSE}. + * + * @hide + */ + @TestApi + public static final String DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL = "logging_level"; + + + /** @hide */ + @TestApi + public static final int LOGGING_LEVEL_OFF = 0; + + /** @hide */ + @TestApi + public static final int LOGGING_LEVEL_DEBUG = 1; + + /** @hide */ + @TestApi + public static final int LOGGING_LEVEL_VERBOSE = 2; + + /** @hide */ + @IntDef(flag = false, value = { + LOGGING_LEVEL_OFF, + LOGGING_LEVEL_DEBUG, + LOGGING_LEVEL_VERBOSE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface LoggingLevel {} + private final Object mLock = new Object(); @NonNull private final Context mContext; - @Nullable + @NonNull private final IContentCaptureManager mService; // Flags used for starting session. @@ -107,11 +172,17 @@ public final class ContentCaptureManager { /** @hide */ public ContentCaptureManager(@NonNull Context context, - @Nullable IContentCaptureManager service) { + @NonNull IContentCaptureManager service) { mContext = Preconditions.checkNotNull(context, "context cannot be null"); - if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName()); + mService = Preconditions.checkNotNull(service, "service cannot be null"); + + // TODO(b/123096662): right now we're reading the device config values here, but ideally + // it should be read on ContentCaptureManagerService and passed back when the activity + // started. + ContentCaptureHelper.setLoggingLevel(); + + if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName()); - mService = service; // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we // do, then we should optimize it to run the tests after the Choreographer finishes the most // important steps of the frame. @@ -133,7 +204,7 @@ public final class ContentCaptureManager { synchronized (mLock) { if (mMainSession == null) { mMainSession = new MainContentCaptureSession(mContext, this, mHandler, mService); - if (VERBOSE) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession); + if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession); } return mMainSession; } @@ -199,8 +270,6 @@ public final class ContentCaptureManager { * </ul> */ public boolean isContentCaptureEnabled() { - if (mService == null) return false; - final MainContentCaptureSession mainSession; synchronized (mLock) { mainSession = mMainSession; @@ -219,7 +288,7 @@ public final class ContentCaptureManager { * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}. */ public void setContentCaptureEnabled(boolean enabled) { - if (DEBUG) { + if (sDebug) { Log.d(TAG, "setContentCaptureEnabled(): setting to " + enabled + " for " + mContext); } @@ -242,8 +311,6 @@ public final class ContentCaptureManager { @SystemApi @TestApi public boolean isContentCaptureFeatureEnabled() { - if (mService == null) return false; - final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); final int resultCode; try { @@ -275,7 +342,7 @@ public final class ContentCaptureManager { @SystemApi @TestApi public void setContentCaptureFeatureEnabled(boolean enabled) { - if (DEBUG) Log.d(TAG, "setContentCaptureFeatureEnabled(): setting to " + enabled); + if (sDebug) Log.d(TAG, "setContentCaptureFeatureEnabled(): setting to " + enabled); final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); final int resultCode; @@ -314,22 +381,23 @@ public final class ContentCaptureManager { /** @hide */ public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.println("ContentCaptureManager"); + final String prefix2 = prefix + " "; synchronized (mLock) { - pw.print(prefix); pw.println("ContentCaptureManager"); - pw.print(prefix); pw.print("isContentCaptureEnabled(): "); + pw.print(prefix2); pw.print("isContentCaptureEnabled(): "); pw.println(isContentCaptureEnabled()); + pw.print(prefix); pw.print("Debug: "); pw.print(sDebug); + pw.print(" Verbose: "); pw.println(sVerbose); pw.print(prefix); pw.print("Context: "); pw.println(mContext); pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId()); - if (mService != null) { - pw.print(prefix); pw.print("Service: "); pw.println(mService); - } + pw.print(prefix); pw.print("Service: "); pw.println(mService); pw.print(prefix); pw.print("Flags: "); pw.println(mFlags); if (mMainSession != null) { - final String prefix2 = prefix + " "; - pw.print(prefix); pw.println("Main session:"); - mMainSession.dump(prefix2, pw); + final String prefix3 = prefix2 + " "; + pw.print(prefix2); pw.println("Main session:"); + mMainSession.dump(prefix3, pw); } else { - pw.print(prefix); pw.println("No sessions"); + pw.print(prefix2); pw.println("No sessions"); } } } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index b8d3fa6f4404..1e051a43a42f 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -15,8 +15,8 @@ */ package android.view.contentcapture; -import static android.view.contentcapture.ContentCaptureHelper.DEBUG; -import static android.view.contentcapture.ContentCaptureHelper.VERBOSE; +import static android.view.contentcapture.ContentCaptureHelper.sDebug; +import static android.view.contentcapture.ContentCaptureHelper.sVerbose; import android.annotation.CallSuper; import android.annotation.IntDef; @@ -120,6 +120,13 @@ public abstract class ContentCaptureSession implements AutoCloseable { */ public static final int STATE_INTERNAL_ERROR = 0x100; + /** + * Session is disabled because service didn't whitelist package. + * + * @hide + */ + public static final int STATE_PACKAGE_NOT_WHITELISTED = 0x200; + private static final int INITIAL_CHILDREN_CAPACITY = 5; /** @hide */ @@ -233,7 +240,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { public final ContentCaptureSession createContentCaptureSession( @NonNull ContentCaptureContext context) { final ContentCaptureSession child = newChild(context); - if (DEBUG) { + if (sDebug) { Log.d(TAG, "createContentCaptureSession(" + context + ": parent=" + mId + ", child=" + child.mId); } @@ -285,20 +292,20 @@ public abstract class ContentCaptureSession implements AutoCloseable { public final void destroy() { synchronized (mLock) { if (mDestroyed) { - if (DEBUG) Log.d(TAG, "destroy(" + mId + "): already destroyed"); + if (sDebug) Log.d(TAG, "destroy(" + mId + "): already destroyed"); return; } mDestroyed = true; // TODO(b/111276913): check state (for example, how to handle if it's waiting for remote // id) and send it to the cache of batched commands - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId); } // Finish children first if (mChildren != null) { final int numberChildren = mChildren.size(); - if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first"); + if (sVerbose) Log.v(TAG, "Destroying " + numberChildren + " children first"); for (int i = 0; i < numberChildren; i++) { final ContentCaptureSession child = mChildren.get(i); try { diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index d949f45ba5e6..f4021b11f317 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -23,9 +23,13 @@ import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_START import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED; -import static android.view.contentcapture.ContentCaptureHelper.DEBUG; -import static android.view.contentcapture.ContentCaptureHelper.VERBOSE; +import static android.view.contentcapture.ContentCaptureHelper.getIntDeviceConfigProperty; import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString; +import static android.view.contentcapture.ContentCaptureHelper.sDebug; +import static android.view.contentcapture.ContentCaptureHelper.sVerbose; +import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY; +import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE; +import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE; import android.annotation.NonNull; import android.annotation.Nullable; @@ -64,6 +68,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { private static final String TAG = MainContentCaptureSession.class.getSimpleName(); + // For readability purposes... private static final boolean FORCE_FLUSH = true; /** @@ -71,17 +76,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession { */ private static final int MSG_FLUSH = 1; - /** - * Maximum number of events that are buffered before sent to the app. - */ - // TODO(b/121044064): use settings - private static final int MAX_BUFFER_SIZE = 100; - - /** - * Frequency the buffer is flushed if stale. - */ - // TODO(b/121044064): use settings - private static final int FLUSHING_FREQUENCY_MS = 5_000; + private static final int DEFAULT_MAX_BUFFER_SIZE = 100; + private static final int DEFAULT_FLUSHING_FREQUENCY_MS = 5_000; + private static final int DEFAULT_LOG_HISTORY_SIZE = 10; /** * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service. @@ -105,14 +102,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { * Interface to the system_server binder object - it's only used to start the session (and * notify when the session is finished). */ - @Nullable // TODO(b/122959591): shoul never be null, we should make main session null instead + @NonNull private final IContentCaptureManager mSystemServerInterface; /** * Direct interface to the service binder object - it's used to send the events, including the * last ones (when the session is finished) */ - @Nullable + @NonNull private IContentCaptureDirectManager mDirectServiceInterface; @Nullable private DeathRecipient mDirectServiceVulture; @@ -131,20 +128,42 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @Nullable private ArrayList<ContentCaptureEvent> mEvents; + /** + * Maximum number of events that are buffered before sent to the app. + */ + private final int mMaxBufferSize; + + /** + * Frequency the buffer is flushed if idle. + */ + private final int mIdleFlushingFrequencyMs; + // Used just for debugging purposes (on dump) private long mNextFlush; - // TODO(b/121044064): use settings to set size - private final LocalLog mFlushHistory = new LocalLog(10); + @Nullable + private final LocalLog mFlushHistory; /** @hide */ protected MainContentCaptureSession(@NonNull Context context, @NonNull ContentCaptureManager manager, @NonNull Handler handler, - @Nullable IContentCaptureManager systemServerInterface) { + @NonNull IContentCaptureManager systemServerInterface) { mContext = context; mManager = manager; mHandler = handler; mSystemServerInterface = systemServerInterface; + + // TODO(b/123096662): right now we're reading the device config values here, but ideally + // it should be read on ContentCaptureManagerService and passed back when the activity + // started. + mMaxBufferSize = getIntDeviceConfigProperty(DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE, + DEFAULT_MAX_BUFFER_SIZE); + mIdleFlushingFrequencyMs = getIntDeviceConfigProperty( + DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY, DEFAULT_FLUSHING_FREQUENCY_MS); + final int logHistorySize = getIntDeviceConfigProperty( + DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, DEFAULT_LOG_HISTORY_SIZE); + + mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null; } @Override @@ -169,14 +188,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { int flags) { if (!isContentCaptureEnabled()) return; - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "start(): token=" + token + ", comp=" + ComponentName.flattenToShortString(component)); } if (hasStarted()) { // TODO(b/122959591): make sure this is expected (and when), or use Log.w - if (DEBUG) { + if (sDebug) { Log.d(TAG, "ignoring handleStartSession(" + token + "/" + ComponentName.flattenToShortString(component) + " while on state " + getStateAsString(mState)); @@ -187,14 +206,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { mApplicationToken = token; mComponentName = component; - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "handleStartSession(): token=" + token + ", act=" + getDebugState() + ", id=" + mId); } try { - if (mSystemServerInterface == null) return; - mSystemServerInterface.startSession(mApplicationToken, component, mId, flags, new IResultReceiver.Stub() { @Override @@ -254,7 +271,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { mState = resultCode; mDisabled.set(false); } - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "handleSessionStarted() result: id=" + mId + " resultCode=" + resultCode + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get() + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size())); @@ -269,7 +286,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @UiThread private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { final int eventType = event.getType(); - if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event); + if (sVerbose) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event); if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED && eventType != ContentCaptureEvent.TYPE_CONTEXT_UPDATED) { // TODO(b/120494182): comment when this could happen (dialogs?) @@ -282,14 +299,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // This happens when the event was queued in the handler before the sesison was ready, // then handleSessionStarted() returned and set it as disabled - we need to drop it, // otherwise it will keep triggering handleScheduleFlush() - if (VERBOSE) Log.v(TAG, "handleSendEvent(): ignoring when disabled"); + if (sVerbose) Log.v(TAG, "handleSendEvent(): ignoring when disabled"); return; } if (mEvents == null) { - if (VERBOSE) { - Log.v(TAG, "handleSendEvent(): creating buffer for " + MAX_BUFFER_SIZE + " events"); + if (sVerbose) { + Log.v(TAG, "handleSendEvent(): creating buffer for " + mMaxBufferSize + " events"); } - mEvents = new ArrayList<>(MAX_BUFFER_SIZE); + mEvents = new ArrayList<>(mMaxBufferSize); } // Some type of events can be merged together @@ -301,7 +318,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // TODO(b/121045053): check if flags match if (lastEvent.getType() == TYPE_VIEW_TEXT_CHANGED && lastEvent.getId().equals(event.getId())) { - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text=" + getSanitizedString(event.getText())); } @@ -315,7 +332,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1); if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED && event.getSessionId().equals(lastEvent.getSessionId())) { - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session " + lastEvent.getSessionId()); } @@ -330,20 +347,20 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final int numberEvents = mEvents.size(); - final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE; + final boolean bufferEvent = numberEvents < mMaxBufferSize; if (bufferEvent && !forceFlush) { scheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true); return; } - if (mState != STATE_ACTIVE && numberEvents >= MAX_BUFFER_SIZE) { + if (mState != STATE_ACTIVE && numberEvents >= mMaxBufferSize) { // Callback from startSession hasn't been called yet - typically happens on system // apps that are started before the system service // TODO(b/122959591): try to ignore session while system is not ready / boot // not complete instead. Similarly, the manager service should return right away // when the user does not have a service set - if (DEBUG) { + if (sDebug) { Log.d(TAG, "Closing session for " + getDebugState() + " after " + numberEvents + " delayed events"); } @@ -398,12 +415,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @UiThread private void scheduleFlush(@FlushReason int reason, boolean checkExisting) { - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason) + ", checkExisting=" + checkExisting); } if (!hasStarted()) { - if (VERBOSE) Log.v(TAG, "handleScheduleFlush(): session not started yet"); + if (sVerbose) Log.v(TAG, "handleScheduleFlush(): session not started yet"); return; } @@ -418,19 +435,19 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // "Renew" the flush message by removing the previous one mHandler.removeMessages(MSG_FLUSH); } - mNextFlush = System.currentTimeMillis() + FLUSHING_FREQUENCY_MS; - if (VERBOSE) { + mNextFlush = System.currentTimeMillis() + mIdleFlushingFrequencyMs; + if (sVerbose) { Log.v(TAG, "handleScheduleFlush(): scheduled to flush in " - + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush)); + + mIdleFlushingFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush)); } // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage() - mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, FLUSHING_FREQUENCY_MS); + mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, mIdleFlushingFrequencyMs); } @UiThread private void flushIfNeeded(@FlushReason int reason) { if (mEvents == null || mEvents.isEmpty()) { - if (VERBOSE) Log.v(TAG, "Nothing to flush"); + if (sVerbose) Log.v(TAG, "Nothing to flush"); return; } flush(reason); @@ -448,7 +465,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } if (mDirectServiceInterface == null) { - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "handleForceFlush(" + getDebugState(reason) + "): hold your horses, " + "client not ready: " + mEvents); } @@ -460,14 +477,16 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final int numberEvents = mEvents.size(); final String reasonString = getflushReasonAsString(reason); - if (DEBUG) { + if (sDebug) { Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason)); } - // Logs reason, size, max size, idle timeout - final String logRecord = "r=" + reasonString + " s=" + numberEvents - + " m=" + MAX_BUFFER_SIZE + " i=" + FLUSHING_FREQUENCY_MS; - try { + if (mFlushHistory != null) { + // Logs reason, size, max size, idle timeout + final String logRecord = "r=" + reasonString + " s=" + numberEvents + + " m=" + mMaxBufferSize + " i=" + mIdleFlushingFrequencyMs; mFlushHistory.log(logRecord); + } + try { mHandler.removeMessages(MSG_FLUSH); final ParceledListSlice<ContentCaptureEvent> events = clearEvents(); @@ -500,15 +519,13 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @UiThread private void destroySession() { - if (DEBUG) { + if (sDebug) { Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with " + (mEvents == null ? 0 : mEvents.size()) + " event(s) for " + getDebugState()); } try { - if (mSystemServerInterface == null) return; - mSystemServerInterface.finishSession(mId); } catch (RemoteException e) { Log.e(TAG, "Error destroying system-service session " + mId + " for " @@ -520,7 +537,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // clearings out. @UiThread private void resetSession(int newState) { - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "handleResetSession(" + getActivityName() + "): from " + getStateAsString(mState) + " to " + getStateAsString(newState)); } @@ -628,12 +645,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @Override void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + super.dump(prefix, pw); + pw.print(prefix); pw.print("mContext: "); pw.println(mContext); pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId()); - if (mSystemServerInterface != null) { - pw.print(prefix); pw.print("mSystemServerInterface: "); - pw.println(mSystemServerInterface); - } + pw.print(prefix); pw.print("mSystemServerInterface: "); if (mDirectServiceInterface != null) { pw.print(prefix); pw.print("mDirectServiceInterface: "); pw.println(mDirectServiceInterface); @@ -651,8 +667,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (mEvents != null && !mEvents.isEmpty()) { final int numberEvents = mEvents.size(); pw.print(prefix); pw.print("buffered events: "); pw.print(numberEvents); - pw.print('/'); pw.println(MAX_BUFFER_SIZE); - if (VERBOSE && numberEvents > 0) { + pw.print('/'); pw.println(mMaxBufferSize); + if (sVerbose && numberEvents > 0) { final String prefix3 = prefix + " "; for (int i = 0; i < numberEvents; i++) { final ContentCaptureEvent event = mEvents.get(i); @@ -660,13 +676,17 @@ public final class MainContentCaptureSession extends ContentCaptureSession { pw.println(); } } - pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS); + pw.print(prefix); pw.print("flush frequency: "); pw.println(mIdleFlushingFrequencyMs); pw.print(prefix); pw.print("next flush: "); TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw); pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")"); } - pw.print(prefix); pw.println("flush history:"); - mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println(); + if (mFlushHistory != null) { + pw.print(prefix); pw.println("flush history:"); + mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println(); + } else { + pw.print(prefix); pw.println("not logging flush history"); + } super.dump(prefix, pw); } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 29f070ed5a65..8113b40eaee0 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -199,7 +199,9 @@ public class ProgressBar extends View { private boolean mMaxInitialized; private int mBehavior; - @UnsupportedAppUsage + // Better to define a Drawable that implements Animatable if you want to modify animation + // characteristics programatically. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052713) private int mDuration; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean mIndeterminate; @@ -284,7 +286,6 @@ public class ProgressBar extends View { } } - mDuration = a.getInt(R.styleable.ProgressBar_indeterminateDuration, mDuration); mMinWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_minWidth, mMinWidth); @@ -709,7 +710,17 @@ public class ProgressBar extends View { /** * Define the drawable used to draw the progress bar in indeterminate mode. * + * <p>For the Drawable to animate, it must implement {@link Animatable}, or override + * {@link Drawable#onLevelChange(int)}. A Drawable that implements Animatable will be animated + * via that interface and therefore provides the greatest amount of customization. A Drawable + * that only overrides onLevelChange(int) is animated directly by ProgressBar and only the + * animation {@link android.R.styleable#ProgressBar_indeterminateDuration duration}, + * {@link android.R.styleable#ProgressBar_indeterminateBehavior repeating behavior}, and + * {@link #setInterpolator(Interpolator) interpolator} can be modified, and only before the + * indeterminate animation begins. + * * @param d the new drawable + * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable * @see #getIndeterminateDrawable() * @see #setIndeterminate(boolean) */ @@ -1774,10 +1785,21 @@ public class ProgressBar extends View { /** * Sets the acceleration curve for the indeterminate animation. - * The interpolator is loaded as a resource from the specified context. + * + * <p>The interpolator is loaded as a resource from the specified context. Defaults to a linear + * interpolation. + * + * <p>The interpolator only affects the indeterminate animation if the + * {@link #setIndeterminateDrawable(Drawable) supplied indeterminate drawable} does not + * implement {@link Animatable}. + * + * <p>This call must be made before the indeterminate animation starts for it to have an affect. * * @param context The application environment * @param resID The resource identifier of the interpolator to load + * @attr ref android.R.styleable#ProgressBar_interpolator + * @see #setInterpolator(Interpolator) + * @see #getInterpolator() */ public void setInterpolator(Context context, @InterpolatorRes int resID) { setInterpolator(AnimationUtils.loadInterpolator(context, resID)); @@ -1787,7 +1809,17 @@ public class ProgressBar extends View { * Sets the acceleration curve for the indeterminate animation. * Defaults to a linear interpolation. * + * <p>The interpolator only affects the indeterminate animation if the + * {@link #setIndeterminateDrawable(Drawable) supplied indeterminate drawable} does not + * implement {@link Animatable}. + * + * <p>This call must be made before the indeterminate animation starts for it to have + * an affect. + * * @param interpolator The interpolator which defines the acceleration curve + * @attr ref android.R.styleable#ProgressBar_interpolator + * @see #setInterpolator(Context, int) + * @see #getInterpolator() */ public void setInterpolator(Interpolator interpolator) { mInterpolator = interpolator; @@ -1797,6 +1829,9 @@ public class ProgressBar extends View { * Gets the acceleration curve type for the indeterminate animation. * * @return the {@link Interpolator} associated to this animation + * @attr ref android.R.styleable#ProgressBar_interpolator + * @see #setInterpolator(Context, int) + * @see #setInterpolator(Interpolator) */ @InspectableProperty public Interpolator getInterpolator() { diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index eef40e1f6e2e..d037337d4546 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -95,7 +95,7 @@ public class Toast { public static final int LENGTH_LONG = 1; final Context mContext; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final TN mTN; @UnsupportedAppUsage int mDuration; @@ -354,7 +354,7 @@ public class Toast { } private static class TN extends ITransientNotification.Stub { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); private static final int SHOW = 0; @@ -362,18 +362,18 @@ public class Toast { private static final int CANCEL = 2; final Handler mHandler; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) int mGravity; int mX; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) int mY; float mHorizontalMargin; float mVerticalMargin; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) View mView; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) View mNextView; int mDuration; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index fbf80914e2f1..2009fd50137a 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -623,7 +623,14 @@ public class ChooserActivity extends ResolverActivity { private FileInfo extractFileInfo(Uri uri, ContentResolver resolver) { String fileName = null; boolean hasThumbnail = false; - Cursor cursor = resolver.query(uri, null, null, null, null); + Cursor cursor = null; + + try { + cursor = resolver.query(uri, null, null, null, null); + } catch (SecurityException e) { + Log.w(TAG, "Error loading file preview", e); + } + if (cursor != null && cursor.getCount() > 0) { int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); int flagsIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAGS); @@ -655,46 +662,50 @@ public class ChooserActivity extends ResolverActivity { // due to permissions issues findViewById(R.id.file_copy_button).setVisibility(View.GONE); - try { - ContentResolver resolver = getContentResolver(); - TextView fileNameView = findViewById(R.id.content_preview_filename); - String action = targetIntent.getAction(); - if (Intent.ACTION_SEND.equals(action)) { - Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); - - FileInfo fileInfo = extractFileInfo(uri, resolver); - fileNameView.setText(fileInfo.name); + String action = targetIntent.getAction(); + if (Intent.ACTION_SEND.equals(action)) { + Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + loadFileUriIntoView(uri); + } else { + List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + int uriCount = uris.size(); - if (fileInfo.hasThumbnail) { - loadUriIntoView(R.id.content_preview_file_thumbnail, uri); - } else { - ImageView fileIconView = findViewById(R.id.content_preview_file_icon); - fileIconView.setVisibility(View.VISIBLE); - fileIconView.setImageResource(R.drawable.ic_doc_generic); - } + if (uriCount == 0) { + contentPreviewLayout.setVisibility(View.GONE); + Log.i(TAG, + "Appears to be no uris available in EXTRA_STREAM, removing " + + "preview area"); + return; + } else if (uriCount == 1) { + loadFileUriIntoView(uris.get(0)); } else { - List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); - if (uris.size() == 0) { - contentPreviewLayout.setVisibility(View.GONE); - Log.i(TAG, - "Appears to be no uris available in EXTRA_STREAM, removing preview " - + "area"); - return; - } - - FileInfo fileInfo = extractFileInfo(uris.get(0), resolver); - int remFileCount = uris.size() - 1; + FileInfo fileInfo = extractFileInfo(uris.get(0), getContentResolver()); + int remUriCount = uriCount - 1; String fileName = getResources().getQuantityString(R.plurals.file_count, - remFileCount, fileInfo.name, remFileCount); + remUriCount, fileInfo.name, remUriCount); + TextView fileNameView = findViewById(R.id.content_preview_filename); fileNameView.setText(fileName); + ImageView fileIconView = findViewById(R.id.content_preview_file_icon); fileIconView.setVisibility(View.VISIBLE); fileIconView.setImageResource(R.drawable.ic_file_copy); } - } catch (SecurityException e) { - Log.w(TAG, "Error loading file preview", e); - contentPreviewLayout.setVisibility(View.GONE); + } + } + + private void loadFileUriIntoView(Uri uri) { + FileInfo fileInfo = extractFileInfo(uri, getContentResolver()); + + TextView fileNameView = findViewById(R.id.content_preview_filename); + fileNameView.setText(fileInfo.name); + + if (fileInfo.hasThumbnail) { + loadUriIntoView(R.id.content_preview_file_thumbnail, uri); + } else { + ImageView fileIconView = findViewById(R.id.content_preview_file_icon); + fileIconView.setVisibility(View.VISIBLE); + fileIconView.setImageResource(R.drawable.ic_doc_generic); } } diff --git a/core/java/com/android/internal/os/BackgroundThread.java b/core/java/com/android/internal/os/BackgroundThread.java index eada142dd3c6..22c832e0689c 100644 --- a/core/java/com/android/internal/os/BackgroundThread.java +++ b/core/java/com/android/internal/os/BackgroundThread.java @@ -17,10 +17,13 @@ package com.android.internal.os; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.Looper; import android.os.Trace; +import java.util.concurrent.Executor; + /** * Shared singleton background thread for each process. */ @@ -29,6 +32,7 @@ public final class BackgroundThread extends HandlerThread { private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000; private static BackgroundThread sInstance; private static Handler sHandler; + private static HandlerExecutor sHandlerExecutor; private BackgroundThread() { super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND); @@ -43,6 +47,7 @@ public final class BackgroundThread extends HandlerThread { looper.setSlowLogThresholdMs( SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); sHandler = new Handler(sInstance.getLooper()); + sHandlerExecutor = new HandlerExecutor(sHandler); } } @@ -59,4 +64,11 @@ public final class BackgroundThread extends HandlerThread { return sHandler; } } + + public static Executor getExecutor() { + synchronized (BackgroundThread.class) { + ensureThreadLocked(); + return sHandlerExecutor; + } + } } diff --git a/core/java/com/android/server/backup/PermissionBackupHelper.java b/core/java/com/android/server/backup/PermissionBackupHelper.java index c0ba18159639..c7c423b82cf1 100644 --- a/core/java/com/android/server/backup/PermissionBackupHelper.java +++ b/core/java/com/android/server/backup/PermissionBackupHelper.java @@ -16,11 +16,14 @@ package com.android.server.backup; -import android.app.AppGlobals; +import android.annotation.NonNull; import android.app.backup.BlobBackupHelper; -import android.content.pm.IPackageManager; +import android.os.UserHandle; +import android.permission.PermissionManagerInternal; import android.util.Slog; +import com.android.server.LocalServices; + public class PermissionBackupHelper extends BlobBackupHelper { private static final String TAG = "PermissionBackup"; private static final boolean DEBUG = false; @@ -31,24 +34,26 @@ public class PermissionBackupHelper extends BlobBackupHelper { // key under which the permission-grant state blob is committed to backup private static final String KEY_PERMISSIONS = "permissions"; - private final int mUserId; + private final @NonNull UserHandle mUser; + + private final @NonNull PermissionManagerInternal mPermissionManager; public PermissionBackupHelper(int userId) { super(STATE_VERSION, KEY_PERMISSIONS); - mUserId = userId; + mUser = UserHandle.of(userId); + mPermissionManager = LocalServices.getService(PermissionManagerInternal.class); } @Override protected byte[] getBackupPayload(String key) { - IPackageManager pm = AppGlobals.getPackageManager(); if (DEBUG) { Slog.d(TAG, "Handling backup of " + key); } try { switch (key) { case KEY_PERMISSIONS: - return pm.getPermissionGrantBackup(mUserId); + return mPermissionManager.backupRuntimePermissions(mUser); default: Slog.w(TAG, "Unexpected backup key " + key); @@ -61,14 +66,13 @@ public class PermissionBackupHelper extends BlobBackupHelper { @Override protected void applyRestoredPayload(String key, byte[] payload) { - IPackageManager pm = AppGlobals.getPackageManager(); if (DEBUG) { Slog.d(TAG, "Handling restore of " + key); } try { switch (key) { case KEY_PERMISSIONS: - pm.restorePermissionGrants(payload, mUserId); + mPermissionManager.restoreRuntimePermissions(payload, mUser); break; default: diff --git a/core/jni/Android.bp b/core/jni/Android.bp index af0b7c307ef6..74061367804e 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -230,6 +230,7 @@ cc_library_shared { ], static_libs: [ + "libasync_safe", "libgif", "libseccomp_policy", "libgrallocusage", diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index a2ed7d3391ed..bd998999ce63 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -1918,7 +1918,6 @@ static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobjec for (jint i = 0; i < nb; i++) { deviceTypesVector.push_back((audio_devices_t) typesPtr[i]); } - env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0); // check each address is a string and add device type/address to list for device affinity Vector<AudioDeviceTypeAddr> deviceVector; @@ -1932,6 +1931,7 @@ static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobjec AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address); deviceVector.add(dev); } + env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0); status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector); return (jint) nativeToJavaStatus(status); diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index 95f99b760382..0ccc327f6d97 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -34,13 +34,16 @@ void setDriverPath(JNIEnv* env, jobject clazz, jstring path) { void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName, jstring driverVersionName, jlong driverVersionCode, - jstring appPackageName) { + jstring driverBuildDate, jstring appPackageName) { ScopedUtfChars driverPackageNameChars(env, driverPackageName); ScopedUtfChars driverVersionNameChars(env, driverVersionName); + ScopedUtfChars driverBuildDateChars(env, driverBuildDate); ScopedUtfChars appPackageNameChars(env, appPackageName); android::GraphicsEnv::getInstance().setGpuStats(driverPackageNameChars.c_str(), driverVersionNameChars.c_str(), - driverVersionCode, appPackageNameChars.c_str()); + driverVersionCode, + driverBuildDateChars.c_str(), + appPackageNameChars.c_str()); } void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring devOptIn, @@ -84,7 +87,7 @@ void setDebugLayersGLES_native(JNIEnv* env, jobject clazz, jstring layers) { const JNINativeMethod g_methods[] = { { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) }, { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) }, - { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) }, + { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) }, { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) }, { "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) }, { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) }, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 5cecf66a593c..7b4e4ea43415 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -25,6 +25,8 @@ #define LOG_TAG "Zygote" +#include <async_safe/log.h> + // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc #include <sys/mount.h> #include <linux/fs.h> @@ -303,27 +305,23 @@ static void SigChldHandler(int /*signal_number*/) { int saved_errno = errno; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - // Log process-death status that we care about. In general it is - // not safe to call LOG(...) from a signal handler because of - // possible reentrancy. However, we know a priori that the - // current implementation of LOG() is safe to call from a SIGCHLD - // handler in the zygote process. If the LOG() implementation - // changes its locking strategy or its use of syscalls within the - // lazy-init critical section, its use here may become unsafe. + // Log process-death status that we care about. if (WIFEXITED(status)) { - ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status)); + async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, + "Process %d exited cleanly (%d)", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status)); - if (WCOREDUMP(status)) { - ALOGI("Process %d dumped core.", pid); - } + async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, + "Process %d exited due to signal %d (%s)%s", pid, + WTERMSIG(status), strsignal(WTERMSIG(status)), + WCOREDUMP(status) ? "; core dumped" : ""); } // If the just-crashed process is the system_server, bring down zygote // so that it is restarted by init and system server will be restarted // from there. if (pid == gSystemServerPid) { - ALOGE("Exit zygote because system server (%d) has terminated", pid); + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, + "Exit zygote because system server (pid %d) has terminated", pid); kill(getpid(), SIGKILL); } @@ -336,14 +334,17 @@ static void SigChldHandler(int /*signal_number*/) { // Note that we shouldn't consider ECHILD an error because // the secondary zygote might have no children left to wait for. if (pid < 0 && errno != ECHILD) { - ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno)); + async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, + "Zygote SIGCHLD error in waitpid: %s", strerror(errno)); } if (blastulas_removed > 0) { if (write(gBlastulaPoolEventFD, &blastulas_removed, sizeof(blastulas_removed)) == -1) { // If this write fails something went terribly wrong. We will now kill // the zygote and let the system bring it back up. - ALOGE("Zygote failed to write to blastula pool event FD: %s", strerror(errno)); + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, + "Zygote failed to write to blastula pool event FD: %s", + strerror(errno)); kill(getpid(), SIGKILL); } } @@ -612,7 +613,7 @@ static void CreateDir(const std::string& dir, } } -static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) { +static void CreatePkgSandboxTarget(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) { // Create /mnt/user/0/package/<package-name> userid_t user_id = multiuser_get_user_id(uid); std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id); @@ -622,7 +623,7 @@ static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn); StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str()); - CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn); + CreateDir(pkg_sandbox_dir, 0755, uid, uid, fail_fn); } static void BindMount(const std::string& sourceDir, const std::string& targetDir, @@ -642,29 +643,98 @@ static void MountPkgSpecificDir(const std::string& mntSourceRoot, fail_fn_t fail_fn) { std::string mntSourceDir = StringPrintf("%s/Android/%s/%s", mntSourceRoot.c_str(), dirName, packageName.c_str()); - CreateDir(mntSourceDir, 0755, uid, uid, fail_fn); std::string mntTargetDir = StringPrintf("%s/Android/%s/%s", mntTargetRoot.c_str(), dirName, packageName.c_str()); - CreateDir(mntTargetDir, 0755, uid, uid, fail_fn); BindMount(mntSourceDir, mntTargetDir, fail_fn); } +static void CreateSubDirs(int dirfd, const std::string& parentDirPath, + const std::vector<std::string>& subDirs, + fail_fn_t fail_fn) { + for (auto& dirName : subDirs) { + struct stat sb; + if (TEMP_FAILURE_RETRY(fstatat(dirfd, dirName.c_str(), &sb, 0)) == 0) { + if (S_ISDIR(sb.st_mode)) { + continue; + } else if (TEMP_FAILURE_RETRY(unlinkat(dirfd, dirName.c_str(), 0)) == -1) { + fail_fn(CREATE_ERROR("Failed to unlinkat on %s/%s: %s", + parentDirPath.c_str(), dirName.c_str(), strerror(errno))); + } + } else if (errno != ENOENT) { + fail_fn(CREATE_ERROR("Failed to fstatat on %s/%s: %s", + parentDirPath.c_str(), dirName.c_str(), strerror(errno))); + } + if (TEMP_FAILURE_RETRY(mkdirat(dirfd, dirName.c_str(), 0700)) == -1) { + fail_fn(CREATE_ERROR("Failed to mkdirat on %s/%s: %s", + parentDirPath.c_str(), dirName.c_str(), strerror(errno))); + } + } +} + +static void EnsurePkgSpecificDirs(const std::string& path, + const std::vector<std::string>& packageNames, + bool createSandboxDir, + fail_fn_t fail_fn) { + std::string androidDir = StringPrintf("%s/Android", path.c_str()); + android::base::unique_fd androidFd( + open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (androidFd.get() < 0) { + if (errno == ENOENT || errno == ENOTDIR) { + if (errno == ENOTDIR && TEMP_FAILURE_RETRY(unlink(androidDir.c_str())) == -1) { + fail_fn(CREATE_ERROR("Failed to unlink %s: %s", + androidDir.c_str(), strerror(errno))); + } + if (TEMP_FAILURE_RETRY(mkdir(androidDir.c_str(), 0700)) == -1) { + fail_fn(CREATE_ERROR("Failed to mkdir %s: %s", + androidDir.c_str(), strerror(errno))); + } + androidFd.reset(open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + } -static void createPkgSpecificDirRoots(const std::string& parentDir, - bool createSandbox, - mode_t mode, uid_t uid, gid_t gid, - fail_fn_t fail_fn) { - std::string androidDir = StringPrintf("%s/Android", parentDir.c_str()); - CreateDir(androidDir, mode, uid, gid, fail_fn); - std::vector<std::string> dirs = {"data", "media", "obb"}; - if (createSandbox) { - dirs.push_back("sandbox"); + if (androidFd.get() < 0) { + fail_fn(CREATE_ERROR("Failed to open %s: %s", androidDir.c_str(), strerror(errno))); + } + } + + std::vector<std::string> dataMediaObbDirs = {"data", "media", "obb"}; + if (createSandboxDir) { + dataMediaObbDirs.push_back("sandbox"); + } + CreateSubDirs(androidFd.get(), androidDir, dataMediaObbDirs, fail_fn); + if (createSandboxDir) { + dataMediaObbDirs.pop_back(); + } + for (auto& dirName : dataMediaObbDirs) { + std::string dataDir = StringPrintf("%s/%s", androidDir.c_str(), dirName.c_str()); + android::base::unique_fd dataFd( + openat(androidFd, dirName.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (dataFd.get() < 0) { + fail_fn(CREATE_ERROR("Failed to openat %s/%s: %s", + androidDir.c_str(), dirName.c_str(), strerror(errno))); + } + CreateSubDirs(dataFd.get(), dataDir, packageNames, fail_fn); + } +} + +static void CreatePkgSandboxSource(const std::string& sandboxSource, fail_fn_t fail_fn) { + + struct stat sb; + if (TEMP_FAILURE_RETRY(stat(sandboxSource.c_str(), &sb)) == 0) { + if (S_ISDIR(sb.st_mode)) { + return; + } else if (TEMP_FAILURE_RETRY(unlink(sandboxSource.c_str())) == -1) { + fail_fn(CREATE_ERROR("Failed to unlink %s: %s", + sandboxSource.c_str(), strerror(errno))); + } + } else if (errno != ENOENT) { + fail_fn(CREATE_ERROR("Failed to stat %s: %s", + sandboxSource.c_str(), strerror(errno))); } - for (auto& dir : dirs) { - std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str()); - CreateDir(path, mode, uid, gid, fail_fn); + if (TEMP_FAILURE_RETRY(mkdir(sandboxSource.c_str(), 0700)) == -1) { + fail_fn(CREATE_ERROR("Failed to mkdir %s: %s", + sandboxSource.c_str(), strerror(errno))); } } @@ -680,21 +750,21 @@ static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames, StringAppendF(&mntTarget, "/%d", userId); } - if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) { + if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) == -1) { ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno)); continue; } - // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox} - createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn); + // Ensure /mnt/runtime/write/emulated/0/Android/{data,media,obb} + EnsurePkgSpecificDirs(mntSource, packageNames, true, fail_fn); std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s", mntSource.c_str(), sandboxId.c_str()); - CreateDir(sandboxSource, 0755, uid, uid, fail_fn); + CreatePkgSandboxSource(sandboxSource, fail_fn); BindMount(sandboxSource, mntTarget, fail_fn); - // Create /storage/emulated/0/Android/{data,media,obb} - createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn); + // Ensure /storage/emulated/0/Android/{data,media,obb} + EnsurePkgSpecificDirs(mntTarget, packageNames, false, fail_fn); for (auto& package : packageNames) { MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn); MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn); @@ -775,15 +845,14 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, userid_t user_id = multiuser_get_user_id(uid); std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package/%s", user_id, package_name.c_str()); - struct stat sb; bool sandboxAlreadyCreated = true; - if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) { + if (TEMP_FAILURE_RETRY(access(pkgSandboxDir.c_str(), F_OK)) == -1) { if (errno == ENOENT) { ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str()); sandboxAlreadyCreated = false; - CreatePkgSandbox(uid, package_name, fail_fn); + CreatePkgSandboxTarget(uid, package_name, fail_fn); } else { - fail_fn(CREATE_ERROR("Failed to lstat %s: %s", + fail_fn(CREATE_ERROR("Failed to access %s: %s", pkgSandboxDir.c_str(), strerror(errno))); } } @@ -794,7 +863,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, pkgSandboxDir.c_str(), strerror(errno))); } - if (access("/storage/obb_mount", F_OK) == 0) { + if (TEMP_FAILURE_RETRY(access("/storage/obb_mount", F_OK)) == 0) { if (mount_mode != MOUNT_EXTERNAL_INSTALLER) { remove("/storage/obb_mount"); } @@ -1384,8 +1453,8 @@ static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gi RuntimeAbort(env, __LINE__, "Bad gids array"); } - for (int gid_index = gids_num; --gids_num >= 0;) { - if (native_gid_proxy[gid_index] == AID_WAKELOCK) { + for (int gids_index = 0; gids_index < gids_num; ++gids_index) { + if (native_gid_proxy[gids_index] == AID_WAKELOCK) { gid_wakelock_found = true; break; } diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml index 949c12e7d1da..0721f6fb3802 100644 --- a/core/res/res/values-night/themes_device_defaults.xml +++ b/core/res/res/values-night/themes_device_defaults.xml @@ -65,4 +65,7 @@ easier. <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" /> <style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault" /> + + <style name="ThemeOverlay.DeviceDefault.Accent.DayNight" + parent="@style/ThemeOverlay.DeviceDefault.Accent" /> </resources>
\ No newline at end of file diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 46e14b41960c..224f54c64b63 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4349,14 +4349,18 @@ <attr name="indeterminate" format="boolean" /> <!-- Restricts to ONLY indeterminate mode (state-keeping progress mode will not work). --> <attr name="indeterminateOnly" format="boolean" /> - <!-- Drawable used for the indeterminate mode. --> + <!-- Drawable used for the indeterminate mode. One that implements Animatable offers more + control over the animation.--> <attr name="indeterminateDrawable" format="reference" /> <!-- Drawable used for the progress mode. --> <attr name="progressDrawable" format="reference" /> - <!-- Duration of the indeterminate animation. --> + <!-- Duration of the indeterminate animation. Only affects the indeterminate animation + if the indeterminate Drawable does not implement + android.graphics.drawable.Animatable. --> <attr name="indeterminateDuration" format="integer" min="1" /> - <!-- Defines how the indeterminate mode should behave when the progress - reaches max. --> + <!-- Defines how the indeterminate mode should behave when the progress reaches max. Only + affects the indeterminate animation if the indeterminate Drawable does not implement + android.graphics.drawable.Animatable. --> <attr name="indeterminateBehavior"> <!-- Progress starts over from 0. --> <enum name="repeat" value="1" /> @@ -4367,6 +4371,9 @@ <attr name="maxWidth" /> <attr name="minHeight" format="dimension" /> <attr name="maxHeight" /> + <!-- Sets the acceleration curve for the indeterminate animation. Defaults to a linear + interpolation. Only affects the indeterminate animation if the indeterminate Drawable + does not implement android.graphics.drawable.Animatable.--> <attr name="interpolator" format="reference" /> <!-- Timeout between frames of animation in milliseconds. {@deprecated Not used by the framework}. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index dae2692c7722..e65e7da57e58 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -46,6 +46,8 @@ <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item> <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item> <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item> + <item><xliff:g id="id">@string/status_bar_camera</xliff:g></item> + <item><xliff:g id="id">@string/status_bar_microphone</xliff:g></item> <item><xliff:g id="id">@string/status_bar_location</xliff:g></item> <item><xliff:g id="id">@string/status_bar_mute</xliff:g></item> <item><xliff:g id="id">@string/status_bar_volume</xliff:g></item> @@ -55,8 +57,6 @@ <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item> <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item> <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item> - <item><xliff:g id="id">@string/status_bar_microphone</xliff:g></item> - <item><xliff:g id="id">@string/status_bar_camera</xliff:g></item> <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item> </string-array> @@ -869,6 +869,9 @@ which means to get a larger screen. --> <bool name="config_lidControlsDisplayFold">false</bool> + <!-- Indicate the display area rect for foldable devices in folded state. --> + <string name="config_foldedArea"></string> + <!-- Desk dock behavior --> <!-- The number of degrees to rotate the display when the device is in a desk dock. @@ -3911,19 +3914,19 @@ <!-- See DisplayWhiteBalanceController. A float array containing a list of ambient color temperatures, in Kelvin. This array, - together with config_displayWhiteBalanceDisplayTemperatureValues, is used to generate a + together with config_displayWhiteBalanceDisplayColorTemperatures, is used to generate a lookup table used in DisplayWhiteBalanceController. This lookup table is used to map ambient color temperature readings to a target color temperature for the display. This table is optional. If used, this array must, 1) Contain at least two entries - 2) Be the same length as config_displayWhiteBalanceDisplayTemperatureValues. --> - <array name="config_displayWhiteBalanceAmbientTemperatureValues"> + 2) Be the same length as config_displayWhiteBalanceDisplayColorTemperatures. --> + <array name="config_displayWhiteBalanceAmbientColorTemperatures"> </array> <!-- See DisplayWhiteBalanceController. An array containing a list of display color temperatures, in Kelvin. See - config_displayWhiteBalanceAmbientTemperatureValues for additional details. + config_displayWhiteBalanceAmbientColorTemperatures for additional details. The same restrictions apply to this array. --> - <array name="config_displayWhiteBalanceDisplayTemperatureValues"> + <array name="config_displayWhiteBalanceDisplayColorTemperatures"> </array> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5e65605a4c65..3580dd475ab9 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2951,6 +2951,8 @@ <public-group type="style" first-id="0x010302e2"> <!-- @hide @SystemApi --> <public name="Theme.DeviceDefault.DocumentsUI" /> + <public name="Theme.DeviceDefault.DayNight" /> + <public name="ThemeOverlay.DeviceDefault.Accent.DayNight" /> </public-group> <public-group type="id" first-id="0x01020046"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 0cdf38849d8b..5948f2988bc4 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3712,7 +3712,7 @@ <string name="ext_media_browse_action">Explore</string> <!-- Notification action to transfer media [CHAR LIMIT=40] --> - <string name="ext_media_seamless_action">Seamless transfer</string> + <string name="ext_media_seamless_action">Switch output</string> <!-- Notification title when external media is missing [CHAR LIMIT=30] --> <string name="ext_media_missing_title"><xliff:g id="name" example="SD card">%s</xliff:g> missing</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 08fc36db928e..7ef5e022c1c4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3586,7 +3586,10 @@ <java-symbol type="integer" name="config_defaultRingVibrationIntensity" /> <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" /> + + <!-- For Foldables --> <java-symbol type="bool" name="config_lidControlsDisplayFold" /> + <java-symbol type="string" name="config_foldedArea" /> <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" /> <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" /> @@ -3653,7 +3656,7 @@ <java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" /> <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" /> <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" /> - <java-symbol type="array" name="config_displayWhiteBalanceAmbientTemperatureValues" /> - <java-symbol type="array" name="config_displayWhiteBalanceDisplayTemperatureValues" /> + <java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" /> + <java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" /> <java-symbol type="drawable" name="ic_action_open" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 160350878349..194c86c2fb81 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1652,6 +1652,7 @@ easier. <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" /> + <!-- DeviceDefault theme for day/night activities. --> <style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault.Light" /> <!-- Theme used for the intent picker activity. --> @@ -1697,6 +1698,10 @@ easier. <item name="colorAccent">@color/accent_device_default_light</item> </style> + <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. --> + <style name="ThemeOverlay.DeviceDefault.Accent.DayNight" + parent="@style/ThemeOverlay.DeviceDefault.Accent.Light" /> + <style name="ThemeOverlay.DeviceDefault.Dark.ActionBar.Accent" parent="ThemeOverlay.Material.Dark.ActionBar"> <item name="colorAccent">@color/accent_device_default_dark</item> </style> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index bdb63643f615..81356710cce6 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1509,6 +1509,9 @@ public final class Bitmap implements Parcelable { * Convenience method that returns the width of this bitmap divided * by the density scale factor. * + * Returns the bitmap's width multiplied by the ratio of the target density to the bitmap's + * source density + * * @param targetDensity The density of the target canvas of the bitmap. * @return The scaled width of this bitmap, according to the density scale factor. */ @@ -1520,6 +1523,9 @@ public final class Bitmap implements Parcelable { * Convenience method that returns the height of this bitmap divided * by the density scale factor. * + * Returns the bitmap's height multiplied by the ratio of the target density to the bitmap's + * source density + * * @param targetDensity The density of the target canvas of the bitmap. * @return The scaled height of this bitmap, according to the density scale factor. */ diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java index aa2917484a05..3dc884eb38ad 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -17,7 +17,6 @@ package android.security.keystore; import android.security.Credentials; -import android.security.GateKeeper; import android.security.KeyStore; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; @@ -204,7 +203,12 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } } } - + if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) { + if (mKeySizeBits != 168) { + throw new InvalidAlgorithmParameterException( + "3DES key size must be 168 bits."); + } + } if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { if (mKeySizeBits < 64) { throw new InvalidAlgorithmParameterException( diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 742813e58129..875b90b7ac65 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1647,6 +1647,10 @@ struct ResTable_overlayable_policy_header // The overlay must reside of the product partition or must have existed on the product // partition before an upgrade to overlay these resources. POLICY_PRODUCT_PARTITION = 0x00000008, + + // The overlay must be signed with the same signature as the actor of the target resource, + // which can be separate or the same as the target package with the resource. + POLICY_SIGNATURE = 0x00000010, }; uint32_t policy_flags; diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h index 8cdcc46b97fb..0289d3fd2ef7 100644 --- a/libs/hwui/thread/ThreadBase.h +++ b/libs/hwui/thread/ThreadBase.h @@ -68,10 +68,12 @@ protected: void processQueue() { mQueue.process(); } virtual bool threadLoop() override { + Looper::setForThread(mLooper); while (!exitPending()) { waitForWork(); processQueue(); } + Looper::setForThread(nullptr); return false; } diff --git a/libs/incident/proto/android/os/header.proto b/libs/incident/proto/android/os/header.proto index a84dc48b8b34..d463f87055b3 100644 --- a/libs/incident/proto/android/os/header.proto +++ b/libs/incident/proto/android/os/header.proto @@ -37,4 +37,9 @@ message IncidentHeaderProto { optional int64 id = 2; // The unique id of the statsd config. } optional StatsdConfigKey config_key = 3; + + // Details about the trigger. com.android.os.AlertTriggerDetails + // Only use bytes type here to avoid indirect dependency on atoms.proto + // And this header passes through incidentd without incidentd parsing it. + optional bytes trigger_details = 4; } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 1aeefb84129f..57a0a725fb41 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -114,6 +114,7 @@ interface ILocationManager // for reporting callback completion void locationCallbackFinished(ILocationListener listener); - // used by gts tests to verify throttling whitelist + // used by gts tests to verify whitelists String[] getBackgroundThrottlingWhitelist(); + String[] getIgnoreSettingsWhitelist(); } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index c027fd499033..586ee2a43683 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -414,6 +414,18 @@ public class LocationManager { } /** + * @hide + */ + @TestApi + public String[] getIgnoreSettingsWhitelist() { + try { + return mService.getIgnoreSettingsWhitelist(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide - hide this constructor because it has a parameter * of type ILocationManager, which is a system private class. The * right way to create an instance of this class is using the diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java index 0a9ca025e2b0..3594ee7f6a91 100644 --- a/media/java/android/media/AudioFocusInfo.java +++ b/media/java/android/media/AudioFocusInfo.java @@ -16,6 +16,7 @@ package android.media; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -29,10 +30,10 @@ import java.util.Objects; @SystemApi public final class AudioFocusInfo implements Parcelable { - private final AudioAttributes mAttributes; + private final @NonNull AudioAttributes mAttributes; private final int mClientUid; - private final String mClientId; - private final String mPackageName; + private final @NonNull String mClientId; + private final @NonNull String mPackageName; private final int mSdkTarget; private int mGainRequest; private int mLossReceived; @@ -80,13 +81,21 @@ public final class AudioFocusInfo implements Parcelable { * The audio attributes for the audio focus request. * @return non-null {@link AudioAttributes}. */ - public AudioAttributes getAttributes() { return mAttributes; } + public @NonNull AudioAttributes getAttributes() { + return mAttributes; + } - public int getClientUid() { return mClientUid; } + public int getClientUid() { + return mClientUid; + } - public String getClientId() { return mClientId; } + public @NonNull String getClientId() { + return mClientId; + } - public String getPackageName() { return mPackageName; } + public @NonNull String getPackageName() { + return mPackageName; + } /** * The type of audio focus gain request. diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java index b9731d111aa3..4e7050129058 100644 --- a/media/java/android/media/AudioFocusRequest.java +++ b/media/java/android/media/AudioFocusRequest.java @@ -225,9 +225,9 @@ public final class AudioFocusRequest { /** @hide */ public static final String KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING = "a11y_force_ducking"; - private final OnAudioFocusChangeListener mFocusListener; // may be null - private final Handler mListenerHandler; // may be null - private final AudioAttributes mAttr; // never null + private final @Nullable OnAudioFocusChangeListener mFocusListener; + private final @Nullable Handler mListenerHandler; + private final @NonNull AudioAttributes mAttr; private final int mFocusGain; private final int mFlags; diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 92afe7ede8f2..24a3a9b32f77 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.CallbackExecutor; +import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1713,12 +1714,11 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, /** * Specifies the logical microphone (for processing). * - * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*) - * @return retval OK if the call is successful, an error code otherwise. - * @hide + * @param direction Direction constant. + * @return true if sucessful. */ - public int setMicrophoneDirection(int direction) { - return native_set_microphone_direction(direction); + public boolean setMicrophoneDirection(int direction) { + return native_set_microphone_direction(direction) == 0; } /** @@ -1727,11 +1727,10 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, * * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle), * though 0 (no zoom) to 1 (maximum zoom). - * @return retval OK if the call is successful, an error code otherwise. - * @hide + * @return true if sucessful. */ - public int setMicrophoneFieldDimension(float zoom) { - return native_set_microphone_field_dimension(zoom); + public boolean setMicrophoneFieldDimension(@FloatRange(from = -1.0, to = 1.0) float zoom) { + return native_set_microphone_field_dimension(zoom) == 0; } //--------------------------------------------------------- diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java index ad25a06fabe2..5f324f7f97ed 100644 --- a/media/java/android/media/MediaHTTPConnection.java +++ b/media/java/android/media/MediaHTTPConnection.java @@ -16,6 +16,8 @@ package android.media; +import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED; + import android.annotation.UnsupportedAppUsage; import android.net.NetworkUtils; import android.os.IBinder; @@ -23,21 +25,19 @@ import android.os.StrictMode; import android.util.Log; import java.io.BufferedInputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.net.CookieHandler; -import java.net.CookieManager; -import java.net.Proxy; -import java.net.URL; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.NoRouteToHostException; import java.net.ProtocolException; +import java.net.Proxy; +import java.net.URL; import java.net.UnknownServiceException; import java.util.HashMap; import java.util.Map; - -import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED; +import java.util.concurrent.atomic.AtomicBoolean; /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @@ -67,6 +67,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // from com.squareup.okhttp.internal.http private final static int HTTP_TEMP_REDIRECT = 307; private final static int MAX_REDIRECTS = 20; + private AtomicBoolean mIsConnected = new AtomicBoolean(false); @UnsupportedAppUsage public MediaHTTPConnection() { @@ -90,6 +91,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { mAllowCrossDomainRedirect = true; mURL = new URL(uri); mHeaders = convertHeaderStringToMap(headers); + mIsConnected.set(true); } catch (MalformedURLException e) { return null; } @@ -140,7 +142,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public void disconnect() { - teardownConnection(); + if (mIsConnected.getAndSet(false)) { + (new Thread() { + @Override + public void run() { + teardownConnection(); + } + }).start(); + } mHeaders = null; mURL = null; } @@ -325,7 +334,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public int readAt(long offset, int size) { - return native_readAt(offset, size); + if (!mIsConnected.get()) { + return -1; + } + int result = native_readAt(offset, size); + if (!mIsConnected.get()) { + return -1; + } + return result; } private int readAt(long offset, byte[] data, int size) { diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java index 99201c0279bf..489e2683259e 100644 --- a/media/java/android/media/MicrophoneDirection.java +++ b/media/java/android/media/MicrophoneDirection.java @@ -16,38 +16,46 @@ package android.media; -/** - * @hide - */ +import android.annotation.FloatRange; +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + public interface MicrophoneDirection { /** - * @hide + * Don't do any directionality processing of the activated microphone(s). */ int MIC_DIRECTION_UNSPECIFIED = 0; - /** - * @hide + * Optimize capture for audio coming from the screen-side of the device. */ int MIC_DIRECTION_FRONT = 1; - /** - * @hide + * Optimize capture for audio coming from the side of the device opposite the screen. */ int MIC_DIRECTION_BACK = 2; - /** - * @hide + * Optimize capture for audio coming from an off-device microphone. */ int MIC_DIRECTION_EXTERNAL = 3; + /** @hide */ + @IntDef({ + MIC_DIRECTION_UNSPECIFIED, + MIC_DIRECTION_FRONT, + MIC_DIRECTION_BACK, + MIC_DIRECTION_EXTERNAL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Directionmode{}; /** * Specifies the logical microphone (for processing). * - * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*) - * @return retval OK if the call is successful, an error code otherwise. - * @hide + * @param direction Direction constant. + * @return true if sucessful. */ - int setMicrophoneDirection(int direction); + boolean setMicrophoneDirection(@Directionmode int direction); /** * Specifies the zoom factor (i.e. the field dimension) for the selected microphone @@ -55,8 +63,7 @@ public interface MicrophoneDirection { * * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle), * though 0 (no zoom) to 1 (maximum zoom). - * @return retval OK if the call is successful, an error code otherwise. - * @hide + * @return true if sucessful. */ - int setMicrophoneFieldDimension(float zoom); + boolean setMicrophoneFieldDimension(@FloatRange(from = -1.0, to = 1.0) float zoom); } diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp index 7acdfa1fd4a8..a71977f8cc6c 100644 --- a/packages/CaptivePortalLogin/Android.bp +++ b/packages/CaptivePortalLogin/Android.bp @@ -18,7 +18,7 @@ android_app { name: "CaptivePortalLogin", srcs: ["src/**/*.java"], sdk_version: "system_current", - certificate: "platform", + certificate: "networkstack", static_libs: [ "androidx.legacy_legacy-support-v4", "metrics-constants-protos", diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml index e15dca046006..0894ee576a2d 100644 --- a/packages/CaptivePortalLogin/AndroidManifest.xml +++ b/packages/CaptivePortalLogin/AndroidManifest.xml @@ -23,8 +23,8 @@ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> - <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" /> + <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" /> <application android:label="@string/app_name" android:usesCleartextTraffic="true" diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index c5e598d8ce46..31a3ff4a9b8f 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -221,6 +221,12 @@ public class Assistant extends NotificationAssistantService { } @Override + public Adjustment onNotificationEnqueued(StatusBarNotification sbn) { + // we use the version with channel, so this is never called. + return null; + } + + @Override public Adjustment onNotificationEnqueued(StatusBarNotification sbn, NotificationChannel channel) { if (DEBUG) Log.i(TAG, "ENQUEUED " + sbn.getKey() + " on " + channel.getId()); diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index d6565936c860..b700bf324817 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -35,11 +35,12 @@ java_library { android_app { name: "NetworkStack", sdk_version: "system_current", - certificate: "platform", + certificate: "networkstack", privileged: true, static_libs: [ "NetworkStackLib" ], + jarjar_rules: "jarjar-rules-shared.txt", manifest: "AndroidManifest.xml", required: ["NetworkStackPermissionStub"], }
\ No newline at end of file diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml index 860ebfbf6da7..047671281fcc 100644 --- a/packages/NetworkStack/AndroidManifest.xml +++ b/packages/NetworkStack/AndroidManifest.xml @@ -24,12 +24,10 @@ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> - <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <!-- Signature permission defined in NetworkStackStub --> <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" /> <!-- Send latency broadcast as current user --> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> - <uses-permission android:name="android.permission.NETWORK_STACK" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> <application diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt new file mode 100644 index 000000000000..a8c712a3336d --- /dev/null +++ b/packages/NetworkStack/jarjar-rules-shared.txt @@ -0,0 +1,19 @@ +rule com.android.internal.util.** android.net.networkstack.util.@1 + +rule android.net.shared.Inet4AddressUtils* android.net.networkstack.shared.Inet4AddressUtils@1 +rule android.net.shared.InetAddressUtils* android.net.networkstack.shared.InetAddressUtils@1 + +# Ignore DhcpResultsParcelable, but jarjar DhcpResults +# TODO: move DhcpResults into services.net and delete from here +rule android.net.DhcpResultsParcelable* @0 +rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1 +rule android.net.LocalLog* android.net.networkstack.LocalLog@1 + +# TODO: remove from framework dependencies, then remove here +rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1 +rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1 + +# Used by UidRange, which is used by framework classes such as NetworkCapabilities. +rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1 +# TODO: move TcpKeepalivePacketData to services.net and delete +rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java index 96d1a287ef09..97d26c7c9c1f 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java @@ -18,7 +18,7 @@ package android.net.dhcp; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.shared.FdEventsReader; +import android.net.util.FdEventsReader; import android.os.Handler; import android.system.Os; diff --git a/core/java/android/net/shared/FdEventsReader.java b/packages/NetworkStack/src/android/net/util/FdEventsReader.java index bffbfb115886..1380ea720d40 100644 --- a/core/java/android/net/shared/FdEventsReader.java +++ b/packages/NetworkStack/src/android/net/util/FdEventsReader.java @@ -14,14 +14,13 @@ * limitations under the License. */ -package android.net.shared; +package android.net.util; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; diff --git a/packages/NetworkStack/src/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java index 94b1e9f2e14e..4aec6b6753a6 100644 --- a/packages/NetworkStack/src/android/net/util/PacketReader.java +++ b/packages/NetworkStack/src/android/net/util/PacketReader.java @@ -18,7 +18,6 @@ package android.net.util; import static java.lang.Math.max; -import android.net.shared.FdEventsReader; import android.os.Handler; import android.system.Os; diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java index c6a207f26577..90db207c9902 100644 --- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java +++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java @@ -247,6 +247,12 @@ public class NetworkStackService extends Service { } @Override + public void notifyCaptivePortalAppFinished(int response) { + checkNetworkStackCallingPermission(); + mNm.notifyCaptivePortalAppFinished(response); + } + + @Override public void forceReevaluation(int uid) { checkNetworkStackCallingPermission(); mNm.forceReevaluation(uid); diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index b9e901b5c5e3..ec4a47930fad 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -39,9 +39,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.CaptivePortal; import android.net.ConnectivityManager; -import android.net.ICaptivePortal; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.LinkProperties; @@ -460,6 +458,13 @@ public class NetworkMonitor extends StateMachine { sendMessage(CMD_LAUNCH_CAPTIVE_PORTAL_APP); } + /** + * Notify that the captive portal app was closed with the provided response code. + */ + public void notifyCaptivePortalAppFinished(int response) { + sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response); + } + @Override protected void log(String s) { if (DBG) Log.d(TAG + "/" + mNetwork.toString(), s); @@ -671,29 +676,8 @@ public class NetworkMonitor extends StateMachine { case CMD_LAUNCH_CAPTIVE_PORTAL_APP: final Bundle appExtras = new Bundle(); // OneAddressPerFamilyNetwork is not parcelable across processes. - appExtras.putParcelable( - ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork)); - appExtras.putParcelable(ConnectivityManager.EXTRA_CAPTIVE_PORTAL, - new CaptivePortal(new ICaptivePortal.Stub() { - @Override - public void appResponse(int response) { - if (response == APP_RETURN_WANTED_AS_IS) { - mContext.enforceCallingPermission( - PERMISSION_NETWORK_SETTINGS, - "CaptivePortal"); - } - sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response); - } - - @Override - public void logEvent(int eventId, String packageName) - throws RemoteException { - mContext.enforceCallingPermission( - PERMISSION_NETWORK_SETTINGS, - "CaptivePortal"); - mCallback.logCaptivePortalLoginEvent(eventId, packageName); - } - })); + final Network network = new Network(mNetwork); + appExtras.putParcelable(ConnectivityManager.EXTRA_NETWORK, network); final CaptivePortalProbeResult probeRes = mLastPortalProbeResult; appExtras.putString(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl); if (probeRes.probeSpec != null) { @@ -702,7 +686,7 @@ public class NetworkMonitor extends StateMachine { } appExtras.putString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT, mCaptivePortalUserAgent); - mCm.startCaptivePortalApp(appExtras); + mCm.startCaptivePortalApp(network, appExtras); return HANDLED; default: return NOT_HANDLED; diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp index 4a09b3e205a6..5c7b514834cb 100644 --- a/packages/NetworkStack/tests/Android.bp +++ b/packages/NetworkStack/tests/Android.bp @@ -18,6 +18,7 @@ android_test { name: "NetworkStackTests", certificate: "platform", srcs: ["src/**/*.java"], + test_suites: ["device-tests"], resource_dirs: ["res"], static_libs: [ "android-support-test", diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java index a4a100000d12..af71ac534bf7 100644 --- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java +++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java @@ -22,6 +22,7 @@ import static android.system.OsConstants.ETH_P_ARP; import static android.system.OsConstants.ETH_P_IP; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_ICMPV6; +import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_STREAM; @@ -1017,6 +1018,7 @@ public class ApfTest { private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4; private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8; private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12; + private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13; private static final byte[] IPV4_BROADCAST_ADDRESS = {(byte) 255, (byte) 255, (byte) 255, (byte) 255}; @@ -1568,7 +1570,7 @@ public class ApfTest { // Verify IPv4 packet from another address is passed assertPass(program, ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort, - anotherDstPort, anotherSeqNum, anotherAckNum)); + anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); // Remove IPv4 keepalive filter apfFilter.removeKeepalivePacketFilter(slot1); @@ -1613,15 +1615,15 @@ public class ApfTest { // dst: 10.0.0.5, port: 12345 assertDrop(program, ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1)); + dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); // Verify IPv4 non-keepalive ack packet from the same source address is passed assertPass(program, ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum + 100, seqNum)); + dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */)); // Verify IPv4 packet from another address is passed assertPass(program, ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort, - anotherDstPort, anotherSeqNum, anotherAckNum)); + anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); // Verify IPv6 keepalive ack packet is dropped // src: 2404:0:0:0:0:0:faf2, port: 54321 @@ -1650,13 +1652,13 @@ public class ApfTest { // Verify IPv4, IPv6 packets are passed assertPass(program, ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1)); + dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); assertPass(program, ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, dstPort, srcPort, ackNum, seqNum + 1)); assertPass(program, ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort, - dstPort, anotherSeqNum, anotherAckNum)); + dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); assertPass(program, ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort, dstPort, anotherSeqNum, anotherAckNum)); @@ -1664,28 +1666,30 @@ public class ApfTest { apfFilter.shutdown(); } - private static byte[] ipv4Packet(byte[] sip, byte[] tip, int sport, - int dport, int seq, int ack) { - ByteBuffer packet = ByteBuffer.wrap(new byte[100]); + private static byte[] ipv4Packet(byte[] sip, byte[] dip, int sport, + int dport, int seq, int ack, int dataLength) { + final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN; + + ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]); + + // ether type packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP); + + // IPv4 header packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45); + packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength); + packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP); put(packet, IPV4_SRC_ADDR_OFFSET, sip); - put(packet, IPV4_DEST_ADDR_OFFSET, tip); + put(packet, IPV4_DEST_ADDR_OFFSET, dip); packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport); packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport); packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq); packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack); - return packet.array(); - } - private static byte[] ipv4Packet(byte[] sip, byte[] tip, int sport, - int dport, int seq, int ack, int dataLength) { - final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN; - - ByteBuffer packet = ByteBuffer.wrap(ipv4Packet(sip, tip, sport, dport, seq, ack)); - packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength); - // TCP header length 5, reserved 3 bits, NS=0 + // TCP header length 5(20 bytes), reserved 3 bits, NS=0 packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50); + // TCP flags: ACK set + packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10); return packet.array(); } diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index b98b0f798fe3..9a16bb77182e 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -16,8 +16,7 @@ package com.android.server.connectivity; -import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN; -import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL; +import static android.net.CaptivePortal.APP_RETURN_DISMISSED; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; @@ -41,8 +40,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.Intent; -import android.net.CaptivePortal; import android.net.ConnectivityManager; import android.net.INetworkMonitorCallbacks; import android.net.InetAddresses; @@ -54,10 +51,10 @@ import android.net.captiveportal.CaptivePortalProbeResult; import android.net.metrics.IpConnectivityLog; import android.net.util.SharedLog; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.ConditionVariable; import android.os.Handler; import android.os.SystemClock; -import android.os.UserHandle; import android.provider.Settings; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -487,19 +484,23 @@ public class NetworkMonitorTest { // Check that startCaptivePortalApp sends the expected intent. nm.launchCaptivePortalApp(); - final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mContext, timeout(HANDLER_TIMEOUT_MS).times(1)) - .startActivityAsUser(intentCaptor.capture(), eq(UserHandle.CURRENT)); - final Intent intent = intentCaptor.getValue(); - assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction()); - final Network network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); - assertEquals(TEST_NETID, network.netId); + final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class); + verify(mCm, timeout(HANDLER_TIMEOUT_MS).times(1)) + .startCaptivePortalApp(networkCaptor.capture(), bundleCaptor.capture()); + final Bundle bundle = bundleCaptor.getValue(); + final Network bundleNetwork = bundle.getParcelable(ConnectivityManager.EXTRA_NETWORK); + assertEquals(TEST_NETID, bundleNetwork.netId); + // network is passed both in bundle and as parameter, as the bundle is opaque to the + // framework and only intended for the captive portal app, but the framework needs + // the network to identify the right NetworkMonitor. + assertEquals(TEST_NETID, networkCaptor.getValue().netId); // Have the app report that the captive portal is dismissed, and check that we revalidate. setStatus(mHttpsConnection, 204); setStatus(mHttpConnection, 204); - final CaptivePortal captivePortal = intent.getParcelableExtra(EXTRA_CAPTIVE_PORTAL); - captivePortal.reportCaptivePortalDismissed(); + + nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED); verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)) .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null); } diff --git a/packages/NetworkStackPermissionStub/Android.bp b/packages/NetworkStackPermissionStub/Android.bp index 94870c919dfa..dd70cf56b51b 100644 --- a/packages/NetworkStackPermissionStub/Android.bp +++ b/packages/NetworkStackPermissionStub/Android.bp @@ -21,7 +21,7 @@ android_app { // a classes.dex. srcs: ["src/**/*.java"], platform_apis: true, - certificate: "platform", + certificate: "networkstack", privileged: true, manifest: "AndroidManifest.xml", } diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 0988cab78a49..cfc76b70275f 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-toegang"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-oudio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD oudio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Gehoortoestel"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Gekoppel aan gehoortoestel"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Gehoortoestelle"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Gekoppel aan gehoortoestelle"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Gekoppel aan media-oudio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Gekoppel aan foonoudio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Gekoppel aan lêeroordragbediener"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gebruik vir foonoudio"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gebruik vir lêeroordrag"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gebruik vir invoer"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Gebruik vir gehoortoestel"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Gebruik vir gehoortoestelle"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Bind saam"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"BIND SAAM"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Kanselleer"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android-bedryfstelsel"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Verwyderde programme"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Verwyderde programme en gebruikers"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Stelselopdaterings"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-verbinding"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Wi-Fi-warmkol"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-verbinding"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 301d6099a6a7..6e6d58fb4470 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"የሲም መዳረሻ"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"ኤችዲ ኦዲዮ፦ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"ኤችዲ ኦዲዮ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"መስሚያ አጋዥ መሣሪያ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ከመስሚያ አጋዥ መሣሪያ ጋር ተገናኝቷል"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"አጋዥ መስሚያዎች"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ከአጋዥ መስሚያዎች ጋር ተገናኝቷል"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ወደ ማህደረ መረጃ አውዲዮ ተያይዟል"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ወደ ስልክ አውዲዮ ተያይዟል"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ወደ ፋይል ዝውውር አገልጋይ ተያይዟል"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ለስልክ ድምፅ ተጠቀም"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ለፋይል ዝውውር ተጠቀም"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ለውፅአት ተጠቀም"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ለመስሚያ አጋዥ መሣሪያ ተጠቀም"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ለአጋዥ መስሚያዎች ይጠቀሙ"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"አጣምር"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"አጣምር"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ይቅር"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android ስርዓተ ክወና"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"የተወገዱ መተግበሪያዎች"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"የተወገዱ መተግበሪያዎች እና ተጠቃሚዎች"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"የሥርዓት ዝማኔዎች"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB መሰካት"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ተጓጓዥ ድረስ ነጥቦች"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ብሉቱዝ ማያያዝ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 91de9e3f693c..18d47ace8608 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"الوصول إلى شريحة SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"صوت عالي الدقة: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"صوت عالي الدقة"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"سماعة الأذن الطبية"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"تم توصيل سماعة الأذن الطبية"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"سماعات الأذن الطبية"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"تمّ التوصيل بسماعات الأذن الطبية"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"متصل بالإعدادات الصوتية للوسائط"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"متصل بالإعدادات الصوتية للهاتف"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"متصل بخادم نقل الملف"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"الاستخدام لإعدادات الهاتف الصوتية"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"استخدامه لنقل الملفات"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"استخدام للإدخال"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"استخدام سماعة الأذن الطبية"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"استخدام سماعات الأذن الطبية"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"إقران"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"إقران"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"إلغاء"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"نظام التشغيل Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"التطبيقات المزالة"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"التطبيقات والمستخدمون الذين تمت إزالتهم"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"تحديثات النظام"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"ربط USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"نقطة اتصال محمولة"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ربط البلوتوث"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index e726ae46e3a2..f865563200e1 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s মাধ্যমেদি স্বয়ংক্ৰিয়ভাৱে সংযোগ কৰা হৈছে"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ’ল"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ৰ মাধ্যমেদি সংযোগ কৰা হৈছে"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g>ৰ জৰিয়তে সংযুক্ত"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"ছাইন আপ কৰিবলৈ টিপক"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"সংযোজিত, ইণ্টাৰনেট নাই"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"ইণ্টাৰনেট সংযোগ নাই"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ছাইন ইন কৰা দৰকাৰী"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"একচেছ পইণ্ট কিছু সময়ৰ বাবে পূৰ্ণ হৈ আছে"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$sৰ যোগেৰে সংযোজিত"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> খুলি থকা হৈছে"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"সংযোগ কৰিব পৰা নগ’ল"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"ছাইন আপ সম্পূৰ্ণ কৰি থকা হৈছে…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"ছাইন আপ সম্পূৰ্ণ কৰিব পৰা নগ’ল। আকৌ চেষ্টা কৰিবলৈ টিপক।"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"ছাইন আপ সম্পূৰ্ণ হৈছে সংযোগ কৰি থকা হৈছে…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"অতি লেহেম"</string> <string name="speed_label_slow" msgid="813109590815810235">"লেহেমীয়া"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ঠিক"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ছিম প্ৰৱেশ"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"এইচ্ছডি অডিঅ’"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"শ্ৰৱণ যন্ত্ৰ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ’ল"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"শ্ৰৱণ যন্ত্ৰ"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"শ্ৰৱণ যন্ত্ৰলৈ সংযোগ কৰা হৈছে"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফ’ন অডিঅ\'ৰ লগত সংযোগ কৰা হ’ল"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল ট্ৰান্সফাৰ ছাৰ্ভাৰৰ সৈতে সংযোজিত হৈ আছে"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফ\'ন অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তৰ কৰিবলৈ ব্যৱহাৰ কৰক"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ইনপুটৰ বাবে ব্যৱহাৰ কৰক"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"শ্ৰৱণ যন্ত্ৰৰ বাবে ব্যৱহাৰ কৰক"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"শ্ৰৱণ যন্ত্ৰৰ বাবে ব্যৱহাৰ কৰক"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"যোৰা লগাওক"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"যোৰা লগাওক"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"বাতিল কৰক"</string> @@ -143,8 +136,10 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"আঁতৰোৱা এপ্সমূহ"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"আঁতৰোৱা এপ্ আৰু ব্যৱহাৰকাৰীসমূহ"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"ইউএছবি টেডাৰিং"</string> - <string name="tether_settings_title_wifi" msgid="3277144155960302049">"প\'ৰ্টেবল হ\'টস্প\'ট"</string> + <string name="tether_settings_title_wifi" msgid="3277144155960302049">"প\'ৰ্টেবল হটস্পট"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ব্লুটুথ টেডাৰিং"</string> <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"টেডাৰ কৰি থকা হৈছে"</string> <string name="tether_settings_title_all" msgid="8356136101061143841">"টেডাৰিং আৰু প\'ৰ্টেবল হটস্পট"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 4dd4817cee8a..8e6e07d17d09 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Girişi"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Qulaqlıq"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Qulaqlığa qoşuldunuz"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Eşitmə Aparatı"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Eşitmə Aparatlarına qoşuldu"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Media audioya birləşdirilib"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon audiosuna qoşulu"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Fayl transfer serverinə qoşulu"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon audiosu istifadə edin"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Fayl transferi üçün istifadə edin"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Daxiletmə üçün istifadə edin"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Qulaqlıq üçün istifadə edin"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Eşitmə Aparatları üçün istifadə edin"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Birləşdir"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"CÜTLƏNDİR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Ləğv et"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Silinmiş tətbiqlər"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Tətbiqləri və istifadəçiləri silin"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Sistem güncəllənməsi"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB Birləşmə"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portativ hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth birləşmə"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index dc5430114ba7..1cdd1fd30984 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM kartici"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD zvuk"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Slušni aparat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Povezano sa slušnim aparatom"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Slušni aparati"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Povezano sa slušnim aparatima"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano sa zvukom medija"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano sa zvukom telefona"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezano sa serverom za prenos datoteka"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Korišćenje za audio telefona"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Korišćenje za prenos datoteka"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Koristi za ulaz"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Koristi za slušni aparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Koristi za slušne aparate"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Otkaži"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Ažuriranja sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB Internet povezivanje"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosni hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth privezivanje"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 2fa2692a3bbf..1a60c3d1a531 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ да SIM-карты"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Аўдыя ў HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Аўдыя ў HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слыхавы апарат"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Падключана да слыхавога апарата"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Слыхавыя апараты"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Падключана да слыхавых апаратаў"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Падключана да аўдыё медыа"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Падключана да аўдыё тэлефона"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Падключаны да серверу перадачы файлаў"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Выкарыстоўваць для аўдыё тэлефона"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Выкарыстоўваць для перадачы файлаў"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Выкарыстоўваць для ўводу"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Выкарыстоўваць для слыхавога апарата"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Выкарыстоўваць для слыхавых апаратаў"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Падлучыць"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СПАЛУЧЫЦЬ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Скасаваць"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"АС Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Выдаленыя прыкладанні"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Выдаленыя прыкладанні і карыстальнiкi"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Абнаўленні сістэмы"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-мадэм"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Партатыўная кропка доступу"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-мадэм"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 1454118c46c0..aaedce4bf1a2 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Достъп до SIM картата"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Висококачествено аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Висококачествено аудио"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слухов апарат"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Има връзка със слуховия апарат"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Слухови апарати"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Установена е връзка със слухов апарат"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Установена е връзка с медийно аудио"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Връзка със звука на телефона"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Установена е връзка със сървър за трансфер на файлове"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Използване на телефон за аудио"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Използване на за пренос на файлове"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Да се използва за въвеждане"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Използване за слухов апарат"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Използване за слухови апарати"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Сдвояване"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СДВОЯВАНЕ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Отказ"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android (ОС)"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Премахнати приложения"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Премахнати приложения и потребители"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Системни актуализации"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Тетъринг през USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Преносима точка за достъп"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Тетъринг през Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index dbf397f10c2a..ef8dd3de56a9 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"স্বয়ংক্রিয়ভাবে %1$s এর মাধ্যমে কানেক্ট হয়েছে"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটওয়ার্কের রেটিং প্রদানকারীর মাধ্যমে অটোমেটিক কানেক্ট"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে কানেক্ট হয়েছে"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g>-এর মাধ্যমে কানেক্ট করা আছে"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s এর মাধ্যমে উপলব্ধ"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"সাইন-আপ করতে ট্যাপ করুন"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"কানেক্ট, ইন্টারনেট নেই"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"ইন্টারনেট কানেকশন নেই"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"সাইন-ইন করা দরকার"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"এই মুহূর্তে অ্যাক্সেস পয়েন্টের কোনও কানেকশন ফাঁকা নেই"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s এর মাধ্যমে কানেক্ট হয়েছে"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$s এর মাধ্যমে পাওয়া যাচ্ছে"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> খোলা হচ্ছে"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"কানেক্ট করা যায়নি"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"সাইন-আপ সম্পূর্ণ করা হচ্ছে…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"সাইন-আপ করা যায়নি। আবার চেষ্টা করতে ট্যাপ করুন।"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"সাইন-আপ করা হয়ে গেছে। কানেক্ট করা হচ্ছে…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"খুব ধীরে"</string> <string name="speed_label_slow" msgid="813109590815810235">"ধীরে"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ঠিক আছে"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"সিম -এর অ্যাক্সেস"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD অডিও: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD অডিও"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"হিয়ারিং এড"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্রবণ যন্ত্রের সাথে কানেক্ট রয়েছে"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"হিয়ারিং এড"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"হিয়ারিং এডের সাথে কানেক্ট করা হয়েছে"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিওতে কানেক্ট রয়েছে"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিওতে কানেক্ট"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল স্থানান্তর সার্ভারের সঙ্গে কানেক্ট"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ইনপুটের জন্য ব্যবহার করুন"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"শ্রবণ যন্ত্রের জন্য ব্যবহার করুন"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"হিয়ারিং এডের জন্য ব্যবহার করুন"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"যুক্ত করুন"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"যুক্ত করুন"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"বাতিল করুন"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"সরানো অ্যাপ্লিকেশানগুলি"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"সরানো অ্যাপ্লিকেশানগুলি এবং ব্যবহারকারীগণ"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB টিথারিং"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"পোর্টেবল হটস্পট"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ব্লুটুথ টিথারিং"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 272e7971e5bf..4193d5250570 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM-u"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Slušni aparat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Povezano na slušni aparat"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Slušni aparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Povezan na slušne aparate"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano sa zvukom medija"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano na zvuk telefona"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezano sa serverom za prijenos podataka"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Koristi za zvuk telefona"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Koristi za prijenos fajlova"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Koristi kao ulaz"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Koristi za slušni aparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Korištenje za slušne aparate"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Otkaži"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Ažuriranja sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Povezivanje mobitela USB-om"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prijenosna pristupna tačka"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Dijeljenje Bluetooth veze"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 5d2dd65f9824..9c3e4d94cf26 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accés a la SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Àudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Àudio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audiòfon"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"S\'ha connectat a l\'audiòfon"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Audiòfons"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"S\'ha connectat als audiòfons"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connectat a l\'àudio del mitjà"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connectat a àudio del telèfon"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connectat al servidor de transferència de fitxers"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilitza-ho per a l\'àudio del telèfon"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilitza per a la transferència de fitxers"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilitza per a entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Utilitza per a l\'audiòfon"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Utilitza per als audiòfons"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincula"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"VINCULA"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel·la"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicacions eliminades"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicacions i usuaris eliminats"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Actualitzacions del sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartició de xarxa per USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Punt d\'accés Wi-Fi"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartició de xarxa per Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 19a042ed2f6d..b6507bccce1d 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Přístup k SIM kartě"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD zvuk"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Naslouchátko"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Připojeno k naslouchátku"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Naslouchátka"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Připojeno k naslouchátkům"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Připojeno ke zvukovému médiu"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Připojeno k náhlavní soupravě"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Připojeno k serveru pro přenos dat"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Umožňuje připojení náhlavní soupravy"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Použít pro přenos souborů"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Použít pro vstup"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Použít pro naslouchátko"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Použít pro naslouchátka"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párovat"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROVAT"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Zrušit"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odebrané aplikace"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odebrané aplikace a odebraní uživatelé"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Aktualizace systému"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Připojení přes USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Přenosný hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Připojení přes Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index bde67fde480f..a870cf883590 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-adgang"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-lyd"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Høreapparat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Der er oprettet forbindelse til høreapparat"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Høreapparater"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Forbundet til høreapparater"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Forbundet til medielyd"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Forbundet til telefonlyd"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Forbundet til filoverførselsserver"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Brug til telefonlyd"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Brug til filoverførsel"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Brug til input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Anvend til høreapparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Brug til høreapparater"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Par"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCEPTÉR PARRING"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuller"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Fjernede apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Fjernede apps og brugere"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Systemopdateringer"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Netdeling via USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Netdeling via Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 543e8f86ee71..c1d502e30717 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Zugriff auf SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-Audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hörhilfe"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Mit Hörhilfe verbunden"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hörhilfen"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Mit Hörhilfen verbunden"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Verbunden mit Medien-Audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Verbunden mit Telefon-Audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Mit Dateiübertragungsserver verbunden"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Telefon-Audio verwenden"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Für Dateiübertragung verwenden"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Für Eingabe verwenden"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Für Hörhilfe verwenden"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Für Hörhilfen verwenden"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Koppeln"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPELN"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Abbrechen"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Entfernte Apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Entfernte Apps und Nutzer"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Systemupdates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-Tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Mobiler Hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-Tethering"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index f7ec12be8651..22c1b26dc2fa 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Πρόσβαση SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Ήχος HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Ήχος HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Βοήθημα ακοής"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Συνδέθηκε σε βοήθημα ακοής"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Βοηθήματα ακοής"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Έγινε σύνδεση σε βοηθήματα ακοής"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Συνδέθηκε σε ήχο πολυμέσων"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Συνδεδεμένο στον ήχο τηλεφώνου"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Συνδεδεμένο σε διακομιστή μεταφοράς αρχείων"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Χρήση για ήχο τηλεφώνου"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Χρήση για τη μεταφορά αρχείων"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Χρήση για είσοδο"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Χρήση για βοήθημα ακοής"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Χρήση για βοηθήματα ακοής"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Σύζευξη"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ΣΥΖΕΥΞΗ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Ακύρωση"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Λειτουργικό σύστημα Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Εφαρμογές που καταργήθηκαν"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Εφαρμογές και χρήστες που έχουν καταργηθεί"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Ενημερώσεις συστήματος"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Πρόσδεση USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Φορητό σημείο πρόσβασης"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Πρόσδεση Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index b9d309398d67..d4f4e5e1104a 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hearing Aid"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connected to Hearing Aid"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hearing Aids"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connected to Hearing Aids"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Use for Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Use for Hearing Aids"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"System updates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index b9d309398d67..d4f4e5e1104a 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hearing Aid"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connected to Hearing Aid"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hearing Aids"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connected to Hearing Aids"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Use for Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Use for Hearing Aids"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"System updates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index b9d309398d67..d4f4e5e1104a 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hearing Aid"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connected to Hearing Aid"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hearing Aids"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connected to Hearing Aids"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Use for Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Use for Hearing Aids"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"System updates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index b9d309398d67..d4f4e5e1104a 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hearing Aid"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connected to Hearing Aid"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hearing Aids"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connected to Hearing Aids"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Use for Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Use for Hearing Aids"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"System updates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index 2d3e8301cb1e..98b63eec19dc 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hearing Aid"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connected to Hearing Aid"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hearing Aids"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connected to Hearing Aids"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file transfer server"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Use for Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Use for Hearing Aids"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"System updates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 00f85e665112..e803abdac612 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio en HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audífonos"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectado a un audífono"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Audífonos"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Conectado a audífonos"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado al audio multimedia"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado al audio del dispositivo"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado al servidor de transferencia de archivo"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para el audio del dispositivo"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizar para la transferencia de archivos"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizar para entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar con audífonos"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Usar para audífonos"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincular"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaciones y usuarios eliminados"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Actualizaciones del sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Conexión mediante USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portátil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Conexión mediante Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index b21b7d1ead5f..293eff121b2a 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso a tarjeta SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audífonos"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectado a audífono"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Audífonos"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Conectado a audífonos"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado al audio del medio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado al audio del teléfono"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado con el servidor de transferencia de archivos"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para audio del teléfono"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Uso de la transferencia de archivos"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Usar para entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar con audífonos"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Usar con audífonos"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincular"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"VINCULAR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Usuarios y aplicaciones eliminados"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Actualizaciones del sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartir conexión por USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona Wi-Fi portátil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartir conexión por Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index fab137519725..14ac8272432f 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kaardi juurdepääs"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-heli: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-heli"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Kuuldeaparaat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Kuuldeaparaadiga ühendatud"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Kuuldeaparaadid"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Kuuldeaparaatidega ühendatud"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ühendatud meediumiheliga"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ühendatud telefoniheliga"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ühendatud failiedastuse serveriga"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Kasuta telefoniheli jaoks"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Kasutage failide edastamiseks"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Kasutage sisendi jaoks"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Kuuldeaparaadiga kasutamiseks"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Kasuta kuulmisaparaatide puhul"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Seo"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SEO"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Tühista"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Eemaldatud rakendused"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Eemaldatud rakendused ja kasutajad"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Süsteemivärskendused"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB jagamine"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Mobiilne kuumkoht"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Jagamine Bluetoothiga"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 7d3e1f3049da..04710c7bb0cb 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM txartelerako sarbidea"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Kalitate handiko audioa: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Kalitate handiko audioa"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audiofonoa"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Audiofonora konektatuta"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Audifonoak"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Audifonoetara konektatuta"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Euskarriaren audiora konektatuta"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefonoaren audiora konektatuta"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Fitxategi-transferentziako zerbitzarira konektatuta"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Erabili telefonoaren audiorako"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Erabili fitxategi-transferentziarako"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Erabili idazketarako"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Erabili audiofonorako"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Erabili audifonoak"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parekatu"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAREKATU"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Utzi"</string> @@ -121,8 +121,8 @@ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Aurikularra"</string> <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Idazteko gailua"</string> <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth gailua"</string> - <string name="bluetooth_hearingaid_left_pairing_message" msgid="7378813500862148102">"Ezkerreko audiofonoa parekatzen…"</string> - <string name="bluetooth_hearingaid_right_pairing_message" msgid="1550373802309160891">"Eskuineko audiofonoa parekatzen…"</string> + <string name="bluetooth_hearingaid_left_pairing_message" msgid="7378813500862148102">"Ezkerreko audifonoa parekatzen…"</string> + <string name="bluetooth_hearingaid_right_pairing_message" msgid="1550373802309160891">"Eskuineko audifonoa parekatzen…"</string> <string name="bluetooth_hearingaid_left_battery_level" msgid="8797811465352097562">"Ezkerrekoa. Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_hearingaid_right_battery_level" msgid="7309476148173459677">"Eskuinekoa. Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="accessibility_wifi_off" msgid="1166761729660614716">"Desaktibatuta dago Wi-Fi konexioa."</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android sistema eragilea"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Kendutako aplikazioak"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Kendutako aplikazioak eta erabiltzaileak"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Sistemaren eguneratzeak"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Konexioa partekatzea (USB)"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Sare publiko eramangarria"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Konexioa partekatzea (Bluetooth)"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 293c463334fd..8f5509255f51 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"دسترسی سیمکارت"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"صدای HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"صدای HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"سمعک"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"متصل به سمعک"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"سمعکها"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"متصل به سمعکها"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"به رسانه صوتی متصل شد"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"به تلفن صوتی متصل شد"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"به سرور انتقال فایل متصل شد"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"استفاده برای تلفن صوتی"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"استفاده برای انتقال فایل"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"استفاده برای چاپ"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"استفاده برای سمعک"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"استفاده برای سمعکها"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"مرتبطسازی"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"مرتبطسازی"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"لغو"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"سیستم عامل Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"برنامههای حذف شده"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"برنامهها و کاربران حذف شده"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"بهروزرسانیهای سیستم"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"اتصال داده با سیم USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"نقطه اتصال قابل حمل"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"اتصال اینترنت با تلفن همراه بلوتوث"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index f335eb930c1c..5802a03f1070 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kortin käyttö"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-ääni: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-ääni"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Kuulolaite"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Kuulolaite yhdistetty"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Kuulolaitteet"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Yhdistetty kuulolaitteisiin"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Yhdistetty median ääneen"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Yhdistetty puhelimen ääneen"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Yhdistetty tiedostonsiirtopalvelimeen"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Käytä puhelimen äänille"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Käytä tiedostojen siirtoon"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Käytä syöttöön"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Käytä kuulolaitteen kanssa"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Käytä kuulolaitteilla"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Muodosta laitepari"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"MUODOSTA LAITEPARI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Peruuta"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android-käyttöjärjestelmä"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Poistetut sovellukset"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Poistetut sovellukset ja käyttäjät"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Järjestelmäpäivitykset"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Jaettu yhteys USB:n kautta"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Kannettava yhteyspiste"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Jaettu Bluetooth-yhteys"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 49591039178c..ec8d6b086418 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accès à la carte SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Prothèse auditive"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connecté à la prothèse auditive"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Prothèses auditives"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connecté aux prothèses auditives"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connecté aux paramètres audio du média"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connecté à l\'audio du téléphone"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connexion au serveur de transfert de fichiers"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utiliser pour les paramètres audio du téléphone"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utiliser pour le transfert de fichiers"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utiliser comme entrée"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Utiliser avec la prothèse auditive"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Utiliser avec les prothèses auditives"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Associer"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ASSOCIER"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuler"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Système d\'exploitation Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Applications supprimées"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Applications et utilisateurs supprimés"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Mises à jour système"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Partage de connexion par USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Point d\'accès Wi-Fi mobile"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Partage connexion Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 1f071de1ac6b..0b620d80cbb2 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accès à la carte SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Assistance auditive"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connecté à la prothèse auditive"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Appareils auditifs"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connexion établie avec les appareils auditifs"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connecté aux paramètres audio du média"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connecté aux paramètres audio du téléphone"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connexion au serveur de transfert de fichiers"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utiliser pour les paramètres audio du téléphone"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utiliser pour le transfert de fichiers"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utiliser comme entrée"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Utiliser pour l\'assistance auditive"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Utiliser pour les appareils auditifs"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Associer"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ASSOCIER"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuler"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Plate-forme Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Applications supprimées"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Applications et utilisateurs supprimés"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Mises à jour du système"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Partage connexion Bluetooth par USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Point d\'accès Wi-Fi mobile"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Partage connexion Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 06faf00036dd..b4d7fcb9270f 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso á SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio en HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Audiófonos"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectouse ao audiófono"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Audiófonos"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Conectado a audiófonos"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao audio multimedia"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao audio do teléfono"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferencia de ficheiros"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilízase para o audio do teléfono"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilízase para a transferencia de ficheiros"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilízase para a entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar con audiófonos"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Utilizar para audiófonos"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sincronizar"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicacións eliminadas"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicacións e usuarios eliminados"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Actualizacións do sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Conexión compart. por USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona wifi portátil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Conexión por Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 232dea9e1f1a..97b9036157a3 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"સિમ ઍક્સેસ"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ઑડિઓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ઑડિઓ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"સાંભળવામાં સહાય આપતું યંત્ર"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"સાંભળવામાં સહાય આપતા યંત્ર સાથે કનેક્ટ કરેલ"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"શ્રવણ યંત્રો"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"શ્રવણ યંત્રો સાથે કનેક્ટ કરેલું છે"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"મીડિયા ઑડિઓ સાથે કનેક્ટ કર્યુ"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ફોન ઑડિઓ સાથે કનેક્ટ થયાં"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયાં"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ફોન ઑડિઓ માટે ઉપયોગ કરો"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ફાઇલ સ્થાનાંતર માટે ઉપયોગ કરો"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ઇનપુટ માટે ઉપયોગ કરો"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"સાંભળવામાં સહાય આપતા યંત્ર માટે ઉપયોગ કરો"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"શ્રવણ યંત્રો માટે ઉપયોગ કરો"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"જોડી"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"જોડાણ બનાવો"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"રદ કરો"</string> @@ -136,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"દૂર કરેલી ઍપ્લિકેશનો"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"દૂર કરેલી ઍપ્લિકેશનો અને વપરાશકર્તાઓ"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ટિથરિંગ"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"પોર્ટેબલ હૉટસ્પૉટ"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"બ્લૂટૂથ ટિથરિંગ"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 2f03eb1b9c3a..8b1ca93d9acd 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम ऐक्सेस"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ऑडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ऑडियो"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"सुनने में मददगार डिवाइस"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"सुनने में मददगार डिवाइस से जाेड़ा गया"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"सुनने में मदद करने वाले डिवाइस"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"सुनने में मदद करने वाले डिवाइस से कनेक्ट है"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"मीडिया ऑडियो से कनेक्ट किया गया"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"फ़ोन ऑडियो से कनेक्ट किया गया"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"फ़ाइल स्थानांतरण सर्वर से कनेक्ट किया गया"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फ़ोन ऑडियो के लिए उपयोग करें"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फ़ाइल स्थानांतरण के लिए उपयोग करें"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"इनपुट के लिए उपयोग करें"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"सुनने में मददगार डिवाइस के लिए इस्तेमाल करें"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"सुनने में मदद करने वाले डिवाइस के लिए इस्तेमाल करें"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"जोड़ें"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"जोड़ें"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द करें"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"निकाले गए ऐप्स"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ऐप्स और उपयोगकर्ताओं को निकालें"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"सिस्टम अपडेट"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"यूएसबी से टेदरिंग"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हॉटस्पॉट"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लूटूथ टेदरिंग"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index bb14b066276b..b4cbbdbf3af9 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM-u"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Slušni aparat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Povezano sa slušnim aparatom"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Slušni aparati"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Povezano sa Slušnim aparatima"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano s medijskim zvukom"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano sa telefonskim zvukom"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezano s poslužiteljem za prijenos datoteka"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Koristi za telefonski zvuk"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Koristi za prijenos datoteke"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Upotrijebi za ulaz"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Upotrebljavaj za slušni aparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Upotrijebi za Slušne aparate"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Odustani"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Ažuriranja sustava"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB dijeljenje veze"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prijen. pristupna točka"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Dijeljenje Bluetoothom veze"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 14d8c78ed6b8..589eb59d4299 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-elérés"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hallókészülék"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Csatlakoztatva a hallókészülékhez"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hallókészülékek"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Hallókészülékhez csatlakoztatva"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Csatlakoztatva az eszköz hangjához"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Csatlakoztatva a telefon hangjához"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Csatlakozva a fájlküldő szerverhez"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Felhasználás a telefon hangjához"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Felhasználás fájlátvitelre"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Használat beviteli eszközként"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Használat hallókészülékhez"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Hallókészülékkel való használat"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párosítás"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROSÍTÁS"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Mégse"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Eltávolított alkalmazások"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Eltávolított alkalmazások és felhasználók"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Rendszerfrissítések"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-megosztás"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hordozható hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth megosztása"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 28ebe4febea9..736b4c3d88c9 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM քարտի հասանելիություն"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD աուդիո՝ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD աուդիո"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Լսողական ապարատ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Միացված է լսողական ապարատին"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Լսողական ապարատ"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Լսողական ապարատը միացված է"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Միացված է մեդիա աուդիոյին"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Միացված է հեռախոսի ձայնային տվյալներին"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Միացված է ֆայլերի փոխանցման սերվերին"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Օգտագործել հեռախոսի աուդիոյի համար"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Օգտագործել ֆայլի փոխանցման համար"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Օգտագործել ներմուծման համար"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Օգտագործել լսողական ապարատի համար"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Օգտագործել լսողական ապարատի համար"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Զուգավորել"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Զուգավորել"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Չեղարկել"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Հեռացված ծրագրեր"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Հեռացված հավելվածներն ու օգտատերերը"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Համակարգի թարմացումներ"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB մոդեմ"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Դյուրակիր թեժ կետ"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth մոդեմ"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 182e52338891..c5d8f30d332f 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Akses SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Alat Bantu Dengar"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Terhubung ke Alat Bantu Dengar"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Alat Bantu Dengar"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Terhubung ke Alat Bantu Dengar"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Tersambung ke media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Tersambung ke audio ponsel"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Sambungkan ke server transfer file"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gunakan untuk audio ponsel"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gunakan untuk transfer file"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gunakan untuk masukan"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Gunakan untuk Alat Bantu Dengar"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Gunakan untuk Alat Bantu Dengar"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sandingkan"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SANDINGKAN"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Batal"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplikasi dihapus"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplikasi dan pengguna yang dihapus"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Update sistem"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portabel"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering bluetooth"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 577b7ae4dadb..58505f55e6e5 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Aðgangur að SIM-korti"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-hljóð: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-hljóð"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Heyrnatæki"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Tengt við heyrnartæki"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Heyrnartæki"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Tengt við heyrnartæki"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Tengt við hljóðspilun efnis"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Tengt við hljóð símans"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Tengt við skráaflutningsþjón"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Nota fyrir hljóð símans"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Nota við skráaflutning"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Nota fyrir inntak"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Nota fyrir heyrnartæki"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Nota fyrir heyrnartæki"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Para"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PARA"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Hætta við"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android stýrikerfið"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Fjarlægð forrit"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Fjarlægð forrit og notendur"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Kerfisuppfærslur"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-tjóðrun"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Heitur reitur"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-tjóðrun"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 9fc32949db38..6d863aa2a982 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accesso alla SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Apparecchio acustico"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Connesso all\'apparecchio acustico"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Apparecchi acustici"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Connessione con gli apparecchi acustici stabilita"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Collegato ad audio media"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Collegato ad audio telefono"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Collegato al server di trasferimento file"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usa per audio telefono"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usa per trasferimento file"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizza per l\'input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usa per l\'apparecchio acustico"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Utilizza per gli apparecchi acustici"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Accoppia"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCOPPIA"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annulla"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Sistema operativo Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Applicazioni rimosse"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"App e utenti rimossi"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Aggiornamenti di sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portatile"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 8ee11e4b2069..6e37c9a6eeda 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"גישה ל-SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"אודיו באיכות HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"אודיו באיכות HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"מכשיר שמיעה"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"מחובר למכשיר שמיעה"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"מכשירי שמיעה"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"מחובר אל מכשירי שמיעה"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"מחובר לאודיו של מדיה"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"מחובר לאודיו של הטלפון"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"מחובר לשרת העברת קבצים"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"השתמש עבור האודיו של הטלפון"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"השתמש להעברת קבצים"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"השתמש לקלט"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"יש להשתמש עבור מכשיר שמיעה"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"שימוש בשביל מכשירי שמיעה"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"התאם"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"התאם"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ביטול"</string> @@ -136,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"אפליקציות שהוסרו"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"אפליקציות ומשתמשים שהוסרו"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"שיתוף אינטרנט דרך USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"נקודה לשיתוף אינטרנט"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"שיתוף אינטרנט דרך Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 4efd61b37383..233e8e80b646 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIMアクセス"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD オーディオ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD オーディオ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"補聴器"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"補聴器に接続済み"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"補聴器"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"補聴器に接続"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"メディアの音声に接続"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"携帯電話の音声に接続"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ファイル転送サーバーに接続"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"携帯電話の音声に使用"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ファイル転送に使用"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"入力に使用"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"補聴器に使用"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"補聴器に使用"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ペア設定する"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ペア設定する"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"キャンセル"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"削除したアプリケーション"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"削除されたアプリとユーザー"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"システム アップデート"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB テザリング"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ポータブルアクセスポイント"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth テザリング"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index c613a06b2544..09bea2a0795f 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM წვდომა"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD აუდიო: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD აუდიო"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"სმენის აპარატი"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"დაკავშირებულია სმენის აპარატთან"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"სმენის მოწყობილობები"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"დაკავშირებულია სმენის მოწყობილობებთან"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"დაკავშირებულია აუდიო მულტიმედიურ სისტემასთან"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"დაკავშირებულია ტელეფონის აუდიო მოწყობილობასთან"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"დაკავშირებულია ფაილების გადაცემის სერვერთან"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"გამოიყენეთ ტელეფონის აუდიომოწყობილობაში"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ფაილების ტრანსფერისათვის გამოყენება"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"შეტანისთვის გამოყენება"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"სმენის აპარატის გამოყენება"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"გამოყენება სმენის მოწყობილობებისთვის"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"დაწყვილება"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"დაწყვილება"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"გაუქმება"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"აპების წაშლა"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"წაშლილი აპები და მომხმარებლები"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"სისტემის განახლებები"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ტეტერინგი"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"პორტატული უსადენო ქსელი"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth ტეტერინგი"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 8d6d76ecd30d..8670ec96012e 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM картасына кіру"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD форматты аудиомазмұн: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD форматты аудиомазмұн"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Есту аппараты"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Есту аппаратына жалғанған"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Есту аппараттары"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Есту аппараттарына жалғанған"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Медиа аудиосына жалғанған"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Телефон аудиосына қосылған"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Файл жіберу серверіне жалғанған"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Телефон аудиосы үшін қолдану"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файлды жіберу үшін қолдану"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Кіріс үшін қолдану"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Есту аппаратына пайдалану"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Есту аппараттары үшін пайдалану"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Жұптау"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ЖҰПТАУ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Бас тарту"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android операциялық жүйесі"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Алынған қолданбалар"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Алынған қолданбалар және пайдаланушылар"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Жүйелік жаңарту"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB тетеринг"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Алынбалы хот-спот"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth модем"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 990320108698..6bf8a0f3266f 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ការចូលដំណើរការស៊ីម"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"សំឡេងកម្រិត HD៖ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"សំឡេងកម្រិត HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ឧបករណ៍ជំនួយការស្ដាប់"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"បានភ្ជាប់ទៅឧបករណ៍ជំនួយការស្តាប់"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ឧបករណ៍ជំនួយការស្ដាប់"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"បានភ្ជាប់ទៅឧបករណ៍ជំនួយការស្ដាប់"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"បានភ្ជាប់ទៅអូឌីយ៉ូមេឌៀ"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"តភ្ជាប់ទៅអូឌីយ៉ូទូរស័ព្ទ"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"បានតភ្ជាប់ទៅម៉ាស៊ីនមេផ្ទេរឯកសារ"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ប្រើសម្រាប់អូឌីយ៉ូទូរស័ព្ទ"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ប្រើសម្រាប់ផ្ទេរឯកសារ"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ប្រើសម្រាប់បញ្ចូល"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ប្រើសម្រាប់ឧបករណ៍ជំនួយការស្តាប់"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ប្រើសម្រាប់ឧបករណ៍ជំនួយការស្តាប់"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ផ្គូផ្គង"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ផ្គូផ្គង"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"បោះបង់"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"ប្រព័ន្ធប្រតិបត្តិការ Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"កម្មវិធីដែលបានលុប"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"បានលុបកម្មវិធី និងអ្នកប្រើ"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"បច្ចុប្បន្នភាពប្រព័ន្ធ"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"ការភ្ជាប់តាម USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ហតស្ពតចល័ត"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ការភ្ជាប់ប៊្លូធូស"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 888b93fb17ad..41b0fbda408f 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ನೆಟ್ವರ್ಕ್ ರೇಟಿಂಗ್ ಒದಗಿಸುವವರ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಮೂಲಕ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"ಸೈನ್ ಅಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ಸೈನ್ ಇನ್ ಮಾಡುವ ಅಗತ್ಯವಿದೆ"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ಪ್ರವೇಶ ಕೇಂದ್ರ ತಾತ್ಕಾಲಿಕವಾಗಿ ಭರ್ತಿಯಾಗಿದೆ"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಲಾಗುತ್ತಿದೆ"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"ಸೈನ್-ಅಪ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಲಾಗುತ್ತಿದೆ…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"ಸೈನ್-ಅಪ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"ಸೈನ್-ಅಪ್ ಪೂರ್ಣಗೊಂಡಿದೆ. ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"ತುಂಬಾ ನಿಧಾನವಾಗಿದೆ"</string> <string name="speed_label_slow" msgid="813109590815810235">"ನಿಧಾನ"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ಸರಿ"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ಸಿಮ್ ಪ್ರವೇಶ"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ಆಡಿಯೋ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ಆಡಿಯೋ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ಶ್ರವಣ ಸಾಧನ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ಶ್ರವಣ ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ಶ್ರವಣ ಸಾಧನಗಳು"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ಶ್ರವಣ ಸಾಧನಗಳಿಗೆ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ಮಾಧ್ಯಮ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ಫೋನ್ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ಫೈಲ್ ವರ್ಗಾವಣೆ ಸರ್ವರ್ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ಫೋನ್ ಆಡಿಯೋಗಾಗಿ ಬಳಕೆ"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ಫೈಲ್ ವರ್ಗಾವಣೆಗಾಗಿ ಬಳಸು"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ಇನ್ಪುಟ್ಗಾಗಿ ಬಳಸು"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ಶ್ರವಣ ಸಾಧನಕ್ಕಾಗಿ ಬಳಸಿ"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ಶ್ರವಣ ಸಾಧನಗಳಿಗಾಗಿ ಬಳಸಿ"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ಜೋಡಿ"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ಜೋಡಿ ಮಾಡು"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ರದ್ದುಮಾಡಿ"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ತೆಗೆದುಹಾಕಲಾದ ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ಟೆಥರಿಂಗ್"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ಪೋರ್ಟಬಲ್ ಹಾಟ್ಸ್ಪಾಟ್"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ಬ್ಲೂಟೂತ್ ಟೆಥರಿಂಗ್"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index d7e9488cea42..877866c7c320 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 액세스"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD 오디오: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD 오디오"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"보청기"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"보청기에 연결됨"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"보청기"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"보청기에 연결됨"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"미디어 오디오에 연결됨"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"휴대전화 오디오에 연결됨"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"파일 전송 서버에 연결됨"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"휴대전화 오디오에 사용"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"파일 전송에 사용"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"입력에 사용"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"보청기에 사용"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"보청기로 사용"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"페어링"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"페어링"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"취소"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"삭제된 앱"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"삭제된 앱 및 사용자"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"시스템 업데이트"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 테더링"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"휴대용 핫스팟"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"블루투스 테더링"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 6898c61e5b85..9e4a9a8a1250 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM картаны пайдалануу мүмкүнчүлүгү"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD форматындагы аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD форматындагы аудио"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Угуу аппараты"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Угуу аппаратына туташты"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Угуу аппараттары"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Угуу аппараттарына туташып турат"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Медиа аудиого туташты"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Телефон аудиосуна туташты"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Файл өткөрүү серверине туташты"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Телефон аудиосу үчүн колдонулсун"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файл өткөрүү үчүн колдонулсун"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Киргизүү үчүн колдонулсун"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Угуу аппараты үчүн колдонуу"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Угуу аппараттары үчүн колдонуу"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Жупташтыруу"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ЖУПТАШТЫРУУ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Жок"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Алынып салынган колдонмолор"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Өчүрүлгөн колдонмолор жана колдонуучулар"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Тутум жаңыртуулары"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB модем"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ташыма кошулуу чекити"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth модем"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index acbaf701ace2..7e6aaacea44e 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ການເຂົ້າເຖິງ SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"ສຽງ HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"ສຽງ HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ເຄື່ອງຊ່ວຍຟັງ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ເຊື່ອມຕໍ່ຫາເຄື່ອງຊ່ວຍຟັງແລ້ວ"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ອຸປະກອນຊ່ວຍຟັງ"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ເຊື່ອມຕໍ່ຫາອຸປະກອນຊ່ວຍຟັງແລ້ວ"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ເຊື່ອມຕໍ່ກັບສື່ດ້ານສຽງແລ້ວ"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ເຊື່ອມຕໍ່ກັບສຽງໂທລະສັບແລ້ວ"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ເຊື່ອມຕໍ່ກັບເຊີບເວີໂອນຍ້າຍໄຟລ໌ແລ້ວ"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ໃຊ້ສຳລັບລະບົບສຽງຂອງໂທລະສັບ"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ໃຊ້ເພື່ອໂອນຍ້າຍໄຟລ໌"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ໃຊ້ສຳລັບການປ້ອນຂໍ້ມູນ"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ໃຊ້ກັບເຄື່ອງຊ່ວຍຟັງ"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ໃຊ້ສຳລັບອຸປະກອນຊ່ວຍຟັງ"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ຈັບຄູ່"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ຈັບຄູ່"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ຍົກເລີກ"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ແອັບຯທີ່ຖືກລຶບອອກແລ້ວ"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ລຶບແອັບຯ ແລະຜູ່ໃຊ້ແລ້ວ"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"ການອັບເດດລະບົບ"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"ການປ່ອຍສັນຍານຜ່ານ USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ຮັອດສະປອດເຄື່ອນທີ່"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ປ່ອຍສັນຍານຜ່ານ Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 89334517aa7d..71b8cf0ff375 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM prieiga"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD garsas: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD garsas"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Klausos aparatas"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Prisijungta prie klausos aparato"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Klausos aparatai"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Prisijungta prie klausos aparatų"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Prijungta prie medijos garso įrašo"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Prijungta prie telefono garso"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Prijungta prie failų perkėlimo serverio"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Naudoti telefono garso įrašui"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Naudoti failų perkėlimui"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Naudoti įvedant"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Klausos aparato naudojimas"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Naudoti su klausos aparatais"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Susieti"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SUSIETI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Atšaukti"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"„Android“ OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Pašalintos programos"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Pašalintos programos ir naudotojai"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Sistemos naujiniai"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB susiejimas"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Perkeliama aktyvioji sritis"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"„Bluetooth“ susiejimas"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index ac41ae082c1e..82ec0ae5b1cd 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Piekļuve SIM kartei"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Dzirdes aparāts"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Izveidots savienojums ar dzirdes aparātu"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Dzirdes aparāti"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Izveidots savienojums ar dzirdes aparātiem"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Savienots ar multivides audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Savienots ar tālruņa audio"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Savienots ar failu pārsūtīšanas serveri"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Izmantot tālruņa skaņai"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Izmantot faila pārsūtīšanai"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Izmantot ievadei"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Izmantot dzirdes aparātam"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Izmantot dzirdes aparātiem"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Izveidot pāri"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SAVIENOT PĀRĪ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Atcelt"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Noņemtās lietotnes"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Noņemtās lietotnes un lietotāji"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Sistēmas atjauninājumi"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB saistīšana"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Pārnēsājams tīklājs"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth saistīšana"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 5b45977a32a6..c99ef681b899 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Пристап до SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD аудио"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слушно помагало"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Поврзано со слушно помагало"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Слушни помагала"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Поврзано со слушни помагала"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Поврзан со аудио на медиуми"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Поврзан со аудио на телефон"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Поврзан со сервер за пренос на датотеки"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Користи за аудио на телефон"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Користи за пренос на датотеки"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Користи за внес"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Користете како слушно помагало"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Користи за слушни помагала"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Спари"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СПАРИ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Откажи"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Оперативен систем Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Отстранети апликации"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Отстранети апликации и корисници"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Ажурирања на системот"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Поврзување со USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Преносл. точка на пристап"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Поврзување со Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index efe6cd6dfbc5..0292cabb73bf 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ആക്സസ്"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ഓഡിയോ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ഓഡിയോ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ശ്രവണ സഹായി"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ശ്രവണ സഹായിലേക്ക് കണക്റ്റ് ചെയ്തു"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ശ്രവണ സഹായികൾ"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ശ്രവണ സഹായികളിലേക്ക് കണക്റ്റ് ചെയ്തു"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"മീഡിയ ഓഡിയോയിലേക്ക് കണക്റ്റുചെയ്തു"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ഫോൺ ഓഡിയോയിൽ കണക്റ്റുചെയ്തു"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ഫയൽ കൈമാറ്റ സെർവറിലേക്ക് കണക്റ്റുചെയ്തു"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ഫോൺ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ഫയൽ കൈമാറ്റത്തിനായി ഉപയോഗിക്കുന്നു"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ഇൻപുട്ടിനായി ഉപയോഗിക്കുക"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ശ്രവണ സഹായത്തിനായി ഉപയോഗിക്കുക"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ശ്രവണ സഹായികൾക്കായി ഉപയോഗിക്കുക"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ജോടിയാക്കുക"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ജോടിയാക്കുക"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"റദ്ദാക്കുക"</string> @@ -136,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"നീക്കംചെയ്ത അപ്ലിക്കേഷനുകൾ"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"നീക്കംചെയ്ത അപ്ലിക്കേഷനുകളും ഉപയോക്താക്കളും"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ടെതറിംഗ്"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"പോർട്ടബിൾ ഹോട്ട്സ്പോട്ട്"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ബ്ലൂടൂത്ത് ടെതറിംഗ്"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 9c3db2e99717..10c1415c7630 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -49,8 +49,8 @@ <string name="available_via_carrier" msgid="1469036129740799053">"%1$s-р боломжтой"</string> <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g>-г нээж байна"</string> <string name="osu_connect_failed" msgid="2187750899158158934">"Холбогдож чадсангүй"</string> - <string name="osu_completing_sign_up" msgid="9037638564719197082">"Бүртгүүлэлтийг дуусгаж байна…"</string> - <string name="osu_sign_up_failed" msgid="7296159750352873260">"Бүртгүүлэлтийг дуусгаж чадсангүй. Дахин оролдохын тулд товшино уу."</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"Бүртгэлийг дуусгаж байна…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"Бүртгэлийг дуусгаж чадсангүй. Дахин оролдохын тулд товшино уу."</string> <string name="osu_sign_up_complete" msgid="8207626049093289203">"Бүртгүүлж дууслаа. Холбогдож байна…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"Маш удаан"</string> <string name="speed_label_slow" msgid="813109590815810235">"Удаан"</string> @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Хандалт"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD аудио"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Сонсголын төхөөрөмж"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Сонсголын төхөөрөмжид холбогдсон"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Сонсголын төхөөрөмж"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Сонсголын төхөөрөмжтэй холбосон"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Медиа аудиод холбогдсон"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Утасны аудид холбогдсон"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Файл дамжуулах серверт холбогдсон"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Утасны аудиод ашиглах"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файл дамжуулахад ашиглах"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Оруулахад ашиглах"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Сонсголын төхөөрөмжид ашиглах"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Сонсголын төхөөрөмжид ашиглах"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Хослуулах"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ХОСЛУУЛАХ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Цуцлах"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Андройд OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Арилгасан апп-ууд"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Арилгасан апп-ууд болон хэрэглэгчид"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Системийн шинэчлэлт"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB модем болгох"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Зөөврийн сүлжээний цэг"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth модем болгох"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index a792c4f2de5e..0c2f0eefb0e7 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम प्रवेश"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ऑडिओ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ऑडिओ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ऐकण्याची सुविधा"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ऐकण्याच्या सुविधेशी कनेक्ट केलेले आहे"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"श्रवण यंत्रे"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"श्रवण यंत्रांशी कनेक्ट केले आहे"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"मीडिया ऑडिओवर कनेक्ट केले"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"फोन ऑडिओ वर कनेक्ट केले"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"फाईल स्थानांतर सर्व्हरवर कनेक्ट केले"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फोन ऑडिओसाठी वापरा"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फाईल स्थानांतरणासाठी वापरा"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"इनपुट साठी वापरा"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ऐकण्याच्या सुविधेसाठी वापरा"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"श्रवण यंत्रांसाठी वापरा"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"पेअर करा"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"पेअर करा"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द करा"</string> @@ -136,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"काढलेले अॅप्स"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"काढलेले अॅप्स आणि वापरकर्ते"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेदरिंग"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हॉटस्पॉट"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लूटूथ टेदरिंग"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 419c6ecd069a..e98418d55fb6 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Akses SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Alat Bantu Pendengaran"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Disambungkan ke Alat Bantu Pendengaran"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Alat Bantu Dengar"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Disambungkan pada Alat Bantu Dengar"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Disambungkan ke audio media"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Disambungkan ke audio telefon"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Bersambung ke pelayan pemindahan fail"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gunakan untuk audio telefon"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gunakan untuk pemindahan fail"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gunakan untuk input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Gunakan untuk Alat Bantu Pendengaran"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Gunakan untuk Alat Bantu Dengar"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Jadikan pasangan"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"JADIKAN PASANGAN"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Batal"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Apl dialih keluar"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Apl dan pengguna yang dialih keluar"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Kemas kini sistem"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Penambatan USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Titik panas mudah alih"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Penambatan Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 3e9e181209b4..ed2aae63f295 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM အသုံးပြုခြင်း"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD အသံ- <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD အသံ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"နားကြားကိရိယာ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"နားကြားကိရိယာသို့ ချိတ်ဆက်ထားသည်"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"နားကြားကိရိယာ"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"နားကြားကိရိယာနှင့် ချိတ်ဆက်ပြီးပါပြီ"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"မီဒီယာအသံအား ချိတ်ဆက်ရန်"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ဖုန်းအသံအား ချိတ်ဆက်ရန်"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ဖိုင်လွှဲပြောင်းမည့်ဆာဗာနှင့် ချိတ်ဆက်ထားပြီး"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ဖုန်းအသံအားအသုံးပြုရန်"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ဖိုင်လွဲပြောင်းရန်အတွက်အသုံးပြုရန်"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ထည့်သွင်းရန်အသုံးပြုသည်"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"နားကြားကိရိယာအတွက် အသုံးပြုရန်"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"နားကြားကိရိယာအတွက် အသုံးပြုသည်"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"အတူတွဲပါ"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ချိတ်တွဲရန်"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"မလုပ်တော့"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ဖယ်ရှားထားသော အက်ပ်များ"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ဖယ်ရှားထားသော အပလီကေးရှင်းနှင့် သုံးစွဲသူများ"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"စနစ် အပ်ဒိတ်လုပ်ခြင်းများ"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB သုံး၍ချိတ်ဆက်ခြင်း"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ရွေ့လျားနိုင်သောဟော့စပေါ့"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ဘလူးတုသ်သုံးချိတ်ဆက်ခြင်း"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 65085e8d15d4..93e53e52f968 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Tilgang til SIM-kortet"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-lyd"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Høreapparat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Koblet til høreapparat"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Høreapparater"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Koblet til høreapparater"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Koblet til medielyd"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Koblet til telefonlyd"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Koblet til tjener for filoverføring"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Bruk for telefonlyd"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Bruk til filoverføring"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Bruk for inndata"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Bruk for høreapparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Bruk for høreapparater"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sammenkoble"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOBLE TIL"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Avbryt"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android-operativsystem"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Fjernede apper"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Fjernede apper og brukere"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Systemoppdateringer"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-internettdeling"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Flyttbar trådløs sone"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-internettdeling"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 16b3b070df7a..7daf9564cc9b 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s मार्फत् स्वतः जडान गरिएको"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्कको दर्जा प्रदायक मार्फत स्वत: जडान गरिएको"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g> मार्फत जडान गरिएको"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s मार्फत उपलब्ध"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"साइन अप गर्न ट्याप गर्नुहोस्"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"जडान गरियो तर इन्टरनेट छैन"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"इन्टरनेटमाथिको पहुँच छैन"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन गर्न आवश्यक छ"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"पहुँचसम्बन्धी स्थान अस्थायी रूपमा भरिएको छ"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s मार्फत जडान गरियो"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$s मार्फत उपलब्ध"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> खोल्दै"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"जडान गर्न सकिएन"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"साइन अप गर्ने कार्य सम्पन्न गर्दै…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"साइन अप गर्ने कार्य सम्पन्न गर्न सकिएन। फेरि प्रयास गर्न ट्याप गर्नुहोस्।"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"साइन अप गर्ने कार्य सम्पन्न भयो। जडान गर्दै…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"धेरै ढिलो"</string> <string name="speed_label_slow" msgid="813109590815810235">"बिस्तारै"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ठिक छ"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM पहुँच"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD अडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD अडियो"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"सुन्नमा मद्दत गर्ने यन्त्र"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"सुन्नमा मद्दत गर्ने यन्त्रमा जडान गरियो"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"श्रवण यन्त्रहरू"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"श्रवण यन्त्रहरूमा जडान गरियो"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"मिडिया अडियोसँग जडित"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"फोन अडियोमा जडान गरियो"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"फाइल ट्रान्सफर सर्भरमा जडान गरियो"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फोन अडियोको लागि प्रयोग गर्नुहोस्"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फाइल ट्रान्सफरका लागि प्रयोग गर्नुहोस्"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"इनपुटको लागि प्रयोग गर्नुहोस्"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"सुन्नमा मद्दत गर्ने यन्त्रका लागि प्रयोग गर्नुहोस्"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"श्रवण यन्त्रहरूका लागि प्रयोग गर्नुहोस्"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"जोडी"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"जोडी"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द गर्नुहोस्"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"एन्ड्रोइड OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"हटाइएका अनुप्रयोगहरू"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"अनुप्रयोगहरू र प्रयोगकर्ताहरू हटाइयो।"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेथर गर्दै"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हटस्पट"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लुटुथ टेथर गर्दै"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 2f8c2c2c249a..959c1eac1d7d 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Sim-toegang"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Gehoorapparaat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Verbonden met gehoorapparaat"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Gehoorapparaten"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Verbonden met gehoorapparaten"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Verbonden met audio van medium"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Verbonden met audio van telefoon"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Verbonden met server voor bestandsoverdracht"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gebruiken voor audio van telefoon"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gebruiken voor bestandsoverdracht"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gebruiken voor invoer"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Gebruiken voor gehoorapparaat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Gebruiken voor gehoorapparaten"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Koppelen"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPELEN"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuleren"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android-besturingssysteem"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Verwijderde apps"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Verwijderde apps en gebruikers"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Systeemupdates"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Draagbare hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-tethering"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 95ab7bbab027..54ddf845847e 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲୀ ସଂଯୁକ୍ତ"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ନେଟୱର୍କ ମୂଲ୍ୟାୟନ ପ୍ରଦାତାଙ୍କ ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲ୍ୟ ସଂଯୁକ୍ତ"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g> ଦ୍ବାରା ସଂଯୋଗ କରାଯାଇଛି"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"ସାଇନ୍ ଅପ୍ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ସଂଯୁକ୍ତ, ଇଣ୍ଟର୍ନେଟ୍ ନାହିଁ"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"କୌଣସି ଇଣ୍ଟରନେଟ୍ ନାହିଁ"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ସାଇନ୍-ଇନ୍ ଆବଶ୍ୟକ"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ଆକ୍ସେସ୍ ପଏଣ୍ଟ ସାମୟିକ ଭାବେ ପୂର୍ଣ୍ଣ"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> ଖୋଲୁଛି"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"ସଂଯୋଗ କରିହେଲା ନାହିଁ"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"ସାଇନ୍ ଅପ୍ ଶେଷ ହେଉଛି…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"ସାଇନ୍ ଅପ୍ ଶେଷ ହୋଇପାରିଲା ନାହିଁ। ପୁଣି ଥରେ ଚେଷ୍ଟା କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"ସାଇନ୍ ଅପ୍ ଶେଷ ହୋଇଛି। ସଂଯୋଗ କରୁଛି…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"ବହୁତ ମନ୍ଥର"</string> <string name="speed_label_slow" msgid="813109590815810235">"କମ୍ ବେଗ"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ଠିକ୍ ଅଛି"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ସିମ୍ ଆକ୍ସେସ୍"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ଅଡିଓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ଅଡିଓ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ଶ୍ରବଣ ଯନ୍ତ୍ର ସହିତ ସଂଯୁକ୍ତ ହେଲା"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ଶ୍ରବଣ ଯନ୍ତ୍ରକୁ ସଂଯୋଗ ହୋଇଛି"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ମିଡିଆ ଅଡିଓ ସହ ସଂଯୁକ୍ତ"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ଫୋନ୍ ଅଡିଓ ସହିତ ସଂଯୁକ୍ତ"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ସର୍ଭର୍ ସହ ସଂଯୁକ୍ତ"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ଫୋନ୍ ଅଡିଓ ପାଇଁ ବ୍ୟବହାର କର"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ଇନ୍ପୁଟ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ଶ୍ରବଣ ଯନ୍ତ୍ର ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ଶ୍ରବଣ ଯନ୍ତ୍ର ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ପେୟାର୍"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ପେୟାର୍"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"କଢ଼ାଯାଇଥିବା ଆପ୍ଗୁଡ଼ିକ"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ଆପ୍ ଏବଂ ଉପଯୋଗକର୍ତ୍ତା ବାହାର କରାଗଲା"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ଟିଥରିଙ୍ଗ"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ପୋର୍ଟବଲ୍ ହଟସ୍ପଟ୍"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ବ୍ଲୁଟୂଥ ଟିଥରିଙ୍ଗ"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 1ddd862828d2..dcf3e3cb46ec 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ਰਾਹੀਂ ਆਪਣੇ-ਆਪ ਕਨੈਕਟ ਹੋਇਆ"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਰਾਹੀਂ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਇਆ"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g> ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"ਸਾਈਨ-ਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ਸਾਈਨ-ਇਨ ਲੋੜੀਂਦਾ ਹੈ"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ਐਕਸੈੱਸ ਪੁਆਇੰਟ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਸੰਪੂਰਨ ਰੁਝੇਂਵੇਂ ਵਿੱਚ ਹੈ"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"ਸਾਈਨ-ਅੱਪ ਮੁਕੰਮਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"ਸਾਈਨ-ਅੱਪ ਮੁਕੰਮਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"ਸਾਈਨ-ਅੱਪ ਮੁਕੰਮਲ ਹੋਇਆ ਕਨੈਕਟ ਹੋ ਰਿਹਾ ਹੈ…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"ਬਹੁਤ ਹੌਲੀ"</string> <string name="speed_label_slow" msgid="813109590815810235">"ਹੌਲੀ"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ਠੀਕ ਹੈ"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ਸਿਮ ਪਹੁੰਚ"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ਆਡੀਓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ਆਡੀਓ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ਸੁਣਨ ਦਾ ਸਾਧਨ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ਸੁਣਨ ਦੇ ਸਾਧਨ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ਮੀਡੀਆ ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ਫ਼ੋਨ ਔਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ਫਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਸਰਵਰ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ਫ਼ੋਨ ਔਡੀਓ ਲਈ ਵਰਤੋ"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਲਈ ਵਰਤੋ"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ਇਨਪੁਟ ਲਈ ਵਰਤੋ"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ਸੁਣਨ ਦੇ ਸਾਧਨ ਲਈ ਵਰਤੋ"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਲਈ ਵਰਤੋ"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"ਪੇਅਰ ਕਰੋ"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ਪੇਅਰ ਕਰੋ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ਰੱਦ ਕਰੋ"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ਹਟਾਏ ਗਏ ਐਪਸ"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ਹਟਾਏ ਗਏ ਐਪਸ ਅਤੇ ਉਪਭੋਗਤਾ"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ਟੈਦਰਿੰਗ"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ਪੋਰਟੇਬਲ ਹੌਟਸਪੌਟ"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ਬਲੂਟੁੱਥ ਟੈਦਰਿੰਗ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index e2109c8c35b0..505e3959244d 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Dostęp do karty SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Dźwięk HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Dźwięk HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparat słuchowy"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Po połączeniu z aparatem słuchowym"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Aparaty słuchowe"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Połączono z aparatami słuchowymi"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Połączono z funkcją audio multimediów"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Połączono z funkcją audio telefonu"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Połączono z serwerem transferu plików"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Użyj dla funkcji audio telefonu"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Użyj do transferu plików"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Użyj do wprowadzania"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Użyj dla funkcji aparatu słuchowego"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Użyj z aparatami słuchowymi"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sparuj"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SPARUJ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anuluj"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"System operacyjny Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Usunięte aplikacje"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Usunięte aplikacje i użytkownicy"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Aktualizacje systemu"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering przez USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Przenośny punkt dostępu"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering przez Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 19e22e420026..c0f31a6a5f73 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso ao chip"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Áudio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparelho auditivo"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectado a um aparelho auditivo"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Aparelhos auditivos"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Conectado a aparelhos auditivos"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao áudio da mídia"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao áudio do smartphone"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferência de arquivo"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usar para áudio do smartphone"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usado para transferência de arquivo"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Usar para entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar para aparelho auditivo"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Usar para aparelhos auditivos"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parear"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAREAR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Sistema operacional Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Apps removidos"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Apps e usuários removidos"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Atualizações do sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ponto de acesso portátil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 1f1072c08ffa..08c3cc82c259 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso ao SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Áudio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparelho auditivo"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Associar ao aparelho auditivo"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Aparelhos auditivos"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Ligado a aparelhos auditivos"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ligado ao áudio de multimédia"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ligado ao áudio do telefone"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ligado ao servidor de transferência de ficheiros"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para áudio do telefone"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizar para transferência de ficheiros"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizar para entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Utilizar com o aparelho auditivo"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Utilizar para aparelhos auditivos"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sincr."</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicações removidas"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicações e utilizadores removidos"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Atualizações do sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Ligação USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portátil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Ligação Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 19e22e420026..c0f31a6a5f73 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso ao chip"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Áudio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparelho auditivo"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectado a um aparelho auditivo"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Aparelhos auditivos"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Conectado a aparelhos auditivos"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao áudio da mídia"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao áudio do smartphone"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferência de arquivo"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usar para áudio do smartphone"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usado para transferência de arquivo"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Usar para entrada"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar para aparelho auditivo"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Usar para aparelhos auditivos"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parear"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAREAR"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Sistema operacional Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Apps removidos"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Apps e usuários removidos"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Atualizações do sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ponto de acesso portátil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 7fa75a8862cf..015eb9240fc5 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acces la SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparat auditiv"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Conectat la aparatul auditiv"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Aparate auditive"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Conectat la aparatul auditiv"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectat la profilul pentru conținut media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectat la componenta audio a telefonului"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectat la serverul de transfer de fișiere"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizați pentru componenta audio a telefonului"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizați pentru transferul de fișiere"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizați pentru introducere date"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Utilizați pentru aparatul auditiv"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Folosiți pentru aparatele auditive"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Asociați"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"CONECTAȚI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anulați"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Sistem de operare Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicații eliminate"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicații și utilizatori eliminați"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Actualizări de sistem"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering prin USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portabil"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering prin Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 6cdfd3c3f318..b0b592caf6c7 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ к SIM-карте"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD Audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слуховой аппарат"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Подключен к слуховому аппарату"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Слуховые аппараты"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Слуховой аппарат подключен"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Подключено к мультимедийному аудиоустройству"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Подключено к аудиоустройству телефона"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Установлено подключение к серверу передачи файлов"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Использовать для аудиоустройства телефона"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Используется для передачи файлов"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Использовать для ввода"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Использовать для слухового аппарата"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Использовать для слухового аппарата"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Добавить"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ДОБАВИТЬ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Отмена"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"ОС Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Удаленные приложения"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Удаленные приложения и пользователи"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Обновления системы"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-модем"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Точка доступа Wi-Fi"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-модем"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index f85289c64527..ca7a96227d99 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ප්රවේශය"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ශ්රව්යය: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ශ්රව්යය"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"ශ්රවණාධාරකය"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"ශ්රවණාධාරකයට සම්බන්ධයි"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"ශ්රවණාධාරක"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"ශ්රවණාධාරක වෙත සම්බන්ධ කළා"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"මාධ්ය ශ්රව්යට සම්බන්ධ විය"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"දුරකතනයේ ශ්රව්යට සම්බන්ධ විය"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ගොනු හුවමාරු සේවාදායකය සමග සම්බන්ධ විය"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"දුරකථන ශ්රව්ය සඳහා භාවිතා කෙරේ"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ගොනු හුවමාරුව සඳහා භාවිතා කරන්න"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ආදානය සඳහා භාවිතා කරන්න"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ශ්රවණාධාරකය සඳහා භාවිත කරන්න"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ශ්රවණාධාර සඳහා භාවිත කරන්න"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"යුගල කරන්න"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"යුගල කරන්න"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"අවලංගු කරන්න"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ඉවත් කළ යෙදුම්"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"යෙදුම් සහ පරිශීලකයින් ඉවත් කරන ලදි"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"පද්ධති යාවත්කාලීන"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ටෙදරින්"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ජංගම හොට්ස්පොට්"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"බ්ලූටූත් ටෙදරින්"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index eae5be7952c3..dd7efdd50a59 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Prístup k SIM karte"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD zvuk"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Načúvacia pomôcka"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Pripojené k načúvacej pomôcke"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Načúvacie pomôcky"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Pripojené k načúvacím pomôckam"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Pripojené ku zvukovému médiu"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Pripojené ku zvuku telefónu"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Pripojené na server pre prenos údajov"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Použiť pre zvuk telefónu"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Použiť na prenos súborov"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Použiť pre vstup"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Použitie načúvacej pomôcky"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Použiť pre načúvacie pomôcky"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párovať"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROVAŤ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Zrušiť"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odstránené aplikácie"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odstránené aplikácie a používatelia"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Aktualizácie systému"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Pripojenie cez USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosný prístupový bod"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Pripojenie cez Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index bef9a3e5aadd..fada686f00d1 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Dostop do kartice SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Zvok visoke kakovosti"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Slušni pripomoček"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Povezava s slušnim pripomočkom je vzpostavljena"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Slušni pripomočki"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Povezava s slušnimi pripomočki je vzpostavljena"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezan s profilom za predstavnostni zvok"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezava s profilom za zvok telefona vzpostavljena"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezava s strežnikom za prenos datotek je vzpostavljena"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Uporabi za zvok telefona"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Uporabi za prenos datotek"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Uporabi za vnos"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Uporaba za slušni pripomoček"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Uporabi za slušne pripomočke"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Seznani"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SEZNANI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Prekliči"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odstranjene aplikacije"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odstranjene aplikacije in uporabniki"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Posodobitve sistema"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Internet prek USB-ja"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosna dostopna točka"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Internet prek Bluetootha"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 8bb67f9a348f..2132767193c5 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Qasje në kartën SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Audio HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparati i dëgjimit"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Lidhur me aparatin e dëgjimit"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Aparatet e dëgjimit"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Lidhur me aparatet e dëgjimit"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"U lidh me audion e medias"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"U lidh me audion e telefonit"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"U lidh me serverin e transferimit të skedarëve"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Përdor për audion e telefonit"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Përdor për transferimin e skedarëve"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Përdore për hyrjen"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Përdore për aparatin e dëgjimit"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Përdore për aparatet e dëgjimit"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Çifto"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ÇIFTO"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anulo"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Sistemi operativ Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplikacionet e hequra"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplikacionet dhe përdoruesit e hequr"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Përditësimet e sistemit"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Ndarje përmes USB-së"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona e qasjes e lëvizshme"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Ndarje interneti përmes Bluetooth-it"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 4378a463c839..6cf4b208c544 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Приступ SIM картици"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD звук: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD звук"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слушни апарат"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Повезано са слушним апаратом"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Слушни апарати"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Повезано са слушним апаратима"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Повезано са звуком медија"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Повезано са звуком телефона"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Повезано са сервером за пренос датотека"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Коришћење за аудио телефона"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Коришћење за пренос датотека"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Користи за улаз"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Користи за слушни апарат"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Користи за слушне апарате"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Упари"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"УПАРИ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Откажи"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android ОС"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Уклоњене апликације"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Уклоњене апликације и корисници"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Ажурирања система"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB Интернет повезивање"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Преносни хотспот"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth привезивање"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 3fcb6dc80713..f2950dcf2808 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-åtkomst"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-ljud: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-ljud"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hörapparat"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Ansluten till hörapparat"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Hörapparater"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Ansluten till hörapparater"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ansluten till medialjud"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ansluten till telefonens ljud"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ansluten till filöverföringsserver"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Använd för telefonens ljud"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Använd för filöverföring"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Använd för inmatning"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Använd med hörapparat"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Använd med hörapparater"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parkoppling"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PARKOPPLA"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Avbryt"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Operativsystemet Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Borttagna appar"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Borttagna appar och användare"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Systemuppdateringar"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Internetdelning via USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Mobil surfzon"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Delning via Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 47c7bb2187ef..d8a74a14c40f 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Ufikiaji wa SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Sauti ya HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Sauti ya HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Visaidizi vya Kusikia"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Imeunganishwa kwenye Visaidizi vya Kusikia"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Vifaa vya Kusaidia Kusikia"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Imeunganishwa kwenye Vifaa vya Kusaidia Kusikia"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Imeunganishwa kwenye sikika ya njia ya mawasiliano"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Imeunganishwa kwenye sauti ya simu"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Imeunganishwa kwenye seva ya kuhamisha faili"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Tumia kwa sauti ya simu"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Tumia kwa hali faili"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Tumia kwa kuingiza"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Tumia katika Visaidizi vya Kusikia"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Tumia kwenye Vifaa vya Kusaidia Kusikia"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Oanisha"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"OANISHA"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Ghairi"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"OS ya Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Programu zilizoondolewa"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Watumiaji na programu ziilizoondolewa"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Masasisho ya mfumo"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Shiriki intaneti kwa USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Intaneti ya kusambazwa"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Shiriki intaneti kwa Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 63c6cd9b11f2..71716cec6886 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s மூலம் தானாக இணைக்கப்பட்டது"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"நெட்வொர்க் மதிப்பீடு வழங்குநரால் தானாக இணைக்கப்பட்டது"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g> மூலம் இணைக்கப்பட்டது"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"பதிவு செய்யத் தட்டவும்"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"இணைக்கப்பட்டுள்ளது, ஆனால் இண்டர்நெட் இல்லை"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"இணைய இணைப்பு இல்லை"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"உள்நுழைய வேண்டும்"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"தற்காலிகமாக அணுகல் புள்ளி நிரம்பியுள்ளது"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s வழியாக இணைக்கப்பட்டது"</string> <string name="available_via_carrier" msgid="1469036129740799053">"%1$s வழியாகக் கிடைக்கிறது"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> திறக்கப்படுகிறது"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"இணைக்க முடியவில்லை"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"பதிவு செய்வது நிறைவடைகிறது…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"பதிவு செய்வதை நிறைவுசெய்ய இயலவில்லை மீண்டும் முயற்சிக்கத் தட்டவும்."</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"பதிவு செய்வது நிறைவடைந்தது. இணைக்கிறது…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"மிகவும் வேகம் குறைவானது"</string> <string name="speed_label_slow" msgid="813109590815810235">"வேகம் குறைவு"</string> <string name="speed_label_okay" msgid="2331665440671174858">"சரி"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"சிம் அணுகல்"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ஆடியோ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ஆடியோ"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"செவித்துணைக் கருவி"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"செவித்துணைக் கருவியுடன் இணைக்கப்பட்டிருக்கிறது"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"செவித்துணை கருவிகள்"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"செவித்துணை கருவிகளுடன் இணைக்கப்பட்டது"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"கோப்பைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"மொபைல் ஆடியோவைப் பயன்படுத்து"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"கோப்பு பரிமாற்றத்திற்காகப் பயன்படுத்து"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"உள்ளீட்டுக்குப் பயன்படுத்து"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"செவித்துணைக் கருவிக்காகப் பயன்படுத்து"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"செவித்துணை கருவிகளுக்குப் பயன்படுத்தவும்"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"இணை"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"இணை"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ரத்துசெய்"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"அகற்றப்பட்ட பயன்பாடுகள்"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"அகற்றப்பட்ட பயன்பாடுகள் மற்றும் பயனர்கள்"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB டெதெரிங்"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"போர்ட்டபிள் ஹாட்ஸ்பாட்"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"புளூடூத் டெதெரிங்"</string> @@ -203,7 +198,7 @@ <string name="vpn_settings_not_available" msgid="956841430176985598">"இவரால் VPN அமைப்புகளை மாற்ற முடியாது"</string> <string name="tethering_settings_not_available" msgid="6765770438438291012">"இவரால் இணைப்புமுறை அமைப்புகளை மாற்ற முடியாது"</string> <string name="apn_settings_not_available" msgid="7873729032165324000">"இவரால் ஆக்சஸ் பாயிண்ட் நேம் அமைப்புகளை மாற்ற முடியாது"</string> - <string name="enable_adb" msgid="7982306934419797485">"USB பிழைத்திருத்தம்"</string> + <string name="enable_adb" msgid="7982306934419797485">"USB பிழைதிருத்தம்"</string> <string name="enable_adb_summary" msgid="4881186971746056635">"USB இணைக்கப்பட்டிருக்கும்போது பிழைத்திருத்தப் பயன்முறையை அமை"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"USB பிழைத்திருத்த அங்கீகரிப்புகளை நிராகரி"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"பிழைப் புகாருக்கான ஷார்ட்கட்"</string> @@ -263,8 +258,8 @@ <string name="debug_view_attributes" msgid="6485448367803310384">"காட்சி பண்புக்கூறு சோதனையை இயக்கு"</string> <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"வைஃபை இயங்கும் போதும் (வேகமான நெட்வொர்க் மாற்றத்திற்கு), மொபைல் டேட்டாவை எப்போதும் இயக்கத்தில் வைக்கும்."</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை கிடைக்கும் போது, அதைப் பயன்படுத்தும்"</string> - <string name="adb_warning_title" msgid="6234463310896563253">"USB பிழைத்திருத்தத்தை அனுமதிக்கவா?"</string> - <string name="adb_warning_message" msgid="7316799925425402244">"USB பிழைத்திருத்தம் மேம்படுத்தல் நோக்கங்களுக்காக மட்டுமே. அதை உங்கள் கணினி மற்றும் சாதனத்திற்கு இடையில் தரவை நகலெடுக்கவும், அறிவிப்பு இல்லாமல் உங்கள் சாதனத்தில் பயன்பாடுகளை நிறுவவும், பதிவு தரவைப் படிக்கவும் பயன்படுத்தவும்."</string> + <string name="adb_warning_title" msgid="6234463310896563253">"USB பிழைதிருத்தத்தை அனுமதிக்கவா?"</string> + <string name="adb_warning_message" msgid="7316799925425402244">"USB பிழைதிருத்தம் மேம்படுத்தல் நோக்கங்களுக்காக மட்டுமே. அதை உங்கள் கணினி மற்றும் சாதனத்திற்கு இடையில் தரவை நகலெடுக்கவும், அறிவிப்பு இல்லாமல் உங்கள் சாதனத்தில் பயன்பாடுகளை நிறுவவும், பதிவு தரவைப் படிக்கவும் பயன்படுத்தவும்."</string> <string name="adb_keys_warning_message" msgid="5659849457135841625">"நீங்கள் ஏற்கனவே அனுமதித்த எல்லா கணினிகளிலிருந்தும் USB பிழைத்திருத்தத்திற்கான அணுகலைத் திரும்பப்பெற வேண்டுமா?"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"மேம்பட்ட அமைப்புகளை அனுமதிக்கவா?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"இந்த அமைப்பு மேம்பட்டப் பயன்பாட்டிற்காக மட்டுமே. உங்கள் சாதனம் மற்றும் அதில் உள்ள பயன்பாடுகளைச் சிதைக்கும் அல்லது தவறாகச் செயல்படும் வகையில் பாதிப்பை ஏற்படுத்தும்."</string> @@ -276,10 +271,10 @@ <string name="enable_terminal_summary" msgid="67667852659359206">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் பயன்பாட்டை இயக்கு"</string> <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP சரிபார்ப்பு"</string> <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP சரிபார்க்கும் செயல்பாடுகளை அமை"</string> - <string name="debug_debugging_category" msgid="6781250159513471316">"பிழைத்திருத்தம்"</string> + <string name="debug_debugging_category" msgid="6781250159513471316">"பிழைதிருத்தம்"</string> <string name="debug_app" msgid="8349591734751384446">"பிழைத்திருத்தப் பயன்பாட்டைத் தேர்ந்தெடுக்கவும்"</string> <string name="debug_app_not_set" msgid="718752499586403499">"பிழைத்திருத்தப் பயன்பாடு அமைக்கப்படவில்லை"</string> - <string name="debug_app_set" msgid="2063077997870280017">"பிழைத்திருத்தும் பயன்பாடு: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="debug_app_set" msgid="2063077997870280017">"பிழைதிருத்தும் பயன்பாடு: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"பயன்பாட்டைத் தேர்ந்தெடுக்கவும்"</string> <string name="no_application" msgid="2813387563129153880">"ஒன்றுமில்லை"</string> <string name="wait_for_debugger" msgid="1202370874528893091">"பிழைதிருத்திக்குக் காத்திருக்கவும்"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index d8ec167c8e50..e4dd85f8d248 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM యాక్సెస్"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ఆడియో"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"వినికిడి పరికరం"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"వినికిడి పరికరానికి కనెక్ట్ చేస్తోంది"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"వినికిడి మద్దతు ఉపకరణాలు"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"వినికిడి మద్దతు ఉపకరణాలకు కనెక్ట్ చేయబడింది"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"మీడియా ఆడియోకు కనెక్ట్ చేయబడింది"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ఫోన్ ఆడియోకు కనెక్ట్ చేయబడింది"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ఫైల్ బదిలీ సర్వర్కు కనెక్ట్ చేయబడింది"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ఫోన్ ఆడియో కోసం ఉపయోగించు"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ఫైల్ బదిలీ కోసం ఉపయోగించు"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ఇన్పుట్ కోసం ఉపయోగించు"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"వినికిడి పరికరం కోసం ఉపయోగించు"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"వినికిడి మద్దతు ఉపకరణాలకు ఉపయోగించండి"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"జత చేయి"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"జత చేయి"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"రద్దు చేయి"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"తీసివేయబడిన అనువర్తనాలు"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"తీసివేయబడిన అనువర్తనాలు మరియు వినియోగదారులు"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"సిస్టమ్ అప్డేట్లు"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB టీథరింగ్"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"పోర్టబుల్ హాట్స్పాట్"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"బ్లూటూత్ టీథరింగ్"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 1f4c727dd227..cf8362fe4d37 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"การเข้าถึงซิม"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"เสียง HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"เสียง HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"เครื่องช่วยการได้ยิน"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"เชื่อมต่อเครื่องช่วยการได้ยินแล้ว"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"เครื่องช่วยการได้ยิน"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"เชื่อมต่อกับเครื่องช่วยการได้ยินแล้ว"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"เชื่อมต่อกับระบบเสียงของสื่อแล้ว"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"เชื่อมต่อกับระบบเสียงของโทรศัพท์แล้ว"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"เชื่อมต่อกับเซิร์ฟเวอร์สำหรับโอนไฟล์แล้ว"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ใช้สำหรับระบบเสียงของโทรศัพท์"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ใช้สำหรับการโอนไฟล์"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ใช้สำหรับการป้อนข้อมูล"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"ใช้สำหรับเครื่องช่วยการได้ยิน"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"ใช้สำหรับเครื่องช่วยการได้ยิน"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"จับคู่อุปกรณ์"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"จับคู่อุปกรณ์"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"ยกเลิก"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"ระบบปฏิบัติการของ Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"แอปพลิเคชันที่นำออก"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"แอปพลิเคชันและผู้ใช้ที่นำออก"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"การอัปเดตระบบ"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"ปล่อยสัญญาณผ่าน USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ฮอตสปอตแบบพกพาได้"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ปล่อยสัญญาณบลูทูธ"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 7a31cc9ee3b1..e690800eb9a7 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Access sa SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hearing Aid"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Nakakonekta sa Hearing Aid"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Mga Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Nakakonekta sa Mga Hearing Aid"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Konektado sa media audio"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Nakakonekta sa audio ng telepono"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Nakakonekta sa server sa paglilipat ng file"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Ginagamit para sa audio ng telepono"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Ginagamit para sa paglilipat ng file"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gamitin para sa input"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Gamitin para sa Hearing Aid"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Gamitin para sa Mga Hearing Aid"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pares"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"IPARES"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Kanselahin"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Mga inalis na app"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Mga inalis na apps at user"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Mga pag-update ng system"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Pag-tether sa USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable na hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Pag-tether ng Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 28fc38fcd8a5..ea340e8e92e6 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Erişimi"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ses: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ses"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"İşitme Cihazı"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"İşitme Cihazına bağlandı"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"İşitme Cihazları"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"İşitme Cihazlarına Bağlandı"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Medya sesine bağlanıldı"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon sesine bağlandı"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Dosya aktarım sunucusuna bağlandı"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon sesi için kullan"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Dosya aktarımı için kullan"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Giriş için kullan"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"İşitme Cihazı için kullan"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"İşitme Cihazları için kullan"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşle"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLE"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"İptal"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Kaldırılan uygulamalar"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Kaldırılmış kullanıcılar ve uygulamalar"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Sistem güncellemeleri"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Taşınabilir hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index c63f7e0e0761..cf90ed16efaf 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ до SIM-карти"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD-аудіо: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-аудіо"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Слуховий апарат"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Під’єднано до слухового апарата"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Слухові апарати"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Підключено до слухових апаратів"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Підключено до аудіоджерела"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Підключено до звуку телеф."</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Підключ. до сервера передачі файлів"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Викор. для звуку тел."</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Викор. для перед. файлів"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Викор. для введ."</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Використовувати для слухового апарата"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Використовувати для слухових апаратів"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Підключити"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ПІДКЛЮЧИТИСЯ"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Скасувати"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"ОС Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Видалені програми"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Видалені програми та користувачі"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Оновлення системи"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-модем"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Порт. точка дост."</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-модем"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index 27aa730b6a8b..65ed110d3c46 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -38,27 +38,20 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s کے ذریعے از خود منسلک کردہ"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"نیٹ ورک درجہ بندی کے فراہم کنندہ کے ذریعے از خود منسلک"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"منسلک بذریعہ %1$s"</string> - <!-- no translation found for connected_via_app (5571999941988929520) --> - <skip /> + <string name="connected_via_app" msgid="5571999941988929520">"<xliff:g id="NAME">%1$s</xliff:g> کے ذریعے منسلک"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"دستیاب بذریعہ %1$s"</string> - <!-- no translation found for tap_to_sign_up (6449724763052579434) --> - <skip /> + <string name="tap_to_sign_up" msgid="6449724763052579434">"سائن اپ کے لیے تھپتھپائیں"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"منسلک، انٹرنیٹ نہیں ہے"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"انٹرنیٹ نہیں ہے"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"سائن ان درکار ہے"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"رسائی پوائنٹ عارضی طور پر فُل ہے"</string> <string name="connected_via_carrier" msgid="7583780074526041912">"منسلک بذریعہ %1$s"</string> <string name="available_via_carrier" msgid="1469036129740799053">"دستیاب بذریعہ %1$s"</string> - <!-- no translation found for osu_opening_provider (5488997661548640424) --> - <skip /> - <!-- no translation found for osu_connect_failed (2187750899158158934) --> - <skip /> - <!-- no translation found for osu_completing_sign_up (9037638564719197082) --> - <skip /> - <!-- no translation found for osu_sign_up_failed (7296159750352873260) --> - <skip /> - <!-- no translation found for osu_sign_up_complete (8207626049093289203) --> - <skip /> + <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> کھل رہا ہے"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"منسلک نہیں کیا جا سکا"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"سائن اپ مکمل ہو رہا ہے…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"سائن اپ مکمل نہیں ہو سکا۔ دوبارہ کوشش کرنے کے لیے تھپتھپائیں۔"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"سائن اپ مکمل ہو گیا۔ منسلک ہو رہا ہے…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"بہت سست"</string> <string name="speed_label_slow" msgid="813109590815810235">"سست"</string> <string name="speed_label_okay" msgid="2331665440671174858">"ٹھیک ہے"</string> @@ -94,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM رسائی"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD آڈیو: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD آڈیو"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"سماعتی آلہ"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"سماعتی آلے سے منسلک"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"سماعتی آلات"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"سماعتی آلات سے منسلک ہے"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"میڈیا آڈیو سے مربوط"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"فون آڈیو سے مربوط"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"فائل منتقلی سرور سے مربوط ہو گیا ہے"</string> @@ -112,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"فون آڈیو کیلئے استعمال کریں"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"فائل منتقل کرنے کیلئے استعمال کریں"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"ان پٹ کیلئے استعمال"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"سماعتی آلے کیلئے استعمال کریں"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"سماعتی آلات کے لیے استعمال کریں"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"جوڑا بنائیں"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"جوڑا بنائیں"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"منسوخ کریں"</string> @@ -143,6 +136,8 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ہٹائی گئی ایپس"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ہٹائی گئی ایپس اور صارفین"</string> + <!-- no translation found for data_usage_ota (5377889154805560860) --> + <skip /> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ٹیدرنگ"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"پورٹیبل ہاٹ اسپاٹ"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ ٹیدرنگ"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index bcb4d27d94d4..2851bafd4639 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kartaga kirish"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD audio"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Eshitish apparati"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Eshitish apparatiga ulangan"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Eshitish apparatlari"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Eshitish apparatlariga ulangan"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Audio qurilmasiga ulangan"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon karnayiga ulanildi"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Fayl almashinish serveriga ulanildi"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Dok’dan karnay sifatida foydalanish"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Fayl almashinish uchun foydalanish"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Kiritish qurilmasi sifatida foydalanish"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Eshitish apparati uchun foydalanish"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Eshitish apparatlari uchun foydalanish"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Biriktirish"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ULANISH"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Bekor qilish"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"O‘chirilgan ilovalar"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"O‘chirib tashlangan ilova va foydalanuvchilar"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Tizimni yangilash"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB modem"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ixcham hotspot"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth modem"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index d03b2f175f60..3fb101e6deec 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Quyền truy cập SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Âm thanh HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Âm thanh HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Trợ thính"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Đã kết nối với thiết bị trợ thính"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Thiết bị trợ thính"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Đã kết nối với Thiết bị trợ thính"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Đã kết nối với âm thanh phương tiện"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Đã kết nối với âm thanh điện thoại"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Đã kết nối với máy chủ chuyển tệp"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Sử dụng cho âm thanh điện thoại"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Sử dụng để chuyển tệp"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Sử dụng để nhập"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Sử dụng cho thiết bị trợ thính"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Dùng cho Thiết bị trợ thính"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Ghép nối"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"GHÉP NỐI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Hủy"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Hệ điều hành Android"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Ứng dụng đã xóa"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Ứng dụng và người dùng bị xóa"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Bản cập nhật hệ thống"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Chia sẻ kết nối Internet qua USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Điểm phát sóng di động"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Chia sẻ kết nối Internet qua Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 69674472028c..0a318d752ae7 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取权限"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD 音频:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD 音频"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"助听器"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"已连接到助听器"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"助听器"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"已连接到助听器"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"已连接到媒体音频"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"已连接到手机音频"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"已连接到文件传输服务器"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用于手机音频"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用于文件传输"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"用于输入"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"用于助听器"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"用于助听器"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"配对"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"配对"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android 操作系统"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"已删除的应用"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"已删除的应用和用户"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"系统更新"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 网络共享"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"便携式热点"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"蓝牙网络共享"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 5394afc32334..06bee941ff0c 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -38,9 +38,9 @@ <string name="connected_via_network_scorer" msgid="5713793306870815341">"已透過 %1$s 自動連線"</string> <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已透過網絡評分供應商自動連線"</string> <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string> - <string name="connected_via_app" msgid="5571999941988929520">"透過「<xliff:g id="NAME">%1$s</xliff:g>」連線"</string> + <string name="connected_via_app" msgid="5571999941988929520">"已透過「<xliff:g id="NAME">%1$s</xliff:g>」連線"</string> <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 連線"</string> - <string name="tap_to_sign_up" msgid="6449724763052579434">"輕觸即可註冊"</string> + <string name="tap_to_sign_up" msgid="6449724763052579434">"輕按即可登入"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,但沒有互聯網"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"沒有互聯網連線"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必須登入"</string> @@ -48,10 +48,10 @@ <string name="connected_via_carrier" msgid="7583780074526041912">"已透過 %1$s 連線"</string> <string name="available_via_carrier" msgid="1469036129740799053">"可透過 %1$s 連線"</string> <string name="osu_opening_provider" msgid="5488997661548640424">"正在開啟 <xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g>"</string> - <string name="osu_connect_failed" msgid="2187750899158158934">"無法連線"</string> - <string name="osu_completing_sign_up" msgid="9037638564719197082">"正在完成註冊程序…"</string> - <string name="osu_sign_up_failed" msgid="7296159750352873260">"無法完成註冊程序。輕觸即可重試。"</string> - <string name="osu_sign_up_complete" msgid="8207626049093289203">"註冊完成。連線中…"</string> + <string name="osu_connect_failed" msgid="2187750899158158934">"無法連接"</string> + <string name="osu_completing_sign_up" msgid="9037638564719197082">"正在完成申請…"</string> + <string name="osu_sign_up_failed" msgid="7296159750352873260">"無法完成申請。輕按即可重試。"</string> + <string name="osu_sign_up_complete" msgid="8207626049093289203">"已完成申請。連接中…"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"非常慢"</string> <string name="speed_label_slow" msgid="813109590815810235">"慢"</string> <string name="speed_label_okay" msgid="2331665440671174858">"良好"</string> @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"高清音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"高清音訊"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"助聽器"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"已連線至助聽器"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"助聽器"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"已連接助聽器"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"已連接媒體音頻裝置"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"已連接手機耳機"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"已連線至檔案傳輸伺服器"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用於手機音效"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用於傳輸檔案"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"用於輸入"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"用於助聽器"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"用於助聽器"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"配對"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"配對"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android 作業系統"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"已移除的應用程式"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"已移除的應用程式和使用者"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"系統更新"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 網絡共享"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"可攜式熱點"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"藍牙網絡共享"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 107eb6de564f..a5074d9db005 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取權"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD 高解析音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD 高解析音訊"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"助聽器"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"已連接到助聽器"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"助聽器"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"已連接到助聽器"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"連接至媒體音訊"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"連接至電話音訊"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"已連線到檔案傳輸伺服器"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用於電話音訊"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用於傳輸檔案"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"用於輸入"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"用於助聽器"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"用於助聽器"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"配對"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"配對"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"Android 作業系統"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"移除的應用程式"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"已移除的應用程式和使用者"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"系統更新"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 網路共用"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"可攜式無線基地台"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"藍牙網路共用"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 920df4b81475..589209399839 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -87,8 +87,8 @@ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Ukufinyelela kwe-SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Umsindo we-HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Umsindo we-HD"</string> - <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Usizo lokuzwa"</string> - <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Ixhunywe kokokusiza ukuzwa"</string> + <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"Izinsiza zokuzwa"</string> + <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="3051944447369418317">"Kuxhumeke kwizinsiza zokuzwa"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ixhume emsindweni wemidiya"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ixhunywe kumsindo wefoni"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ixhunywe kwiseva yokudlulisa ifayela"</string> @@ -105,7 +105,7 @@ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Sebenziselwa umsindo wefoni"</string> <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Sebenziselwa ukudlulisa ifayela"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Isetshenziselwa okufakwayo"</string> - <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Sebenzisela usizo lokuzwa"</string> + <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="8843499209204010224">"Sebenzisa izinsiza zokuzwa"</string> <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Bhangqa"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"BHANQA"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Khansela"</string> @@ -136,6 +136,7 @@ <string name="process_kernel_label" msgid="3916858646836739323">"I-Android OS"</string> <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Izinhlelo zokusebenza zisusiwe"</string> <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Izinhelo zokusebenza nabasebenzisi abasusiwe"</string> + <string name="data_usage_ota" msgid="5377889154805560860">"Izibuyekezo zesistimu"</string> <string name="tether_settings_title_usb" msgid="6688416425801386511">"Imodemu nge-USB"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"I-hotspot ephathekayo"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Imodemu nge-Bluetooth"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java b/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java index e92b36a45645..b7f7ad256505 100644 --- a/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java +++ b/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java @@ -23,6 +23,10 @@ import android.content.IntentFilter; import android.net.Uri; import android.os.Process; import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Log; + +import java.util.Set; /** * Utility class that allows Settings to use SystemUI to relay broadcasts related to pinned slices. @@ -38,12 +42,22 @@ public class SliceBroadcastRelay { public static final String EXTRA_URI = "uri"; public static final String EXTRA_RECEIVER = "receiver"; public static final String EXTRA_FILTER = "filter"; + private static final String TAG = "SliceBroadcastRelay"; + + private static final Set<Uri> sRegisteredUris = new ArraySet<>(); - public static void registerReceiver(Context context, Uri registerKey, + /** + * Associate intent filter/sliceUri with corresponding receiver. + */ + public static void registerReceiver(Context context, Uri sliceUri, Class<? extends BroadcastReceiver> receiver, IntentFilter filter) { + + Log.d(TAG, "Registering Uri for broadcast relay: " + sliceUri); + sRegisteredUris.add(sliceUri); + Intent registerBroadcast = new Intent(ACTION_REGISTER); registerBroadcast.setPackage(SYSTEMUI_PACKAGE); - registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey, + registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(sliceUri, Process.myUserHandle().getIdentifier())); registerBroadcast.putExtra(EXTRA_RECEIVER, new ComponentName(context.getPackageName(), receiver.getName())); @@ -52,12 +66,21 @@ public class SliceBroadcastRelay { context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM); } - public static void unregisterReceivers(Context context, Uri registerKey) { - Intent registerBroadcast = new Intent(ACTION_UNREGISTER); + /** + * Unregisters all receivers for a given slice uri. + */ + + public static void unregisterReceivers(Context context, Uri sliceUri) { + if (!sRegisteredUris.contains(sliceUri)) { + return; + } + Log.d(TAG, "Unregistering uri broadcast relay: " + sliceUri); + final Intent registerBroadcast = new Intent(ACTION_UNREGISTER); registerBroadcast.setPackage(SYSTEMUI_PACKAGE); - registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey, + registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(sliceUri, Process.myUserHandle().getIdentifier())); context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM); + sRegisteredUris.remove(sliceUri); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index ac2c2c946725..43affcdfefe9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1065,7 +1065,7 @@ public class AccessPoint implements Comparable<AccessPoint> { } public boolean isSaved() { - return networkId != WifiConfiguration.INVALID_NETWORK_ID; + return mConfig != null; } public Object getTag() { diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 4a5388be2c1e..265d464d9c71 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -22,6 +22,11 @@ android:sharedUserId="android.uid.systemui" coreApp="true"> + <!-- Using OpenGL ES 2.0 --> + <uses-feature + android:glEsVersion="0x00020000" + android:required="true" /> + <!-- SysUI must be the one to define this permission; its name is referenced by the core OS. --> <permission android:name="android.permission.systemui.IDENTITY" diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml index f1158ef11ccc..b7b21fa53b62 100644 --- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml +++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml @@ -16,8 +16,8 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="#4a4a4a" /> + <solid android:color="#242424" /> <!-- 14% of white --> <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding" - android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/> + android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding" /> <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml index 58fe81109731..f64a64e619a0 100644 --- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml @@ -15,6 +15,7 @@ limitations under the License. --> + <com.android.systemui.privacy.OngoingPrivacyChip xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/privacy_chip" @@ -22,47 +23,39 @@ android:layout_width="wrap_content" android:layout_marginLeft="@dimen/ongoing_appops_chip_margin" android:layout_marginRight="@dimen/ongoing_appops_chip_margin" - android:layout_marginTop="@dimen/ongoing_appops_top_chip_margin" - android:layout_marginBottom="@dimen/ongoing_appops_top_chip_margin" - android:gravity="center_vertical|center_horizontal" android:layout_gravity="center_vertical|start" + android:gravity="center_vertical" android:orientation="horizontal" - android:paddingStart="@dimen/ongoing_appops_chip_side_padding" - android:paddingEnd="@dimen/ongoing_appops_chip_side_padding" android:focusable="true"> - <TextView - android:id="@+id/in_use_text" - android:layout_height="match_parent" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical|start" - android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed" - android:gravity="center_vertical" - android:textAppearance="@style/TextAppearance.StatusBar.Clock" - android:textColor="@color/status_bar_clock_color" - android:text="@string/ongoing_privacy_chip_in_use" - /> - <LinearLayout - android:id="@+id/icons_container" - android:layout_height="match_parent" + android:id="@+id/background" + android:layout_height="@dimen/ongoing_appops_chip_height" android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:gravity="center_vertical" - /> + > + <LinearLayout + android:id="@+id/icons_container" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_marginStart="@dimen/ongoing_appops_chip_items_margin" + android:layout_gravity="center_vertical" + android:gravity="center_vertical" + /> - <TextView - android:id="@+id/text_container" - android:layout_height="match_parent" - android:layout_width="wrap_content" - android:singleLine="true" - android:ellipsize="end" - android:lines="1" - android:layout_gravity="center_vertical|end" - android:gravity="center_vertical" - android:textAppearance="@style/TextAppearance.StatusBar.Clock" - android:textColor="@color/status_bar_clock_color" - android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed" - android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed" - /> + <TextView + android:id="@+id/text_container" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical|end" + android:paddingStart="@dimen/ongoing_appops_chip_text_padding" + android:paddingEnd="@dimen/ongoing_appops_chip_text_padding" + android:gravity="center_vertical" + android:singleLine="true" + android:ellipsize="end" + android:lines="1" + android:textAppearance="@style/TextAppearance.StatusBar.Clock" + android:textSize="@dimen/ongoing_appops_chip_text_size" + android:textColor="@color/status_bar_clock_color" + /> + </LinearLayout> </com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl new file mode 100644 index 000000000000..586cdf3fbaae --- /dev/null +++ b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl @@ -0,0 +1,27 @@ +precision mediump float; + +uniform sampler2D uTexture; +uniform float uCenterReveal; +uniform float uReveal; +uniform float uAod2Opacity; +varying vec2 vTextureCoordinates; + +vec3 luminosity(vec3 color) { + float lum = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; + return vec3(lum); +} + +vec4 transform(vec3 diffuse) { + // TODO: Add well comments here, tracking on b/123615467. + vec3 lum = luminosity(diffuse); + diffuse = mix(diffuse, lum, smoothstep(0., uCenterReveal, uReveal)); + float val = mix(uReveal, uCenterReveal, step(uCenterReveal, uReveal)); + diffuse = smoothstep(val, 1.0, diffuse); + diffuse *= uAod2Opacity * (1. - smoothstep(uCenterReveal, 1., uReveal)); + return vec4(diffuse.r, diffuse.g, diffuse.b, 1.); +} + +void main() { + vec4 fragColor = texture2D(uTexture, vTextureCoordinates); + gl_FragColor = transform(fragColor.rgb); +}
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl new file mode 100644 index 000000000000..4393e2bb0ebf --- /dev/null +++ b/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl @@ -0,0 +1,8 @@ +attribute vec4 aPosition; +attribute vec2 aTextureCoordinates; +varying vec2 vTextureCoordinates; + +void main() { + vTextureCoordinates = aTextureCoordinates; + gl_Position = aPosition; +}
\ No newline at end of file diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index df858f0c54e2..bb0c6f6acb06 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -34,5 +34,4 @@ <bool name="quick_settings_wide">true</bool> <dimen name="qs_detail_margin_top">0dp</dimen> <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen> - <dimen name="ongoing_appops_top_chip_margin">2dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 1e1245fe0d86..1c7ee3667c16 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -980,26 +980,32 @@ <dimen name="ongoing_appops_dialog_items_bottom_margin">24dp</dimen> <!-- Top and bottom margin of title in Ongoing App Ops dialog --> <dimen name="ongoing_appops_dialog_title_margin_top_bottom">18dp</dimen> + <!-- Text size for Ongoing App Ops dialog title --> + <dimen name="ongoing_appops_dialog_title_size">20sp</dimen> + <!-- Text size for Ongoing App Ops dialog items --> + <dimen name="ongoing_appops_dialog_item_size">16sp</dimen> <!-- Side margins around the Ongoing App Ops chip--> - <dimen name="ongoing_appops_chip_margin">12dp</dimen> - <!-- Top and bottom margins around the Ongoing App Ops chip --> - <dimen name="ongoing_appops_top_chip_margin">12dp</dimen> + <dimen name="ongoing_appops_chip_margin">0dp</dimen> + <!-- Height of the Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_height">32dp</dimen> <!-- Start and End padding for Ongoing App Ops chip --> - <dimen name="ongoing_appops_chip_side_padding">6dp</dimen> + <dimen name="ongoing_appops_chip_text_padding">8dp</dimen> <!-- Padding between background of Ongoing App Ops chip and content --> <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen> + <!-- Side padding between background of Ongoing App Ops chip and content --> + <dimen name="ongoing_appops_chip_side_padding">8dp</dimen> <!-- Margin between icons of Ongoing App Ops chip when QQS--> <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen> <!-- Margin between icons of Ongoing App Ops chip when QS--> - <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen> + <dimen name="ongoing_appops_chip_icon_margin_expanded">2dp</dimen> <!-- Icon size of Ongoing App Ops chip --> - <dimen name="ongoing_appops_chip_icon_size">18dp</dimen> + <dimen name="ongoing_appops_chip_icon_size">@*android:dimen/status_bar_icon_size</dimen> <!-- Radius of Ongoing App Ops chip corners --> - <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen> - <!-- Text size for Ongoing App Ops dialog title --> - <dimen name="ongoing_appops_dialog_title_size">20sp</dimen> - <!-- Text size for Ongoing App Ops dialog items --> - <dimen name="ongoing_appops_dialog_item_size">16sp</dimen> + <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen> + <!-- Size of text of Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_text_size">12sp</dimen> + <!-- Margin between items in Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_items_margin">8dp</dimen> <!-- How much a bubble is elevated --> <dimen name="bubble_elevation">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index b4131d738d13..01595f0705be 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1582,19 +1582,19 @@ <!-- Notification Inline controls: continue receiving notifications prompt, channel level --> <string name="inline_keep_showing">Keep showing these notifications?</string> - <!-- Notification inline controls: block notifications button --> + <!-- Notification inline controls: block notifications button [CHAR_LIMIT=25] --> <string name="inline_stop_button">Stop notifications</string> <!-- Notification inline controls: button to deliver notifications silently from this channel [CHAR_LIMIT=35] --> <string name="inline_deliver_silently_button">Deliver Silently</string> - <!-- Notification inline controls: button to block notifications from this channel [CHAR_LIMIT=35] --> + <!-- Notification inline controls: button to block notifications from this channel [CHAR_LIMIT=20] --> <string name="inline_block_button">Block</string> - <!-- Notification inline controls: keep getting notifications button --> + <!-- Notification inline controls: keep getting notifications button [CHAR_LIMIT=25] --> <string name="inline_keep_button">Keep showing</string> - <!-- Notification inline controls: minimize notifications button --> + <!-- Notification inline controls: minimize notifications button [CHAR_LIMIT=20] --> <string name="inline_minimize_button">Minimize</string> <!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index f277c4303ac1..3ac7fd4c61c1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -724,6 +724,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private void handleFaceAuthFailed() { + setFaceRunningState(BIOMETRIC_STATE_STOPPED); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 2aecc24e83c0..7e645ab77a63 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -28,7 +28,9 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region.Op; import android.hardware.display.DisplayManager; +import android.opengl.GLSurfaceView; import android.os.AsyncTask; +import android.os.Build; import android.os.Handler; import android.os.Trace; import android.service.wallpaper.WallpaperService; @@ -39,6 +41,7 @@ import android.view.Surface; import android.view.SurfaceHolder; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.glwallpaper.ImageWallpaperRenderer; import java.io.FileDescriptor; import java.io.IOException; @@ -73,10 +76,78 @@ public class ImageWallpaper extends WallpaperService { @Override public Engine onCreateEngine() { - mEngine = new DrawableEngine(); - return mEngine; + if (Build.IS_DEBUGGABLE) { + Log.v(TAG, "We are using GLEngine"); + } + return new GLEngine(this); + } + + class GLEngine extends Engine { + private GLWallpaperSurfaceView mWallpaperSurfaceView; + + GLEngine(Context context) { + mWallpaperSurfaceView = new GLWallpaperSurfaceView(context); + mWallpaperSurfaceView.setRenderer( + new ImageWallpaperRenderer(context, mWallpaperSurfaceView)); + mWallpaperSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); + setOffsetNotificationsEnabled(true); + } + + @Override + public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { + if (mWallpaperSurfaceView != null) { + mWallpaperSurfaceView.notifyAmbientModeChanged(inAmbientMode, animationDuration); + } + } + + @Override + public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, + float yOffsetStep, int xPixelOffset, int yPixelOffset) { + if (mWallpaperSurfaceView != null) { + mWallpaperSurfaceView.notifyOffsetsChanged(xOffset, yOffset); + } + } + + private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView { + private WallpaperStatusListener mWallpaperChangedListener; + + GLWallpaperSurfaceView(Context context) { + super(context); + setEGLContextClientVersion(2); + } + + @Override + public SurfaceHolder getHolder() { + return getSurfaceHolder(); + } + + @Override + public void setRenderer(Renderer renderer) { + super.setRenderer(renderer); + mWallpaperChangedListener = (WallpaperStatusListener) renderer; + } + + private void notifyAmbientModeChanged(boolean inAmbient, long duration) { + if (mWallpaperChangedListener != null) { + mWallpaperChangedListener.onAmbientModeChanged(inAmbient, duration); + } + } + + private void notifyOffsetsChanged(float xOffset, float yOffset) { + if (mWallpaperChangedListener != null) { + mWallpaperChangedListener.onOffsetsChanged( + xOffset, yOffset, getHolder().getSurfaceFrame()); + } + } + + @Override + public void render() { + requestRender(); + } + } } + // TODO: Remove this engine, tracking on b/123617158. class DrawableEngine extends Engine { private final Runnable mUnloadWallpaperCallback = () -> { unloadWallpaper(false /* forgetSize */); @@ -564,4 +635,35 @@ public class ImageWallpaper extends WallpaperService { } } } + + /** + * A listener to trace status of image wallpaper. + */ + public interface WallpaperStatusListener { + + /** + * Called back while ambient mode changes. + * @param inAmbientMode true if is in ambient mode, false otherwise. + * @param duration the duration of animation. + */ + void onAmbientModeChanged(boolean inAmbientMode, long duration); + + /** + * Called back while wallpaper offsets. + * @param xOffset The offset portion along x. + * @param yOffset The offset portion along y. + */ + void onOffsetsChanged(float xOffset, float yOffset, Rect frame); + } + + /** + * An abstraction for view of GLRenderer. + */ + public interface ImageGLView { + + /** + * Ask the view to render. + */ + void render(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 6d583df6082b..6bb4fb5ef94a 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -41,6 +41,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; +import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; @@ -141,7 +142,7 @@ public class SystemUIFactory { StatusBar statusBar, StatusBarStateController statusBarStateController, NotificationListener listener) { return new NotificationIconAreaController(context, statusBar, statusBarStateController, - listener); + listener, Dependency.get(NotificationMediaManager.class)); } public KeyguardIndicationController createKeyguardIndicationController(Context context, diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index be2dd679bba5..e62c77de0051 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -52,7 +52,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.phone.StatusBarWindowController; import java.util.List; @@ -315,8 +315,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe } @Override - public void onEntryInflated(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + public void onEntryInflated(NotificationEntry entry, @InflationFlag int inflatedFlags) { if (!areBubblesEnabled(mContext)) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 62cc8895ac73..ed9b38b85156 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -58,7 +58,7 @@ import java.math.RoundingMode; /** * Renders bubbles in a stack and handles animating expanded and collapsed states. */ -public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.FloatingView { +public class BubbleStackView extends FrameLayout { private static final String TAG = "BubbleStackView"; /** @@ -146,8 +146,9 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F mBubbleData = data; mInflater = LayoutInflater.from(context); - mTouchHandler = new BubbleTouchHandler(context); + mTouchHandler = new BubbleTouchHandler(context, this); setOnTouchListener(mTouchHandler); + mInflater = LayoutInflater.from(context); Resources res = getResources(); mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); @@ -199,6 +200,8 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)); setClipChildren(false); + + mBubbleContainer.bringToFront(); } @Override @@ -484,9 +487,10 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F if (shouldExpand) { mBubbleContainer.setController(mExpandedAnimationController); mExpandedAnimationController.expandFromStack( - mStackAnimationController.getStackPosition(), () -> { - updatePointerPosition(); - updateAfter.run(); + mStackAnimationController.getStackPosition(), + () -> { + updatePointerPosition(); + updateAfter.run(); }); } else { mBubbleContainer.cancelAllAnimations(); @@ -544,55 +548,49 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F : null; } - @Override - public void setPosition(float x, float y) { - mStackAnimationController.moveFirstBubbleWithStackFollowing(x, y); - } - - @Override - public void setPositionX(float x) { - // Unsupported, use setPosition(x, y). - } - - @Override - public void setPositionY(float y) { - // Unsupported, use setPosition(x, y). - } - - @Override - public PointF getPosition() { + public PointF getStackPosition() { return mStackAnimationController.getStackPosition(); } /** Called when a drag operation on an individual bubble has started. */ - public void onBubbleDragStart(BubbleView bubble) { - // TODO: Save position and snap back if not dismissed. + public void onBubbleDragStart(View bubble) { + mExpandedAnimationController.prepareForBubbleDrag(bubble); } /** Called with the coordinates to which an individual bubble has been dragged. */ - public void onBubbleDragged(BubbleView bubble, float x, float y) { - bubble.setTranslationX(x); - bubble.setTranslationY(y); + public void onBubbleDragged(View bubble, float x, float y) { + if (!mIsExpanded || mIsAnimating) { + return; + } + + mExpandedAnimationController.dragBubbleOut(bubble, x, y); } /** Called when a drag operation on an individual bubble has finished. */ - public void onBubbleDragFinish(BubbleView bubble, float x, float y, float velX, float velY) { - // TODO: Add fling to bottom to dismiss. + public void onBubbleDragFinish( + View bubble, float x, float y, float velX, float velY, boolean dismissed) { + if (!mIsExpanded || mIsAnimating) { + return; + } + + if (dismissed) { + mExpandedAnimationController.prepareForDismissalWithVelocity(bubble, velX, velY); + } else { + mExpandedAnimationController.snapBubbleBack(bubble, velX, velY); + } } void onDragStart() { - if (mIsExpanded) { + if (mIsExpanded || mIsAnimating) { return; } mStackAnimationController.cancelStackPositionAnimations(); mBubbleContainer.setController(mStackAnimationController); - mIsAnimating = false; } void onDragged(float x, float y) { - // TODO: We can drag if animating - just need to reroute inflight anims to drag point. - if (mIsExpanded) { + if (mIsExpanded || mIsAnimating) { return; } @@ -744,9 +742,9 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F private void updatePointerPosition() { if (mExpandedBubble != null) { - float pointerPosition = mExpandedBubble.iconView.getPosition().x + float pointerPosition = mExpandedBubble.iconView.getTranslationX() + (mExpandedBubble.iconView.getWidth() / 2f); - mExpandedBubble.expandedView.setPointerPosition(pointerPosition); + mExpandedBubble.expandedView.setPointerPosition((int) pointerPosition); } } @@ -772,7 +770,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * @return the normalized x-axis position of the bubble stack rounded to 4 decimal places. */ public float getNormalizedXPosition() { - return new BigDecimal(getPosition().x / mDisplaySize.x) + return new BigDecimal(getStackPosition().x / mDisplaySize.x) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); } @@ -781,7 +779,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * @return the normalized y-axis position of the bubble stack rounded to 4 decimal places. */ public float getNormalizedYPosition() { - return new BigDecimal(getPosition().y / mDisplaySize.y) + return new BigDecimal(getStackPosition().y / mDisplaySize.y) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java index 7d3c0f85c0f7..165eb1dda077 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java @@ -34,17 +34,16 @@ import com.android.systemui.pip.phone.PipDismissViewController; * dismissing, and flings. */ class BubbleTouchHandler implements View.OnTouchListener { + /** Velocity required to dismiss a bubble without dragging it into the dismiss target. */ + private static final float DISMISS_MIN_VELOCITY = 4000f; + + private final PointF mTouchDown = new PointF(); + private final PointF mViewPositionOnTouchDown = new PointF(); + private final BubbleStackView mStack; private BubbleController mController = Dependency.get(BubbleController.class); private PipDismissViewController mDismissViewController; - // The position of the bubble on down event - private float mBubbleDownPosX; - private float mBubbleDownPosY; - // The touch position on down event - private float mDownX = -1; - private float mDownY = -1; - private boolean mMovedEnough; private int mTouchSlopSquared; private VelocityTracker mVelocityTracker; @@ -58,65 +57,42 @@ class BubbleTouchHandler implements View.OnTouchListener { } }; - // Bubble being dragged from the row of bubbles when the stack is expanded - private BubbleView mBubbleDraggingOut; - - /** - * Views movable by this touch handler should implement this interface. - */ - public interface FloatingView { - - /** - * Sets the position of the view. - */ - void setPosition(float x, float y); - - /** - * Sets the x position of the view. - */ - void setPositionX(float x); - - /** - * Sets the y position of the view. - */ - void setPositionY(float y); - - /** - * @return the position of the view. - */ - PointF getPosition(); - } + /** View that was initially touched, when we received the first ACTION_DOWN event. */ + private View mTouchedView; - public BubbleTouchHandler(Context context) { + BubbleTouchHandler(Context context, BubbleStackView stackView) { final int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mTouchSlopSquared = touchSlop * touchSlop; mDismissViewController = new PipDismissViewController(context); + mStack = stackView; } @Override public boolean onTouch(View v, MotionEvent event) { - int action = event.getActionMasked(); - - BubbleStackView stack = (BubbleStackView) v; - View targetView = mBubbleDraggingOut != null - ? mBubbleDraggingOut - : stack.getTargetView(event); - boolean isFloating = targetView instanceof FloatingView; - if (!isFloating || targetView == null || action == MotionEvent.ACTION_OUTSIDE) { - stack.collapseStack(); + final int action = event.getActionMasked(); + + // If we aren't currently in the process of touching a view, figure out what we're touching. + // It'll be the stack, an individual bubble, or nothing. + if (mTouchedView == null) { + mTouchedView = mStack.getTargetView(event); + } + + // If this is an ACTION_OUTSIDE event, or the stack reported that we aren't touching + // anything, collapse the stack. + if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) { + mStack.collapseStack(); cleanUpDismissTarget(); - resetTouches(); + mTouchedView = null; return false; } - FloatingView floatingView = (FloatingView) targetView; - boolean isBubbleStack = floatingView instanceof BubbleStackView; + final boolean isStack = mStack.equals(mTouchedView); + final float rawX = event.getRawX(); + final float rawY = event.getRawY(); - PointF startPos = floatingView.getPosition(); - float rawX = event.getRawX(); - float rawY = event.getRawY(); - float x = mBubbleDownPosX + rawX - mDownX; - float y = mBubbleDownPosY + rawY - mDownY; + // The coordinates of the touch event, in terms of the touched view's position. + final float viewX = mViewPositionOnTouchDown.x + rawX - mTouchDown.x; + final float viewY = mViewPositionOnTouchDown.y + rawY - mTouchDown.y; switch (action) { case MotionEvent.ACTION_DOWN: trackMovement(event); @@ -124,87 +100,83 @@ class BubbleTouchHandler implements View.OnTouchListener { mDismissViewController.createDismissTarget(); mHandler.postDelayed(mShowDismissAffordance, SHOW_TARGET_DELAY); - mBubbleDownPosX = startPos.x; - mBubbleDownPosY = startPos.y; - mDownX = rawX; - mDownY = rawY; - mMovedEnough = false; + mTouchDown.set(rawX, rawY); - if (isBubbleStack) { - stack.onDragStart(); + if (isStack) { + mViewPositionOnTouchDown.set(mStack.getStackPosition()); + mStack.onDragStart(); } else { - stack.onBubbleDragStart((BubbleView) floatingView); + mViewPositionOnTouchDown.set( + mTouchedView.getTranslationX(), mTouchedView.getTranslationY()); + mStack.onBubbleDragStart(mTouchedView); } break; - case MotionEvent.ACTION_MOVE: trackMovement(event); + final float deltaX = rawX - mTouchDown.x; + final float deltaY = rawY - mTouchDown.y; - if (mBubbleDownPosX == -1 || mDownX == -1) { - mBubbleDownPosX = startPos.x; - mBubbleDownPosY = startPos.y; - mDownX = rawX; - mDownY = rawY; - } - final float deltaX = rawX - mDownX; - final float deltaY = rawY - mDownY; if ((deltaX * deltaX) + (deltaY * deltaY) > mTouchSlopSquared && !mMovedEnough) { mMovedEnough = true; } if (mMovedEnough) { - if (floatingView instanceof BubbleView) { - mBubbleDraggingOut = ((BubbleView) floatingView); - stack.onBubbleDragged(mBubbleDraggingOut, x, y); + if (isStack) { + mStack.onDragged(viewX, viewY); } else { - stack.onDragged(x, y); + mStack.onBubbleDragged(mTouchedView, viewX, viewY); } } + // TODO - when we're in the target stick to it / animate in some way? mInDismissTarget = mDismissViewController.updateTarget( - isBubbleStack ? stack.getBubbleAt(0) : (View) floatingView); + isStack ? mStack.getBubbleAt(0) : mTouchedView); break; case MotionEvent.ACTION_CANCEL: - resetTouches(); + mTouchedView = null; cleanUpDismissTarget(); break; case MotionEvent.ACTION_UP: trackMovement(event); - if (mInDismissTarget) { - if (isBubbleStack) { - mController.dismissStack(); - } else { - mController.removeBubble(((BubbleView) floatingView).getKey()); - } + if (mInDismissTarget && isStack) { + mController.dismissStack(); } else if (mMovedEnough) { mVelocityTracker.computeCurrentVelocity(1000); final float velX = mVelocityTracker.getXVelocity(); final float velY = mVelocityTracker.getYVelocity(); - if (isBubbleStack) { - stack.onDragFinish(x, y, velX, velY); + if (isStack) { + mStack.onDragFinish(viewX, viewY, velX, velY); } else { - stack.onBubbleDragFinish(mBubbleDraggingOut, x, y, velX, velY); + final boolean dismissed = mInDismissTarget || velY > DISMISS_MIN_VELOCITY; + mStack.onBubbleDragFinish( + mTouchedView, viewX, viewY, velX, velY, /* dismissed */ dismissed); + if (dismissed) { + mController.removeBubble(((BubbleView) mTouchedView).getKey()); + } } - } else if (floatingView.equals(stack.getExpandedBubbleView())) { - stack.collapseStack(); - } else if (isBubbleStack) { - if (stack.isExpanded()) { - stack.collapseStack(); + } else if (mTouchedView.equals(mStack.getExpandedBubbleView())) { + mStack.collapseStack(); + } else if (isStack) { + if (mStack.isExpanded()) { + mStack.collapseStack(); } else { - stack.expandStack(); + mStack.expandStack(); } } else { - stack.setExpandedBubble(((BubbleView) floatingView).getKey()); + mStack.setExpandedBubble(((BubbleView) mTouchedView).getKey()); } + cleanUpDismissTarget(); mVelocityTracker.recycle(); mVelocityTracker = null; - resetTouches(); + mTouchedView = null; + mMovedEnough = false; break; } + return true; } @@ -216,16 +188,6 @@ class BubbleTouchHandler implements View.OnTouchListener { mDismissViewController.destroyDismissTarget(); } - /** - * Resets anything we care about after a gesture is complete. - */ - private void resetTouches() { - mDownX = -1; - mDownY = -1; - mBubbleDownPosX = -1; - mBubbleDownPosY = -1; - mBubbleDraggingOut = null; - } private void trackMovement(MotionEvent event) { if (mVelocityTracker == null) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index 1a4b19940e34..b409a3181e2b 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -20,7 +20,6 @@ import android.annotation.Nullable; import android.app.Notification; import android.content.Context; import android.graphics.Color; -import android.graphics.PointF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; @@ -39,7 +38,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow /** * A floating object on the screen that can post message updates. */ -public class BubbleView extends FrameLayout implements BubbleTouchHandler.FloatingView { +public class BubbleView extends FrameLayout { private static final String TAG = "BubbleView"; // Same value as Launcher3 badge code @@ -217,25 +216,4 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati // XXX: should we pull from the drawable, app icon, notif tint? return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA); } - - @Override - public void setPosition(float x, float y) { - setPositionX(x); - setPositionY(y); - } - - @Override - public void setPositionX(float x) { - setTranslationX(x); - } - - @Override - public void setPositionY(float y) { - setTranslationY(y); - } - - @Override - public PointF getPosition() { - return new PointF(getTranslationX(), getTranslationY()); - } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java index 5b158e906356..9fd26b80e385 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java @@ -44,6 +44,9 @@ public class ExpandedAnimationController */ private static final int ANIMATE_TRANSLATION_FACTOR = 4; + /** How much to scale down bubbles when they're animating in/out. */ + private static final float ANIMATE_SCALE_PERCENT = 0.5f; + /** * The stack position from which the bubbles were expanded. Saved in {@link #expandFromStack} * and used to return to stack form in {@link #collapseBackToStack}. @@ -59,6 +62,22 @@ public class ExpandedAnimationController /** Height of the status bar. */ private float mStatusBarHeight; + /** + * Whether the individual bubble has been dragged out of the row of bubbles far enough to cause + * the rest of the bubbles to animate to fill the gap. + */ + private boolean mBubbleDraggedOutEnough = false; + + /** The bubble currently being dragged out of the row (to potentially be dismissed). */ + private View mBubbleDraggingOut; + + /** + * Drag velocities for the dragging-out bubble when the drag finished. These are used by + * {@link #onChildRemoved} to animate out the bubble while respecting touch velocity. + */ + private float mBubbleDraggingOutVelX; + private float mBubbleDraggingOutVelY; + @Override protected void setLayout(PhysicsAnimationLayout layout) { super.setLayout(layout); @@ -102,6 +121,87 @@ public class ExpandedAnimationController runAfterTranslationsEnd(after); } + /** Prepares the given bubble to be dragged out. */ + public void prepareForBubbleDrag(View bubble) { + mLayout.cancelAnimationsOnView(bubble); + + mBubbleDraggingOut = bubble; + mBubbleDraggingOut.setTranslationZ(Short.MAX_VALUE); + } + + /** + * Drags an individual bubble to the given coordinates. Bubbles to the right will animate to + * take its place once it's dragged out of the row of bubbles, and animate out of the way if the + * bubble is dragged back into the row. + */ + public void dragBubbleOut(View bubbleView, float x, float y) { + bubbleView.setTranslationX(x); + bubbleView.setTranslationY(y); + + final boolean draggedOutEnough = + y > getExpandedY() + mBubbleSizePx || y < getExpandedY() - mBubbleSizePx; + if (draggedOutEnough != mBubbleDraggedOutEnough) { + animateStackByBubbleWidthsStartingFrom( + /* numBubbleWidths */ draggedOutEnough ? -1 : 0, + /* startIndex */ mLayout.indexOfChild(bubbleView) + 1); + mBubbleDraggedOutEnough = draggedOutEnough; + } + } + + /** + * Snaps a bubble back to its position within the bubble row, and animates the rest of the + * bubbles to accommodate it if it was previously dragged out past the threshold. + */ + public void snapBubbleBack(View bubbleView, float velX, float velY) { + final int index = mLayout.indexOfChild(bubbleView); + + // Snap the bubble back, respecting its current velocity. + mLayout.animateValueForChildAtIndex( + DynamicAnimation.TRANSLATION_X, index, getXForChildAtIndex(index), velX); + mLayout.animateValueForChildAtIndex( + DynamicAnimation.TRANSLATION_Y, index, getExpandedY(), velY); + mLayout.setEndListenerForProperties( + mLayout.new OneTimeMultiplePropertyEndListener() { + @Override + void onAllAnimationsForPropertiesEnd() { + // Reset Z translation once the bubble is done snapping back. + bubbleView.setTranslationZ(0f); + } + }, + DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); + + animateStackByBubbleWidthsStartingFrom( + /* numBubbleWidths */ 0, /* startIndex */ index + 1); + + mBubbleDraggingOut = null; + mBubbleDraggedOutEnough = false; + } + + /** + * Sets configuration variables so that when the given bubble is removed, the animations are + * started with the given velocities. + */ + public void prepareForDismissalWithVelocity(View bubbleView, float velX, float velY) { + mBubbleDraggingOut = bubbleView; + mBubbleDraggingOutVelX = velX; + mBubbleDraggingOutVelY = velY; + mBubbleDraggedOutEnough = false; + } + + /** + * Animates the bubbles, starting at the given index, to the left or right by the given number + * of bubble widths. Passing zero for numBubbleWidths will animate the bubbles to their normal + * positions. + */ + private void animateStackByBubbleWidthsStartingFrom(int numBubbleWidths, int startIndex) { + for (int i = startIndex; i < mLayout.getChildCount(); i++) { + mLayout.animateValueForChildAtIndex( + DynamicAnimation.TRANSLATION_X, + i, + getXForChildAtIndex(i + numBubbleWidths)); + } + } + /** The Y value of the row of expanded bubbles. */ private float getExpandedY() { final WindowInsets insets = mLayout.getRootWindowInsets(); @@ -165,12 +265,7 @@ public class ExpandedAnimationController child.setTranslationX(getXForChildAtIndex(index)); child.setTranslationY(getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR); mLayout.animateValueForChild(DynamicAnimation.TRANSLATION_Y, child, getExpandedY()); - - // Animate the remaining bubbles to the correct X position. - for (int i = index + 1; i < mLayout.getChildCount(); i++) { - mLayout.animateValueForChildAtIndex( - DynamicAnimation.TRANSLATION_X, i, getXForChildAtIndex(i)); - } + animateBubblesAfterIndexToCorrectX(index); } @Override @@ -179,16 +274,36 @@ public class ExpandedAnimationController // TODO: Reverse this when bubbles are at the bottom. mLayout.animateValueForChild( DynamicAnimation.ALPHA, child, 0f, finishRemoval); - mLayout.animateValueForChild( - DynamicAnimation.TRANSLATION_Y, - child, - getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR); - // Animate the remaining bubbles to the correct X position. - for (int i = index; i < mLayout.getChildCount(); i++) { - mLayout.animateValueForChildAtIndex( - DynamicAnimation.TRANSLATION_X, i, getXForChildAtIndex(i)); + // If we're removing the dragged-out bubble, that means it got dismissed. + if (child.equals(mBubbleDraggingOut)) { + // Throw it to the bottom of the screen, towards the center horizontally. + mLayout.animateValueForChild( + DynamicAnimation.TRANSLATION_X, + child, + mLayout.getWidth() / 2f - mBubbleSizePx / 2f, + mBubbleDraggingOutVelX); + mLayout.animateValueForChild( + DynamicAnimation.TRANSLATION_Y, + child, + mLayout.getHeight() + mBubbleSizePx, + mBubbleDraggingOutVelY); + + // Scale it down a bit so it looks like it's disappearing. + mLayout.animateValueForChild(DynamicAnimation.SCALE_X, child, ANIMATE_SCALE_PERCENT); + mLayout.animateValueForChild(DynamicAnimation.SCALE_Y, child, ANIMATE_SCALE_PERCENT); + + mBubbleDraggingOut = null; + } else { + // If we're removing some random bubble just throw it off the top. + mLayout.animateValueForChild( + DynamicAnimation.TRANSLATION_Y, + child, + getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR); } + + // Animate all the other bubbles to their new positions sans this bubble. + animateBubblesAfterIndexToCorrectX(index); } @Override @@ -207,6 +322,23 @@ public class ExpandedAnimationController () -> super.setChildVisibility(child, index, visibility)); } + /** + * Animates the bubbles after the given index to the X position they should be in according to + * {@link #getXForChildAtIndex}. + */ + private void animateBubblesAfterIndexToCorrectX(int start) { + for (int i = start; i < mLayout.getChildCount(); i++) { + final View bubble = mLayout.getChildAt(i); + + // Don't animate the dragging out bubble, or it'll jump around while being dragged. It + // will be snapped to the correct X value after the drag (if it's not dismissed). + if (!bubble.equals(mBubbleDraggingOut)) { + mLayout.animateValueForChild( + DynamicAnimation.TRANSLATION_X, bubble, getXForChildAtIndex(i)); + } + } + } + /** Returns the appropriate X translation value for a bubble at the given index. */ private float getXForChildAtIndex(int index) { return mBubblePaddingPx + (mBubbleSizePx + mBubblePaddingPx) * index; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java index a4ddbf752316..dfdcfc9f3b74 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java @@ -187,6 +187,20 @@ public class PhysicsAnimationLayout extends FrameLayout { } /** + * Sets an end listener that will be called whenever any of the given properties' animations + * end. For example, setting a listener for TRANSLATION_X and TRANSLATION_Y will result in that + * listener being called twice - once when all TRANSLATION_X animations end, and again when all + * TRANSLATION_Y animations end. + */ + public void setEndListenerForProperties( + DynamicAnimation.OnAnimationEndListener endListener, + DynamicAnimation.ViewProperty... properties) { + for (DynamicAnimation.ViewProperty property : properties) { + setEndListenerForProperty(endListener, property); + } + } + + /** * Removes the end listener that would have been called when all child animations for a given * property stopped running. */ @@ -197,7 +211,6 @@ public class PhysicsAnimationLayout extends FrameLayout { @Override public void addView(View child, int index, ViewGroup.LayoutParams params) { super.addView(child, index, params); - setChildrenVisibility(); // Set up animations for the new view, if the controller is set. If it isn't set, we'll be // setting up animations for all children when setController is called. @@ -208,6 +221,8 @@ public class PhysicsAnimationLayout extends FrameLayout { mController.onChildAdded(child, index); } + + setChildrenVisibility(); } @Override @@ -294,6 +309,13 @@ public class PhysicsAnimationLayout extends FrameLayout { } } + /** Cancels all of the physics animations running on the given view. */ + public void cancelAnimationsOnView(View view) { + for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) { + getAnimationFromView(property, view).cancel(); + } + } + /** * Animates the property of the given child view, then runs the callback provided when the * animation ends. @@ -318,6 +340,11 @@ public class PhysicsAnimationLayout extends FrameLayout { }); } + // Set the start velocity if it's something other than the not-set value. + if (startVel != Float.MAX_VALUE) { + animation.setStartVelocity(startVel); + } + animation.animateToFinalPosition(value); } } @@ -337,6 +364,14 @@ public class PhysicsAnimationLayout extends FrameLayout { animateValueForChild(property, view, value, Float.MAX_VALUE, /* after */ null); } + protected void animateValueForChild( + DynamicAnimation.ViewProperty property, + View view, + float value, + float startVel) { + animateValueForChild(property, view, value, startVel, /* after */ null); + } + /** * Animates the property of the child at the given index to the given value, then runs the * callback provided when the animation ends. @@ -414,7 +449,13 @@ public class PhysicsAnimationLayout extends FrameLayout { */ private SpringAnimation getAnimationAtIndex( DynamicAnimation.ViewProperty property, int index) { - return (SpringAnimation) getChildAt(index).getTag(getTagIdForProperty(property)); + return getAnimationFromView(property, getChildAt(index)); + } + + /** Retrieves the animation of the given property from the view via the view tag system. */ + private SpringAnimation getAnimationFromView( + DynamicAnimation.ViewProperty property, View view) { + return (SpringAnimation) view.getTag(getTagIdForProperty(property)); } /** Sets up SpringAnimations of the given property for each child view in the layout. */ @@ -528,4 +569,33 @@ public class PhysicsAnimationLayout extends FrameLayout { } } } + + /** + * One time end listener that waits for every animation on every given property to finish. At + * that point, it calls {@link #onAllAnimationsForPropertiesEnd} and then removes itself as an + * end listener from each property. + */ + public abstract class OneTimeMultiplePropertyEndListener + implements DynamicAnimation.OnAnimationEndListener { + final DynamicAnimation.ViewProperty[] mViewProperties; + + OneTimeMultiplePropertyEndListener(DynamicAnimation.ViewProperty... properties) { + mViewProperties = properties; + } + + @Override + public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, + float velocity) { + if (!arePropertiesAnimating(mViewProperties)) { + onAllAnimationsForPropertiesEnd(); + + for (DynamicAnimation.ViewProperty property : mViewProperties) { + removeEndListenerForProperty(property); + } + } + } + + /** Called when every animation for every property has finished. */ + abstract void onAllAnimationsForPropertiesEnd(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java new file mode 100644 index 000000000000..d03b00bcfc85 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.glwallpaper; + +import static android.opengl.GLES20.GL_FRAGMENT_SHADER; +import static android.opengl.GLES20.GL_VERTEX_SHADER; +import static android.opengl.GLES20.glAttachShader; +import static android.opengl.GLES20.glCompileShader; +import static android.opengl.GLES20.glCreateProgram; +import static android.opengl.GLES20.glCreateShader; +import static android.opengl.GLES20.glGetAttribLocation; +import static android.opengl.GLES20.glGetUniformLocation; +import static android.opengl.GLES20.glLinkProgram; +import static android.opengl.GLES20.glShaderSource; +import static android.opengl.GLES20.glUseProgram; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * This class takes charge of linking shader codes and then return a handle for OpenGL ES program. + */ +class ImageGLProgram { + private static final String TAG = ImageGLProgram.class.getSimpleName(); + + private Context mContext; + private int mProgramHandle; + + ImageGLProgram(Context context) { + mContext = context.getApplicationContext(); + } + + private int loadShaderProgram(int vertexId, int fragmentId) { + final String vertexSrc = getShaderResource(vertexId); + final String fragmentSrc = getShaderResource(fragmentId); + final int vertexHandle = getShaderHandle(GL_VERTEX_SHADER, vertexSrc); + final int fragmentHandle = getShaderHandle(GL_FRAGMENT_SHADER, fragmentSrc); + return getProgramHandle(vertexHandle, fragmentHandle); + } + + private String getShaderResource(int shaderId) { + Resources res = mContext.getResources(); + StringBuilder code = new StringBuilder(); + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(res.openRawResource(shaderId)))) { + String nextLine; + while ((nextLine = reader.readLine()) != null) { + code.append(nextLine).append("\n"); + } + } catch (IOException | Resources.NotFoundException ex) { + Log.d(TAG, "Can not read the shader source", ex); + code = null; + } + + return code == null ? "" : code.toString(); + } + + private int getShaderHandle(int type, String src) { + final int shader = glCreateShader(type); + if (shader == 0) { + Log.d(TAG, "Create shader failed, type=" + type); + return 0; + } + glShaderSource(shader, src); + glCompileShader(shader); + return shader; + } + + private int getProgramHandle(int vertexHandle, int fragmentHandle) { + final int program = glCreateProgram(); + if (program == 0) { + Log.d(TAG, "Can not create OpenGL ES program"); + return 0; + } + + glAttachShader(program, vertexHandle); + glAttachShader(program, fragmentHandle); + glLinkProgram(program); + return program; + } + + boolean useGLProgram(int vertexResId, int fragmentResId) { + mProgramHandle = loadShaderProgram(vertexResId, fragmentResId); + glUseProgram(mProgramHandle); + return true; + } + + int getAttributeHandle(String name) { + return glGetAttribLocation(mProgramHandle, name); + } + + int getUniformHandle(String name) { + return glGetUniformLocation(mProgramHandle, name); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java new file mode 100644 index 000000000000..19d85b155cba --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.glwallpaper; + +import static android.opengl.GLES20.GL_FLOAT; +import static android.opengl.GLES20.GL_LINEAR; +import static android.opengl.GLES20.GL_TEXTURE0; +import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; +import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; +import static android.opengl.GLES20.GL_TRIANGLES; +import static android.opengl.GLES20.glActiveTexture; +import static android.opengl.GLES20.glBindTexture; +import static android.opengl.GLES20.glDrawArrays; +import static android.opengl.GLES20.glEnableVertexAttribArray; +import static android.opengl.GLES20.glGenTextures; +import static android.opengl.GLES20.glTexParameteri; +import static android.opengl.GLES20.glUniform1i; +import static android.opengl.GLES20.glVertexAttribPointer; + +import android.graphics.Bitmap; +import android.opengl.GLUtils; +import android.os.Build; +import android.util.Log; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +/** + * This class takes charge of the geometry data like vertices and texture coordinates. + * It delivers these data to opengl runtime and triggers draw calls if necessary. + */ +class ImageGLWallpaper { + private static final String TAG = ImageGLWallpaper.class.getSimpleName(); + + static final String A_POSITION = "aPosition"; + static final String A_TEXTURE_COORDINATES = "aTextureCoordinates"; + static final String U_CENTER_REVEAL = "uCenterReveal"; + static final String U_REVEAL = "uReveal"; + static final String U_AOD2OPACITY = "uAod2Opacity"; + static final String U_TEXTURE = "uTexture"; + + private static final int HANDLE_UNDEFINED = -1; + private static final int POSITION_COMPONENT_COUNT = 2; + private static final int TEXTURE_COMPONENT_COUNT = 2; + private static final int BYTES_PER_FLOAT = 4; + + // Vertices to define the square with 2 triangles. + private static final float[] VERTICES = { + -1.0f, -1.0f, + +1.0f, -1.0f, + +1.0f, +1.0f, + +1.0f, +1.0f, + -1.0f, +1.0f, + -1.0f, -1.0f + }; + + // Texture coordinates that maps to vertices. + private static final float[] TEXTURES = { + 0f, 1f, + 1f, 1f, + 1f, 0f, + 1f, 0f, + 0f, 0f, + 0f, 1f + }; + + private final FloatBuffer mVertexBuffer; + private final FloatBuffer mTextureBuffer; + private final ImageGLProgram mProgram; + + private int mAttrPosition; + private int mAttrTextureCoordinates; + private int mUniAod2Opacity; + private int mUniCenterReveal; + private int mUniReveal; + private int mUniTexture; + private int mTextureId; + + ImageGLWallpaper(ImageGLProgram program) { + mProgram = program; + + // Create an float array in opengles runtime (native) and put vertex data. + mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT) + .order(ByteOrder.nativeOrder()) + .asFloatBuffer(); + mVertexBuffer.put(VERTICES); + mVertexBuffer.position(0); + + // Create an float array in opengles runtime (native) and put texture data. + mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT) + .order(ByteOrder.nativeOrder()) + .asFloatBuffer(); + mTextureBuffer.put(TEXTURES); + mTextureBuffer.position(0); + } + + void setup() { + setupAttributes(); + setupUniforms(); + } + + private void setupAttributes() { + mAttrPosition = mProgram.getAttributeHandle(A_POSITION); + mVertexBuffer.position(0); + glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT, + false, 0, mVertexBuffer); + glEnableVertexAttribArray(mAttrPosition); + + mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES); + mTextureBuffer.position(0); + glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT, + false, 0, mTextureBuffer); + glEnableVertexAttribArray(mAttrTextureCoordinates); + } + + private void setupUniforms() { + mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY); + mUniCenterReveal = mProgram.getUniformHandle(U_CENTER_REVEAL); + mUniReveal = mProgram.getUniformHandle(U_REVEAL); + mUniTexture = mProgram.getUniformHandle(U_TEXTURE); + } + + int getHandle(String name) { + switch (name) { + case A_POSITION: + return mAttrPosition; + case A_TEXTURE_COORDINATES: + return mAttrTextureCoordinates; + case U_AOD2OPACITY: + return mUniAod2Opacity; + case U_CENTER_REVEAL: + return mUniCenterReveal; + case U_REVEAL: + return mUniReveal; + case U_TEXTURE: + return mUniTexture; + default: + return HANDLE_UNDEFINED; + } + } + + void draw() { + glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2); + } + + void setupTexture(Bitmap bitmap) { + final int[] tids = new int[1]; + + if (bitmap == null) { + Log.w(TAG, "setupTexture: invalid bitmap"); + return; + } + + // Generate one texture object and store the id in tids[0]. + glGenTextures(1, tids, 0); + if (tids[0] == 0) { + Log.w(TAG, "setupTexture: glGenTextures() failed"); + return; + } + + // Bind a named texture to a texturing target. + glBindTexture(GL_TEXTURE_2D, tids[0]); + // Load the bitmap data and copy it over into the texture object that is currently bound. + GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); + // Use bilinear texture filtering when minification. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // Use bilinear texture filtering when magnification. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + mTextureId = tids[0]; + } + + void useTexture() { + // Set the active texture unit to texture unit 0. + glActiveTexture(GL_TEXTURE0); + // Bind the texture to this unit. + glBindTexture(GL_TEXTURE_2D, mTextureId); + // Let the texture sampler in fragment shader to read form this texture unit. + glUniform1i(mUniTexture, 0); + } + + void adjustTextureCoordinates(Bitmap bitmap, int surfaceWidth, int surfaceHeight, + float xOffset, float yOffset) { + if (bitmap == null) { + Log.d(TAG, "adjustTextureCoordinates: invalid bitmap"); + return; + } + + int bitmapWidth = bitmap.getWidth(); + int bitmapHeight = bitmap.getHeight(); + float ratioW = 1f; + float ratioH = 1f; + float rX = 0f; + float rY = 0f; + float[] coordinates = null; + + final boolean adjustWidth = bitmapWidth > surfaceWidth; + final boolean adjustHeight = bitmapHeight > surfaceHeight; + + if (adjustWidth || adjustHeight) { + coordinates = TEXTURES.clone(); + } + + if (adjustWidth) { + float x = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset) / bitmapWidth; + ratioW = (float) surfaceWidth / bitmapWidth; + float referenceX = x + ratioW > 1f ? 1f - ratioW : x; + for (int i = 0; i < coordinates.length; i += 2) { + if (i == 2 || i == 4 || i == 6) { + coordinates[i] = Math.min(1f, referenceX + ratioW); + } else { + coordinates[i] = referenceX; + } + } + rX = referenceX; + } + + + if (adjustHeight) { + float y = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset) / bitmapHeight; + ratioH = (float) surfaceHeight / bitmapHeight; + float referenceY = y + ratioH > 1f ? 1f - ratioH : y; + for (int i = 1; i < coordinates.length; i += 2) { + if (i == 1 || i == 3 || i == 11) { + coordinates[i] = Math.min(1f, referenceY + ratioH); + } else { + coordinates[i] = referenceY; + } + } + rY = referenceY; + } + + if (adjustWidth || adjustHeight) { + if (Build.IS_DEBUGGABLE) { + Log.d(TAG, "adjustTextureCoordinates: sW=" + surfaceWidth + ", sH=" + surfaceHeight + + ", bW=" + bitmapWidth + ", bH=" + bitmapHeight + + ", rW=" + ratioW + ", rH=" + ratioH + ", rX=" + rX + ", rY=" + rY); + } + mTextureBuffer.put(coordinates); + mTextureBuffer.position(0); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java new file mode 100644 index 000000000000..477e7d7ebf72 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.glwallpaper; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Handler.Callback; +import android.os.Message; +import android.util.Log; + +/** + * A helper class that computes histogram and percentile 85 from a bitmap. + * Percentile 85 will be computed each time the user picks a new image wallpaper. + */ +class ImageProcessHelper { + private static final String TAG = ImageProcessHelper.class.getSimpleName(); + private static final float DEFAULT_PER85 = 0.8f; + private static final int MSG_UPDATE_PER85 = 1; + + /** + * This color matrix will be applied to each pixel to get luminance from rgb by below formula: + * Luminance = .2126f * r + .7152f * g + .0722f * b. + */ + private static final float[] LUMINOSITY_MATRIX = new float[] { + .2126f, .0000f, .0000f, .0000f, .0000f, + .0000f, .7152f, .0000f, .0000f, .0000f, + .0000f, .0000f, .0722f, .0000f, .0000f, + .0000f, .0000f, .0000f, 1.000f, .0000f + }; + + private final Handler mHandler = new Handler(new Callback() { + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_PER85: + mPer85 = (float) msg.obj; + return true; + default: + return false; + } + } + }); + + private float mPer85 = DEFAULT_PER85; + + void startComputingPercentile85(Bitmap bitmap) { + new Per85ComputeTask(mHandler).execute(bitmap); + } + + float getPercentile85() { + return mPer85; + } + + private static class Per85ComputeTask extends AsyncTask<Bitmap, Void, Float> { + private Handler mUpdateHandler; + + Per85ComputeTask(Handler handler) { + super(handler); + mUpdateHandler = handler; + } + + @Override + protected Float doInBackground(Bitmap... bitmaps) { + Bitmap bitmap = bitmaps[0]; + if (bitmap != null) { + int[] histogram = processHistogram(bitmap); + return computePercentile85(bitmap, histogram); + } + Log.e(TAG, "Per85ComputeTask: Can't get bitmap"); + return DEFAULT_PER85; + } + + @Override + protected void onPostExecute(Float result) { + Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_PER85, result); + mUpdateHandler.sendMessage(msg); + } + + private int[] processHistogram(Bitmap bitmap) { + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + Bitmap target = Bitmap.createBitmap(width, height, bitmap.getConfig()); + Canvas canvas = new Canvas(target); + ColorMatrix cm = new ColorMatrix(LUMINOSITY_MATRIX); + Paint paint = new Paint(); + paint.setColorFilter(new ColorMatrixColorFilter(cm)); + canvas.drawBitmap(bitmap, new Matrix(), paint); + + // TODO: Fine tune the performance here, tracking on b/123615079. + int[] histogram = new int[256]; + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + int pixel = target.getPixel(col, row); + int y = Color.red(pixel) + Color.green(pixel) + Color.blue(pixel); + histogram[y]++; + } + } + + return histogram; + } + + private float computePercentile85(Bitmap bitmap, int[] histogram) { + float per85 = DEFAULT_PER85; + int pixelCount = bitmap.getWidth() * bitmap.getHeight(); + float[] acc = new float[256]; + for (int i = 0; i < acc.length; i++) { + acc[i] = (float) histogram[i] / pixelCount; + float prev = i == 0 ? 0f : acc[i - 1]; + float next = acc[i]; + float idx = (float) (i + 1) / 255; + float sum = prev + next; + if (prev < 0.85f && sum >= 0.85f) { + per85 = idx; + } + if (i > 0) { + acc[i] += acc[i - 1]; + } + } + return per85; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java new file mode 100644 index 000000000000..5914236ab349 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.glwallpaper; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; + +import com.android.systemui.Interpolators; + +/** + * Use ValueAnimator and appropriate interpolator to control the progress of reveal transition. + * The transition will happen while getting awake and quit events. + */ +class ImageRevealHelper { + private static final String TAG = ImageRevealHelper.class.getSimpleName(); + private static final float MAX_REVEAL = 0f; + private static final float MIN_REVEAL = 1f; + + private final ValueAnimator mAnimator; + private final RevealStateListener mRevealListener; + private float mReveal = MAX_REVEAL; + private boolean mAwake = false; + + ImageRevealHelper(RevealStateListener listener) { + mRevealListener = listener; + mAnimator = ValueAnimator.ofFloat(); + mAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mAnimator.addUpdateListener(animator -> { + mReveal = (float) animator.getAnimatedValue(); + if (mRevealListener != null) { + mRevealListener.onRevealStateChanged(); + } + }); + mAnimator.addListener(new AnimatorListenerAdapter() { + private boolean mIsCanceled; + + @Override + public void onAnimationCancel(Animator animation) { + mIsCanceled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!mIsCanceled) { + mAwake = !mAwake; + } + mIsCanceled = false; + } + }); + } + + private void animate() { + mAnimator.cancel(); + mAnimator.setFloatValues(mReveal, !mAwake ? MIN_REVEAL : MAX_REVEAL); + mAnimator.start(); + } + + public float getReveal() { + return mReveal; + } + + public boolean isAwake() { + return mAwake; + } + + void updateAwake(boolean awake, long duration) { + mAwake = awake; + mAnimator.setDuration(duration); + animate(); + } + + /** + * A listener to trace value changes of reveal. + */ + public interface RevealStateListener { + + /** + * Called back while reveal status changes. + */ + void onRevealStateChanged(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java new file mode 100644 index 000000000000..991b1161dde2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.glwallpaper; + +import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; +import static android.opengl.GLES20.glClear; +import static android.opengl.GLES20.glClearColor; +import static android.opengl.GLES20.glUniform1f; +import static android.opengl.GLES20.glViewport; + +import android.app.WallpaperManager; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.opengl.GLSurfaceView; +import android.os.Build; +import android.util.Log; + +import com.android.systemui.ImageWallpaper; +import com.android.systemui.ImageWallpaper.ImageGLView; +import com.android.systemui.R; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +/** + * A GL renderer for image wallpaper. + */ +public class ImageWallpaperRenderer implements GLSurfaceView.Renderer, + ImageWallpaper.WallpaperStatusListener, ImageRevealHelper.RevealStateListener { + private static final String TAG = ImageWallpaperRenderer.class.getSimpleName(); + + private final WallpaperManager mWallpaperManager; + private final ImageGLProgram mProgram; + private final ImageGLWallpaper mWallpaper; + private final ImageProcessHelper mImageProcessHelper; + private final ImageRevealHelper mImageRevealHelper; + private final ImageGLView mGLView; + private float mXOffset = 0f; + private float mYOffset = 0f; + + public ImageWallpaperRenderer(Context context, ImageGLView glView) { + mWallpaperManager = context.getSystemService(WallpaperManager.class); + if (mWallpaperManager == null) { + Log.w(TAG, "WallpaperManager not available"); + } + + mProgram = new ImageGLProgram(context); + mWallpaper = new ImageGLWallpaper(mProgram); + mImageProcessHelper = new ImageProcessHelper(); + mImageRevealHelper = new ImageRevealHelper(this); + mGLView = glView; + + if (mWallpaperManager != null) { + // Compute per85 as transition threshold, this is an async work. + mImageProcessHelper.startComputingPercentile85(mWallpaperManager.getBitmap()); + } + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + glClearColor(0f, 0f, 0f, 1.0f); + mProgram.useGLProgram( + R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader); + mWallpaper.setup(); + mWallpaper.setupTexture(mWallpaperManager.getBitmap()); + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + glViewport(0, 0, width, height); + if (Build.IS_DEBUGGABLE) { + Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height + + ", xOffset=" + mXOffset + ", yOffset=" + mYOffset); + } + mWallpaper.adjustTextureCoordinates(mWallpaperManager.getBitmap(), + width, height, mXOffset, mYOffset); + } + + @Override + public void onDrawFrame(GL10 gl) { + float threshold = mImageProcessHelper.getPercentile85(); + float reveal = mImageRevealHelper.getReveal(); + + glClear(GL_COLOR_BUFFER_BIT); + + glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), 1); + glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_CENTER_REVEAL), threshold); + glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal); + + mWallpaper.useTexture(); + mWallpaper.draw(); + } + + @Override + public void onAmbientModeChanged(boolean inAmbientMode, long duration) { + mImageRevealHelper.updateAwake(!inAmbientMode, duration); + requestRender(); + } + + @Override + public void onOffsetsChanged(float xOffset, float yOffset, Rect frame) { + if (frame == null || mWallpaperManager == null + || (xOffset == mXOffset && yOffset == mYOffset)) { + return; + } + + Bitmap bitmap = mWallpaperManager.getBitmap(); + if (bitmap == null) { + return; + } + + int width = frame.width(); + int height = frame.height(); + mXOffset = xOffset; + mYOffset = yOffset; + + if (Build.IS_DEBUGGABLE) { + Log.d(TAG, "onOffsetsChanged: width=" + width + ", height=" + height + + ", xOffset=" + mXOffset + ", yOffset=" + mYOffset); + } + mWallpaper.adjustTextureCoordinates(bitmap, width, height, mXOffset, mYOffset); + requestRender(); + } + + @Override + public void onRevealStateChanged() { + requestRender(); + } + + private void requestRender() { + if (mGLView != null) { + mGLView.render(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt index 1765dc866c66..15dc43f041f4 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -16,7 +16,6 @@ package com.android.systemui.privacy import android.content.Context import android.util.AttributeSet -import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout @@ -40,10 +39,12 @@ class OngoingPrivacyChip @JvmOverloads constructor( context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size) private val iconColor = context.resources.getColor( R.color.status_bar_clock_color, context.theme) + private val sidePadding = + context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding) private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg) private lateinit var text: TextView private lateinit var iconsContainer: LinearLayout - private lateinit var inUseText: TextView + private lateinit var back: LinearLayout var expanded = false set(value) { if (value != field) { @@ -64,15 +65,15 @@ class OngoingPrivacyChip @JvmOverloads constructor( override fun onFinishInflate() { super.onFinishInflate() - inUseText = findViewById(R.id.in_use_text) + back = findViewById(R.id.background) text = findViewById(R.id.text_container) iconsContainer = findViewById(R.id.icons_container) } // Should only be called if the builder icons or app changed private fun updateView() { - inUseText.visibility = if (expanded) View.GONE else View.VISIBLE - background = if (expanded) backgroundDrawable else null + back.background = if (expanded) backgroundDrawable else null + back.setPaddingRelative(0, 0, if (expanded) sidePadding else 0, 0) fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) { iconsContainer.removeAllViews() dialogBuilder.generateIcons().forEachIndexed { i, it -> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index c0f87cb37e50..6a8c19ad0e77 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -81,6 +81,7 @@ import com.android.systemui.statusbar.policy.DateView; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.ZenModeController; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -200,6 +201,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons); mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons); StatusIconContainer iconContainer = findViewById(R.id.statusIcons); + // Ignore privacy icons because they show in the space above QQS + iconContainer.addIgnoredSlots(getIgnoredIconSlots()); iconContainer.setShouldRestrictIcons(false); mIconManager = new TintedIconManager(iconContainer); @@ -241,6 +244,18 @@ public class QuickStatusBarHeader extends RelativeLayout implements updateShowPercent(); } + private List<String> getIgnoredIconSlots() { + ArrayList<String> ignored = new ArrayList<>(); + ignored.add(mContext.getResources().getString( + com.android.internal.R.string.status_bar_camera)); + ignored.add(mContext.getResources().getString( + com.android.internal.R.string.status_bar_microphone)); + ignored.add(mContext.getResources().getString( + com.android.internal.R.string.status_bar_location)); + + return ignored; + } + private void updateStatusText() { boolean changed = updateRingerStatus() || updateAlarmStatus(); @@ -372,15 +387,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements setLayoutParams(lp); - if (mPrivacyChip != null) { - MarginLayoutParams lm = (MarginLayoutParams) mPrivacyChip.getLayoutParams(); - int sideMargins = lm.leftMargin; - int topBottomMargins = resources.getDimensionPixelSize( - R.dimen.ongoing_appops_top_chip_margin); - lm.setMargins(sideMargins, topBottomMargins, sideMargins, topBottomMargins); - mPrivacyChip.setLayoutParams(lm); - } - updateStatusIconAlphaAnimator(); updateHeaderTextContainerAlphaAnimator(); updatePrivacyChipAlphaAnimator(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java index 2f1963057ad4..a6af82a28bce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java @@ -28,7 +28,7 @@ import android.view.accessibility.AccessibilityEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import java.util.stream.Stream; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java index a3beb96780d3..57d058880118 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT; import android.annotation.NonNull; import android.content.Context; @@ -26,7 +26,7 @@ import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import javax.inject.Inject; import javax.inject.Singleton; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt index 494473242a90..52b8cc2b685b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt @@ -49,7 +49,7 @@ class MediaArtworkProcessor @Inject constructor() { context.display.getSize(mTmpSize) val renderScript = RenderScript.create(context) - val rect = Rect(0, 0,artwork.width, artwork.height) + val rect = Rect(0, 0, artwork.width, artwork.height) MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE)) val inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(), true /* filter */) @@ -67,6 +67,7 @@ class MediaArtworkProcessor @Inject constructor() { input.destroy() output.destroy() inBitmap.recycle() + blur.destroy() val canvas = Canvas(outBitmap) canvas.drawColor(ColorUtils.setAlphaComponent(color, COLOR_ALPHA)) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java index 5605f3db90fb..f6d3cdfddb31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java @@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification; import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP; import android.app.Notification; import android.service.notification.StatusBarNotification; @@ -30,7 +30,7 @@ import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -102,8 +102,7 @@ public class NotificationAlertingManager { * @param entry entry to add * @param inflatedFlags flags representing content views that were inflated */ - private void showAlertingView(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + private void showAlertingView(NotificationEntry entry, @InflationFlag int inflatedFlags) { if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) { // Possible for shouldHeadsUp to change between the inflation starting and ending. // If it does and we no longer need to heads up, we should free the view. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java index 1ed671fdb6fb..a5a6d87c2030 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java @@ -20,7 +20,7 @@ import android.service.notification.StatusBarNotification; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; /** * Listener interface for changes sent by NotificationEntryManager. @@ -65,8 +65,7 @@ public interface NotificationEntryListener { /** * Called when a notification's views are inflated for the first time. */ - default void onEntryInflated(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + default void onEntryInflated(NotificationEntry entry, @InflationFlag int inflatedFlags) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 56922be73bec..3fbc64163759 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -36,8 +36,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationInflater; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; @@ -56,7 +56,7 @@ import java.util.Map; */ public class NotificationEntryManager implements Dumpable, - NotificationInflater.InflationCallback, + NotificationContentInflater.InflationCallback, NotificationUpdateHandler, VisualStabilityManager.Callback { private static final String TAG = "NotificationEntryMgr"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java index f1bb0d77deaa..6f5baf9faf39 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java @@ -19,8 +19,8 @@ package com.android.systemui.statusbar.notification; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP; import android.annotation.Nullable; import android.content.Context; @@ -42,8 +42,8 @@ import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -78,7 +78,7 @@ public class NotificationRowBinder { private NotificationPresenter mPresenter; private NotificationListContainer mListContainer; private HeadsUpManager mHeadsUpManager; - private NotificationInflater.InflationCallback mInflationCallback; + private NotificationContentInflater.InflationCallback mInflationCallback; private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; private BindRowCallback mBindRowCallback; private NotificationClicker mNotificationClicker; @@ -105,7 +105,7 @@ public class NotificationRowBinder { public void setUpWithPresenter(NotificationPresenter presenter, NotificationListContainer listContainer, HeadsUpManager headsUpManager, - NotificationInflater.InflationCallback inflationCallback, + NotificationContentInflater.InflationCallback inflationCallback, BindRowCallback bindRowCallback) { mPresenter = presenter; mListContainer = listContainer; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index f6d4ce22e905..3bf4d4beb4f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -54,8 +54,8 @@ import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.NotificationGuts; -import com.android.systemui.statusbar.notification.row.NotificationInflater; import java.util.ArrayList; import java.util.Collections; @@ -515,7 +515,7 @@ public final class NotificationEntry { if (row != null) row.resetUserExpansion(); } - public void freeContentViewWhenSafe(@NotificationInflater.InflationFlag int inflationFlag) { + public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) { if (row != null) row.freeContentViewWhenSafe(inflationFlag); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 69828c166463..2b643d0a2fea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -17,13 +17,13 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationCallback; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -89,7 +89,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationCounters; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.wrapper.NotificationMediaTemplateViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.notification.stack.AmbientState; @@ -134,7 +134,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } private LayoutListener mLayoutListener; - private final NotificationInflater mNotificationInflater; + private final NotificationContentInflater mNotificationInflater; private int mIconTransformContentShift; private int mIconTransformContentShiftNoIcon; private int mMaxHeadsUpHeightBeforeN; @@ -1616,7 +1616,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } @VisibleForTesting - public NotificationInflater getNotificationInflater() { + public NotificationContentInflater getNotificationInflater() { return mNotificationInflater; } @@ -1631,7 +1631,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public ExpandableNotificationRow(Context context, AttributeSet attrs) { super(context, attrs); mFalsingManager = FalsingManager.getInstance(context); - mNotificationInflater = new NotificationInflater(this); + mNotificationInflater = new NotificationContentInflater(this); mMenuRow = new NotificationMenuRow(mContext); mImageResolver = new NotificationInlineImageResolver(context, new NotificationInlineImageCache()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 42ebfceca334..b34907dfebf1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -55,9 +55,9 @@ import java.util.concurrent.atomic.AtomicInteger; /** * A utility that inflates the right kind of contentView based on the state */ -public class NotificationInflater { +public class NotificationContentInflater { - public static final String TAG = "NotificationInflater"; + public static final String TAG = "NotifContentInflater"; @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, @@ -127,7 +127,7 @@ public class NotificationInflater { private boolean mRedactAmbient; private final ArrayMap<Integer, RemoteViews> mCachedContentViews = new ArrayMap<>(); - public NotificationInflater(ExpandableNotificationRow row) { + public NotificationContentInflater(ExpandableNotificationRow row) { mRow = row; } @@ -232,8 +232,7 @@ public class NotificationInflater { * will reinflate it. * * @param reInflateFlags flags which views should be inflated. Should be a subset of - * {@link NotificationInflater#mInflationFlags} as only those will be - * inflated/reinflated. + * {@link #mInflationFlags} as only those will be inflated/reinflated. */ private void inflateNotificationViews(@InflationFlag int reInflateFlags) { if (mRow.isRemoved()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java index a5411ecb4bd0..6eb376b58586 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java @@ -52,7 +52,7 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso @Override public void preload(Uri uri) { PreloadImageTask newTask = new PreloadImageTask(mResolver); - newTask.executeOnExecutor(NotificationInflater.EXECUTOR, uri); + newTask.executeOnExecutor(NotificationContentInflater.EXECUTOR, uri); mCache.put(uri, newTask); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 4c06ff6f5e49..3808702176a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -26,12 +26,15 @@ import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.view.NotificationHeaderView; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; +import com.android.internal.util.ContrastColorUtil; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.TransformState; @@ -108,6 +111,11 @@ public abstract class NotificationViewWrapper implements TransformableView { return false; } + // Apps targeting Q should fix their dark mode bugs. + if (mRow.getEntry().targetSdk >= Build.VERSION_CODES.Q) { + return false; + } + int background = getBackgroundColor(view); if (background == Color.TRANSPARENT) { background = defaultBackgroundColor; @@ -138,17 +146,19 @@ public abstract class NotificationViewWrapper implements TransformableView { } } - private boolean childrenNeedInversion(@ColorInt int parentBackground, ViewGroup viewGroup) { + @VisibleForTesting + boolean childrenNeedInversion(@ColorInt int parentBackground, ViewGroup viewGroup) { if (viewGroup == null) { return false; } + int backgroundColor = getBackgroundColor(viewGroup); + if (Color.alpha(backgroundColor) != 255) { + backgroundColor = ContrastColorUtil.compositeColors(backgroundColor, parentBackground); + backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 255); + } for (int i = 0; i < viewGroup.getChildCount(); i++) { View child = viewGroup.getChildAt(i); - int backgroundColor = getBackgroundColor(viewGroup); - if (backgroundColor == Color.TRANSPARENT) { - backgroundColor = parentBackground; - } if (child instanceof TextView) { int foreground = ((TextView) child).getCurrentTextColor(); if (ColorUtils.calculateContrast(foreground, backgroundColor) < 3) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java index 6410860a852d..195d02d9ca72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java @@ -191,7 +191,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } protected int adjustDisableFlags(int state) { - if (!mStatusBarComponent.isLaunchTransitionFadingAway() + if (!mKeyguardMonitor.isLaunchTransitionFadingAway() && !mKeyguardMonitor.isKeyguardFadingAway() && shouldHideNotificationIcons()) { state |= DISABLE_NOTIFICATION_ICONS; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java index dae4da7355c7..64209a7b9e73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java @@ -16,9 +16,17 @@ package com.android.systemui.statusbar.phone; +import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PixelFormat; +import android.util.FloatProperty; +import android.util.MathUtils; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; @@ -27,6 +35,71 @@ import com.android.systemui.R; public class NavigationBarEdgePanel extends View { private static final String TAG = "NavigationBarEdgePanel"; + // TODO: read from resources once drawing is finalized. + private static final boolean SHOW_PROTECTION_STROKE = true; + private static final int PROTECTION_COLOR = 0xffc0c0c0; + private static final int STROKE_COLOR = 0xffe5e5e5; + private static final int PROTECTION_WIDTH_PX = 4; + private static final int BASE_EXTENT = 32; + private static final int ARROW_HEIGHT_DP = 32; + private static final int POINT_EXTENT_DP = 8; + private static final int ARROW_THICKNESS_DP = 4; + private static final float TRACK_LENGTH_MULTIPLIER = 1.5f; + private static final float START_POINTING_RATIO = 0.3f; + private static final float POINTEDNESS_BEFORE_SNAP_RATIO = 0.4f; + private static final int ANIM_DURATION_MS = 150; + + private final Paint mPaint = new Paint(); + private final Paint mProtectionPaint = new Paint(); + + private final ObjectAnimator mEndAnimator; + private final ObjectAnimator mLegAnimator; + + private final float mDensity; + private final float mBaseExtent; + private final float mPointExtent; + private final float mHeight; + private final float mStrokeThickness; + private final boolean mIsLeftPanel; + + private float mStartY; + private float mStartX; + + private boolean mGestureDetected; + private boolean mArrowsPointLeft; + private float mGestureLength; + private float mLegProgress; + private float mDragProgress; + + // How much the "legs" of the back arrow have proceeded from being a line to an arrow. + private static final FloatProperty<NavigationBarEdgePanel> LEG_PROGRESS = + new FloatProperty<NavigationBarEdgePanel>("legProgress") { + @Override + public void setValue(NavigationBarEdgePanel object, float value) { + object.setLegProgress(value); + } + + @Override + public Float get(NavigationBarEdgePanel object) { + return object.getLegProgress(); + } + }; + + // How far across the view the arrow should be drawn. + private static final FloatProperty<NavigationBarEdgePanel> DRAG_PROGRESS = + new FloatProperty<NavigationBarEdgePanel>("dragProgress") { + + @Override + public void setValue(NavigationBarEdgePanel object, float value) { + object.setDragProgress(value); + } + + @Override + public Float get(NavigationBarEdgePanel object) { + return object.getDragProgress(); + } + }; + public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height, int gravity) { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, @@ -40,13 +113,43 @@ public class NavigationBarEdgePanel extends View { lp.setTitle(TAG + context.getDisplayId()); lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel); lp.windowAnimations = 0; - NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context); + NavigationBarEdgePanel panel = new NavigationBarEdgePanel( + context, (gravity & Gravity.LEFT) == Gravity.LEFT); panel.setLayoutParams(lp); return panel; } - private NavigationBarEdgePanel(Context context) { + private NavigationBarEdgePanel(Context context, boolean isLeftPanel) { super(context); + + mEndAnimator = ObjectAnimator.ofFloat(this, DRAG_PROGRESS, 1f); + mEndAnimator.setAutoCancel(true); + mEndAnimator.setDuration(ANIM_DURATION_MS); + + mLegAnimator = ObjectAnimator.ofFloat(this, LEG_PROGRESS, 1f); + mLegAnimator.setAutoCancel(true); + mLegAnimator.setDuration(ANIM_DURATION_MS); + + mDensity = context.getResources().getDisplayMetrics().density; + + mBaseExtent = dp(BASE_EXTENT); + mHeight = dp(ARROW_HEIGHT_DP); + mPointExtent = dp(POINT_EXTENT_DP); + mStrokeThickness = dp(ARROW_THICKNESS_DP); + + mPaint.setStrokeWidth(mStrokeThickness); + mPaint.setStrokeCap(Paint.Cap.ROUND); + mPaint.setColor(STROKE_COLOR); + mPaint.setAntiAlias(true); + + mProtectionPaint.setStrokeWidth(mStrokeThickness + PROTECTION_WIDTH_PX); + mProtectionPaint.setStrokeCap(Paint.Cap.ROUND); + mProtectionPaint.setColor(PROTECTION_COLOR); + mProtectionPaint.setAntiAlias(true); + + // Both panels arrow point the same way + mArrowsPointLeft = getLayoutDirection() == LAYOUT_DIRECTION_LTR; + mIsLeftPanel = isLeftPanel; } public void setWindowFlag(int flags, boolean enable) { @@ -62,6 +165,58 @@ public class NavigationBarEdgePanel extends View { updateLayout(lp); } + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN : { + show(event.getX(), event.getY()); + break; + } + case MotionEvent.ACTION_MOVE: { + handleNewSwipePoint(event.getX()); + break; + } + // Fall through + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + hide(); + break; + } + } + + return false; + } + + @Override + protected void onDraw(Canvas canvas) { + float edgeOffset = mBaseExtent * mDragProgress - mStrokeThickness; + float animatedOffset = mPointExtent * mLegProgress; + canvas.save(); + canvas.translate( + mIsLeftPanel ? edgeOffset : getWidth() - edgeOffset, + mStartY - mHeight * 0.5f); + + float outsideX = mArrowsPointLeft ? animatedOffset : 0; + float middleX = mArrowsPointLeft ? 0 : animatedOffset; + + if (SHOW_PROTECTION_STROKE) { + canvas.drawLine(outsideX, 0, middleX, mHeight * 0.5f, mProtectionPaint); + canvas.drawLine(middleX, mHeight * 0.5f, outsideX, mHeight, mProtectionPaint); + } + + canvas.drawLine(outsideX, 0, middleX, mHeight * 0.5f, mPaint); + canvas.drawLine(middleX, mHeight * 0.5f, outsideX, mHeight, mPaint); + canvas.restore(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + // TODO: read the gesture length from the nav controller. + mGestureLength = getWidth(); + } + public void setDimensions(int width, int height) { final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); if (lp.width != width || lp.height != height) { @@ -71,8 +226,81 @@ public class NavigationBarEdgePanel extends View { } } + private void setLegProgress(float progress) { + mLegProgress = progress; + invalidate(); + } + + private float getLegProgress() { + return mLegProgress; + } + + private void setDragProgress(float dragProgress) { + mDragProgress = dragProgress; + invalidate(); + } + + private float getDragProgress() { + return mDragProgress; + } + + private void hide() { + animate().alpha(0f).setDuration(ANIM_DURATION_MS); + } + + private void show(float x, float y) { + mEndAnimator.cancel(); + mLegAnimator.cancel(); + setLegProgress(0f); + setDragProgress(0f); + setAlpha(1f); + + float halfHeight = mHeight * 0.5f; + mStartY = MathUtils.constrain(y, halfHeight, getHeight() - halfHeight); + mStartX = x; + } + + private void handleNewSwipePoint(float x) { + float dist = MathUtils.abs(x - mStartX); + + setDragProgress(MathUtils.constrainedMap( + 0, 1.0f, + 0, mGestureLength * TRACK_LENGTH_MULTIPLIER, + dist)); + + if (dist < mGestureLength) { + float calculatedLegProgress = MathUtils.constrainedMap( + 0f, POINTEDNESS_BEFORE_SNAP_RATIO, + mGestureLength * START_POINTING_RATIO, mGestureLength, + dist); + + // Blend animated value with drag calculated value, allow the gesture to continue + // while the animation is playing with jump cuts in the animation. + setLegProgress(MathUtils.lerp(calculatedLegProgress, mLegProgress, mDragProgress)); + + if (mGestureDetected) { + mGestureDetected = false; + + mLegAnimator.setFloatValues(POINTEDNESS_BEFORE_SNAP_RATIO); + mLegAnimator.start(); + } + } else { + if (!mGestureDetected) { + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + mGestureDetected = true; + + mLegAnimator.setFloatValues(1f); + mLegAnimator.start(); + } + } + } + private void updateLayout(WindowManager.LayoutParams lp) { WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); wm.updateViewLayout(this, lp); } + + private float dp(float dp) { + return mDensity * dp; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index ebd420478c0f..8152206aa2ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -1227,10 +1227,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav .getSystemService(Context.WINDOW_SERVICE); int width = mPrototypeController.getEdgeSensitivityWidth(); int height = mPrototypeController.getEdgeSensitivityHeight(); + // Explicitly left and right, not start and end as this is device relative. mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, - Gravity.START | Gravity.BOTTOM); + Gravity.LEFT | Gravity.BOTTOM); mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, - Gravity.END | Gravity.BOTTOM); + Gravity.RIGHT | Gravity.BOTTOM); mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener); wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams()); @@ -1252,15 +1253,12 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav mButtonDispatchers.valueAt(i).onDestroy(); } - if (mPrototypeController.isEnabled()) { - WindowManager wm = (WindowManager) getContext() - .getSystemService(Context.WINDOW_SERVICE); - if (mLeftEdgePanel != null) { - wm.removeView(mLeftEdgePanel); - } - if (mRightEdgePanel != null) { - wm.removeView(mRightEdgePanel); - } + WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + if (mLeftEdgePanel != null) { + wm.removeView(mLeftEdgePanel); + } + if (mRightEdgePanel != null) { + wm.removeView(mRightEdgePanel); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index b613e8efa8ee..4dbd8545efb9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -34,8 +34,8 @@ import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.AsyncInflationTask; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup; import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener; import com.android.systemui.statusbar.policy.HeadsUpManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 62f85fe8a00e..99269cf17141 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -24,6 +24,7 @@ import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -47,6 +48,7 @@ public class NotificationIconAreaController implements DarkReceiver, private final NotificationEntryManager mEntryManager; private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons; private final StatusBarStateController mStatusBarStateController; + private final NotificationMediaManager mMediaManager; @VisibleForTesting final NotificationListener.NotificationSettingsListener mSettingsListener = new NotificationListener.NotificationSettingsListener() { @@ -93,13 +95,15 @@ public class NotificationIconAreaController implements DarkReceiver, public NotificationIconAreaController(Context context, StatusBar statusBar, StatusBarStateController statusBarStateController, - NotificationListener notificationListener) { + NotificationListener notificationListener, + NotificationMediaManager notificationMediaManager) { mStatusBar = statusBar; mContrastColorUtil = ContrastColorUtil.getInstance(context); mContext = context; mEntryManager = Dependency.get(NotificationEntryManager.class); mStatusBarStateController = statusBarStateController; mStatusBarStateController.addCallback(this); + mMediaManager = notificationMediaManager; notificationListener.addNotificationSettingsListener(mSettingsListener); initializeNotificationAreaViews(context); @@ -192,10 +196,13 @@ public class NotificationIconAreaController implements DarkReceiver, protected boolean shouldShowNotificationIcon(NotificationEntry entry, boolean showAmbient, boolean showLowPriority, boolean hideDismissed, - boolean hideRepliedMessages) { + boolean hideRepliedMessages, boolean hideCurrentMedia) { if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) { return false; } + if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) { + return false; + } if (!showLowPriority && !entry.isHighPriority()) { return false; } @@ -235,14 +242,16 @@ public class NotificationIconAreaController implements DarkReceiver, private void updateShelfIcons() { updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons, true /* showAmbient */, !mFullyDark /* showLowPriority */, - false /* hideDismissed */, mFullyDark /* hideRepliedMessages */); + false /* hideDismissed */, mFullyDark /* hideRepliedMessages */, + mFullyDark /* hideCurrentMedia */); } public void updateStatusBarIcons() { updateIconsForLayout(entry -> entry.icon, mNotificationIcons, false /* showAmbient */, mShowLowPriority /* showLowPriority */, true /* hideDismissed */, - true /* hideRepliedMessages */); + true /* hideRepliedMessages */, + false /* hideCurrentMedia */); } @VisibleForTesting @@ -261,7 +270,7 @@ public class NotificationIconAreaController implements DarkReceiver, */ private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function, NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority, - boolean hideDismissed, boolean hideRepliedMessages) { + boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia) { ArrayList<StatusBarIconView> toShow = new ArrayList<>( mNotificationScrollLayout.getChildCount()); @@ -271,7 +280,7 @@ public class NotificationIconAreaController implements DarkReceiver, if (view instanceof ExpandableNotificationRow) { NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry(); if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed, - hideRepliedMessages)) { + hideRepliedMessages, hideCurrentMedia)) { toShow.add(function.apply(ent)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index e42004a1ca13..008eeefa8341 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -117,7 +117,6 @@ import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; import android.widget.DateTimeView; -import android.widget.ImageView; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; @@ -460,9 +459,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected boolean mDozing; private boolean mDozingRequested; - protected BackDropView mBackdrop; - protected ImageView mBackdropFront, mBackdropBack; - private NotificationMediaManager mMediaManager; protected NotificationLockscreenUserManager mLockscreenUserManager; protected NotificationRemoteInputManager mRemoteInputManager; @@ -483,8 +479,7 @@ public class StatusBar extends SystemUI implements DemoMode, updateAodMaskVisibility(deviceSupportsAodWallpaper && aodImageWallpaperEnabled); // If WallpaperInfo is null, it must be ImageWallpaper. final boolean supportsAmbientMode = deviceSupportsAodWallpaper - && (info == null && aodImageWallpaperEnabled - || info != null && info.supportsAmbientMode()); + && (info == null || info.supportsAmbientMode()); mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); @@ -492,7 +487,6 @@ public class StatusBar extends SystemUI implements DemoMode, }; private Runnable mLaunchTransitionEndRunnable; - protected boolean mLaunchTransitionFadingAway; private NotificationEntry mDraggedDownEntry; private boolean mLaunchCameraOnScreenTurningOn; private boolean mLaunchCameraOnFinishedGoingToSleep; @@ -932,11 +926,9 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpManager, mNotificationIconAreaController, mScrimController); mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context)); - mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop); - mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front); - mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back); - mMediaManager.setup(mBackdrop, mBackdropFront, mBackdropBack, - mScrimController, mLockscreenWallpaper); + BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop); + mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front), + backdrop.findViewById(R.id.backdrop_back), mScrimController, mLockscreenWallpaper); // Other icons mVolumeComponent = getComponent(VolumeComponent.class); @@ -1592,10 +1584,6 @@ public class StatusBar extends SystemUI implements DemoMode, return mPulsing; } - public boolean isLaunchTransitionFadingAway() { - return mLaunchTransitionFadingAway; - } - public boolean hideStatusBarIconsWhenExpanded() { return mNotificationPanel.hideStatusBarIconsWhenExpanded(); } @@ -2974,7 +2962,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void showKeyguardImpl() { mIsKeyguard = true; - if (mLaunchTransitionFadingAway) { + if (mKeyguardMonitor.isLaunchTransitionFadingAway()) { mNotificationPanel.animate().cancel(); onLaunchTransitionFadingEnded(); } @@ -3006,7 +2994,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanel.onAffordanceLaunchEnded(); releaseGestureWakeLock(); runLaunchTransitionEndRunnable(); - mLaunchTransitionFadingAway = false; + mKeyguardMonitor.setLaunchTransitionFadingAway(false); mPresenter.updateMediaMetaData(true /* metaDataChanged */, true); } @@ -3032,7 +3020,6 @@ public class StatusBar extends SystemUI implements DemoMode, mLaunchTransitionEndRunnable = endRunnable; Runnable hideRunnable = () -> { mKeyguardMonitor.setLaunchTransitionFadingAway(true); - mLaunchTransitionFadingAway = true; if (beforeFading != null) { beforeFading.run(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index 6495910359bb..6e36c019bb28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ViewState; import java.util.ArrayList; +import java.util.List; /** * A container for Status bar system icons. Limits the number of system icons and handles overflow @@ -67,6 +68,8 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { private ArrayList<StatusIconState> mLayoutStates = new ArrayList<>(); // So we can count and measure properly private ArrayList<View> mMeasureViews = new ArrayList<>(); + // Any ignored icon will never be added as a child + private ArrayList<String> mIgnoredSlots = new ArrayList<>(); public StatusIconContainer(Context context) { this(context, null); @@ -146,7 +149,8 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { // Collect all of the views which want to be laid out for (int i = 0; i < count; i++) { StatusIconDisplayable icon = (StatusIconDisplayable) getChildAt(i); - if (icon.isIconVisible() && !icon.isIconBlocked()) { + if (icon.isIconVisible() && !icon.isIconBlocked() + && !mIgnoredSlots.contains(icon.getSlot())) { mMeasureViews.add((View) icon); } } @@ -205,6 +209,47 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { } /** + * Add a name of an icon slot to be ignored. It will not show up nor be measured + * @param slotName name of the icon as it exists in + * frameworks/base/core/res/res/values/config.xml + */ + public void addIgnoredSlot(String slotName) { + addIgnoredSlotInternal(slotName); + requestLayout(); + } + + /** + * Add a list of slots to be ignored + * @param slots names of the icons to ignore + */ + public void addIgnoredSlots(List<String> slots) { + for (String slot : slots) { + addIgnoredSlotInternal(slot); + } + + requestLayout(); + } + + private void addIgnoredSlotInternal(String slotName) { + if (!mIgnoredSlots.contains(slotName)) { + mIgnoredSlots.add(slotName); + } + } + + /** + * Remove a slot from the list of ignored icon slots. It will then be shown when set to visible + * by the {@link StatusBarIconController}. + * @param slotName name of the icon slot to remove from the ignored list + */ + public void removeIgnoredSlot(String slotName) { + if (mIgnoredSlots.contains(slotName)) { + mIgnoredSlots.remove(slotName); + } + + requestLayout(); + } + + /** * Layout is happening from end -> start */ private void calculateIconTranslations() { @@ -223,7 +268,8 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { StatusIconDisplayable iconView = (StatusIconDisplayable) child; StatusIconState childState = getViewStateFromChild(child); - if (!iconView.isIconVisible() || iconView.isIconBlocked()) { + if (!iconView.isIconVisible() || iconView.isIconBlocked() + || mIgnoredSlots.contains(iconView.getSlot())) { childState.visibleState = STATE_HIDDEN; if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") not visible"); continue; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index fd3f680e5e77..0461057bf2e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.policy; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP; import android.annotation.NonNull; import android.annotation.Nullable; @@ -31,7 +31,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java index 6ee341dd974c..f446cefb7b6f 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java +++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java @@ -156,6 +156,8 @@ public class AodMaskView extends ImageView implements StatusBarStateController.S private boolean checkIfNeedMask() { // We need mask for ImageWallpaper / LockScreen Wallpaper (Music album art). + // Because of conflicting with another wallpaper feature, + // we only support LockScreen wallpaper currently. return mWallpaperManager.getWallpaperInfo() == null || ScrimState.AOD.hasBackdrop(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java index c0aac7ee8793..3bd582f955af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java @@ -22,6 +22,8 @@ import android.content.res.Resources; import android.graphics.PointF; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; +import android.view.View; +import android.widget.FrameLayout; import androidx.dynamicanimation.animation.DynamicAnimation; @@ -63,15 +65,13 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC public void testExpansionAndCollapse() throws InterruptedException { Runnable afterExpand = Mockito.mock(Runnable.class); mExpandedController.expandFromStack(mExpansionPoint, afterExpand); - waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); - testExpanded(); + testBubblesInCorrectExpandedPositions(); Mockito.verify(afterExpand).run(); Runnable afterCollapse = Mockito.mock(Runnable.class); mExpandedController.collapseBackToStack(afterCollapse); - waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); testStackedAtPosition(mExpansionPoint.x, mExpansionPoint.y, -1); @@ -79,17 +79,70 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC } @Test - public void testOnChildRemoved() throws InterruptedException { - Runnable afterExpand = Mockito.mock(Runnable.class); - mExpandedController.expandFromStack(mExpansionPoint, afterExpand); + public void testOnChildAdded() throws InterruptedException { + expand(); + + // Add another new view and wait for its animation. + final View newView = new FrameLayout(getContext()); + mLayout.addView(newView, 0); waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); - testExpanded(); + + testBubblesInCorrectExpandedPositions(); + } + + @Test + public void testOnChildRemoved() throws InterruptedException { + expand(); // Remove some views and see if the remaining child views still pass the expansion test. mLayout.removeView(mViews.get(0)); mLayout.removeView(mViews.get(3)); waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); - testExpanded(); + testBubblesInCorrectExpandedPositions(); + } + + @Test + public void testBubbleDraggedNotDismissedSnapsBack() throws InterruptedException { + expand(); + + final View draggedBubble = mViews.get(0); + mExpandedController.prepareForBubbleDrag(draggedBubble); + mExpandedController.dragBubbleOut(draggedBubble, 500f, 500f); + + assertEquals(500f, draggedBubble.getTranslationX(), 1f); + assertEquals(500f, draggedBubble.getTranslationY(), 1f); + + // Snap it back and make sure it made it back correctly. + mExpandedController.snapBubbleBack(draggedBubble, 0f, 0f); + waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); + testBubblesInCorrectExpandedPositions(); + } + + @Test + public void testBubbleDismissed() throws InterruptedException { + expand(); + + final View draggedBubble = mViews.get(0); + mExpandedController.prepareForBubbleDrag(draggedBubble); + mExpandedController.dragBubbleOut(draggedBubble, 500f, 500f); + + assertEquals(500f, draggedBubble.getTranslationX(), 1f); + assertEquals(500f, draggedBubble.getTranslationY(), 1f); + + // Snap it back and make sure it made it back correctly. + mExpandedController.prepareForDismissalWithVelocity(draggedBubble, 0f, 0f); + mLayout.removeView(draggedBubble); + waitForLayoutMessageQueue(); + waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); + + assertEquals(-1, mLayout.indexOfChild(draggedBubble)); + testBubblesInCorrectExpandedPositions(); + } + + /** Expand the stack and wait for animations to finish. */ + private void expand() throws InterruptedException { + mExpandedController.expandFromStack(mExpansionPoint, Mockito.mock(Runnable.class)); + waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y); } /** Check that children are in the correct positions for being stacked. */ @@ -108,7 +161,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC } /** Check that children are in the correct positions for being expanded. */ - private void testExpanded() { + private void testBubblesInCorrectExpandedPositions() { // Check all the visible bubbles to see if they're in the right place. for (int i = 0; i < Math.min(mLayout.getChildCount(), mMaxRenderedBubbles); i++) { assertEquals(mBubblePadding + (i * (mBubbleSize + mBubblePadding)), diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java index 31e44d7b3051..d94b6694c7fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java @@ -155,6 +155,11 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase { } @Override + public void cancelAnimationsOnView(View view) { + mMainThreadHandler.post(() -> super.cancelAnimationsOnView(view)); + } + + @Override protected void animateValueForChildAtIndex(DynamicAnimation.ViewProperty property, int index, float value, float startVel, Runnable after) { mMainThreadHandler.post(() -> diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java index 660f853b3c7b..7b1253af12c6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_CONTRACTED; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index a2c880a5bf9b..3c919a17df6c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -39,8 +39,8 @@ import com.android.systemui.R; import com.android.systemui.bubbles.BubblesTestActivity; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; -import com.android.systemui.statusbar.notification.row.NotificationInflaterTest; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; +import com.android.systemui.statusbar.notification.row.NotificationContentInflaterTest; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -279,7 +279,7 @@ public class NotificationTestHelper { entry.channel.setBlockableSystem(true); row.setEntry(entry); row.getNotificationInflater().addInflationFlags(extraInflationFlags); - NotificationInflaterTest.runThenWaitForInflation( + NotificationContentInflaterTest.runThenWaitForInflation( () -> row.inflateViews(), row.getNotificationInflater()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 79bc0a39d59c..04e7cab406ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -68,8 +68,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -143,7 +143,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Override public void onAsyncInflationFinished(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + @InflationFlag int inflatedFlags) { super.onAsyncInflationFinished(entry, inflatedFlags); mCountDownLatch.countDown(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 6d3553912701..f6fb4163bfc4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -18,9 +18,9 @@ package com.android.systemui.statusbar.notification.row; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_ALL; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_ALL; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java index 648df3cab33c..dfaa76a58e2d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java @@ -16,11 +16,11 @@ package com.android.systemui.statusbar.notification.row; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_ALL; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_EXPANDED; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_ALL; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_EXPANDED; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -49,6 +49,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationCallback; import org.junit.Assert; import org.junit.Before; @@ -64,9 +65,9 @@ import java.util.concurrent.TimeUnit; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) -public class NotificationInflaterTest extends SysuiTestCase { +public class NotificationContentInflaterTest extends SysuiTestCase { - private NotificationInflater mNotificationInflater; + private NotificationContentInflater mNotificationInflater; private Notification.Builder mBuilder; private ExpandableNotificationRow mRow; @@ -80,8 +81,8 @@ public class NotificationInflaterTest extends SysuiTestCase { ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow( mBuilder.build()); mRow = spy(row); - mNotificationInflater = new NotificationInflater(mRow); - mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() { + mNotificationInflater = new NotificationContentInflater(mRow); + mNotificationInflater.setInflationCallback(new InflationCallback() { @Override public void handleInflationException(StatusBarNotification notification, Exception e) { @@ -89,7 +90,7 @@ public class NotificationInflaterTest extends SysuiTestCase { @Override public void onAsyncInflationFinished(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + @NotificationContentInflater.InflationFlag int inflatedFlags) { } }); } @@ -158,14 +159,14 @@ public class NotificationInflaterTest extends SysuiTestCase { @Test @Ignore public void testInflationIsRetriedIfAsyncFails() throws Exception { - NotificationInflater.InflationProgress result = - new NotificationInflater.InflationProgress(); + NotificationContentInflater.InflationProgress result = + new NotificationContentInflater.InflationProgress(); result.packageContext = mContext; CountDownLatch countDownLatch = new CountDownLatch(1); - NotificationInflater.applyRemoteView(result, FLAG_CONTENT_VIEW_EXPANDED, 0, + NotificationContentInflater.applyRemoteView(result, FLAG_CONTENT_VIEW_EXPANDED, 0, new ArrayMap() /* cachedContentViews */, mRow, false /* redactAmbient */, true /* isNewView */, (v, p, r) -> true, - new NotificationInflater.InflationCallback() { + new InflationCallback() { @Override public void handleInflationException(StatusBarNotification notification, Exception e) { @@ -175,11 +176,11 @@ public class NotificationInflaterTest extends SysuiTestCase { @Override public void onAsyncInflationFinished(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + @NotificationContentInflater.InflationFlag int inflatedFlags) { countDownLatch.countDown(); } }, mRow.getPrivateLayout(), null, null, new HashMap<>(), - new NotificationInflater.ApplyCallback() { + new NotificationContentInflater.ApplyCallback() { @Override public void setResultView(View v) { } @@ -199,8 +200,8 @@ public class NotificationInflaterTest extends SysuiTestCase { mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, true); mNotificationInflater.updateNeedsRedaction(true); - NotificationInflater.AsyncInflationTask asyncInflationTask = - (NotificationInflater.AsyncInflationTask) mRow.getEntry().getRunningTask(); + NotificationContentInflater.AsyncInflationTask asyncInflationTask = + (NotificationContentInflater.AsyncInflationTask) mRow.getEntry().getRunningTask(); assertEquals(FLAG_CONTENT_VIEW_AMBIENT | FLAG_CONTENT_VIEW_PUBLIC, asyncInflationTask.getReInflateFlags()); asyncInflationTask.abort(); @@ -217,8 +218,8 @@ public class NotificationInflaterTest extends SysuiTestCase { mNotificationInflater.setIsChildInGroup(true); InflationTask runningTask = mRow.getEntry().getRunningTask(); - NotificationInflater.AsyncInflationTask asyncInflationTask = - (NotificationInflater.AsyncInflationTask) runningTask; + NotificationContentInflater.AsyncInflationTask asyncInflationTask = + (NotificationContentInflater.AsyncInflationTask) runningTask; assertEquals("Successive inflations don't inherit the previous flags!", FLAG_CONTENT_VIEW_ALL, asyncInflationTask.getReInflateFlags()); runningTask.abort(); @@ -233,19 +234,19 @@ public class NotificationInflaterTest extends SysuiTestCase { R.layout.custom_view_dark)); RemoteViews decoratedMediaView = mBuilder.createContentView(); Assert.assertFalse("The decorated media style doesn't allow a view to be reapplied!", - NotificationInflater.canReapplyRemoteView(mediaView, decoratedMediaView)); + NotificationContentInflater.canReapplyRemoteView(mediaView, decoratedMediaView)); } public static void runThenWaitForInflation(Runnable block, - NotificationInflater inflater) throws Exception { + NotificationContentInflater inflater) throws Exception { runThenWaitForInflation(block, false /* expectingException */, inflater); } private static void runThenWaitForInflation(Runnable block, boolean expectingException, - NotificationInflater inflater) throws Exception { + NotificationContentInflater inflater) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(1); final ExceptionHolder exceptionHolder = new ExceptionHolder(); - inflater.setInflationCallback(new NotificationInflater.InflationCallback() { + inflater.setInflationCallback(new InflationCallback() { @Override public void handleInflationException(StatusBarNotification notification, Exception e) { @@ -257,7 +258,7 @@ public class NotificationInflaterTest extends SysuiTestCase { @Override public void onAsyncInflationFinished(NotificationEntry entry, - @NotificationInflater.InflationFlag int inflatedFlags) { + @NotificationContentInflater.InflationFlag int inflatedFlags) { if (expectingException) { exceptionHolder.setException(new RuntimeException( "Inflation finished even though there should be an error")); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java index 24aa772e2fc1..637b30c6bc00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification; +package com.android.systemui.statusbar.notification.row.wrapper; + +import static org.mockito.Mockito.mock; import android.content.Context; import android.support.test.filters.SmallTest; @@ -22,13 +24,15 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.util.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,12 +41,26 @@ import org.junit.runner.RunWith; @RunWithLooper public class NotificationViewWrapperTest extends SysuiTestCase { - @Test - public void constructor_doesntUseViewContext() throws Exception { + private View mView; + private ExpandableNotificationRow mRow; + private TestableNotificationViewWrapper mNotificationViewWrapper; + + @Before + public void setup() throws Exception { Assert.sMainLooper = TestableLooper.get(this).getLooper(); - new TestableNotificationViewWrapper(mContext, - new View(mContext), - new NotificationTestHelper(getContext()).createRow()); + mView = mock(View.class); + mRow = new NotificationTestHelper(getContext()).createRow(); + mNotificationViewWrapper = new TestableNotificationViewWrapper(mContext, mView, mRow); + } + + @Test + public void childrenNeedInversion_doesntCrash_whenOpacity() { + LinearLayout viewGroup = new LinearLayout(mContext); + TextView textView = new TextView(mContext); + textView.setTextColor(0xcc000000); + viewGroup.addView(textView); + + mNotificationViewWrapper.childrenNeedInversion(0xcc000000, viewGroup); } static class TestableNotificationViewWrapper extends NotificationViewWrapper { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java index 608dd8b0d281..120d0b093e0e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java @@ -29,6 +29,7 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationMediaManager; import org.junit.Before; import org.junit.Test; @@ -47,6 +48,8 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase { StatusBar mStatusBar; @Mock StatusBarStateController mStatusBarStateController; + @Mock + private NotificationMediaManager mMediaManager; private NotificationIconAreaController mController; @Before @@ -54,7 +57,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mController = new NotificationIconAreaController(mContext, mStatusBar, - mStatusBarStateController, mListener); + mStatusBarStateController, mListener, mMediaManager); } @Test diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 4afbc641ea6c..4bd50ec21d84 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -45,6 +45,7 @@ import android.provider.Settings; import android.util.LocalLog; import android.util.Slog; import android.util.SparseBooleanArray; +import android.view.contentcapture.ContentCaptureHelper; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.IContentCaptureManager; import android.view.contentcapture.UserDataRemovalRequest; @@ -79,7 +80,8 @@ public final class ContentCaptureManagerService extends private final LocalService mLocalService = new LocalService(); - private final LocalLog mRequestsHistory = new LocalLog(20); + @Nullable + final LocalLog mRequestsHistory; @GuardedBy("mLock") private ActivityManagerInternal mAm; @@ -105,15 +107,19 @@ public final class ContentCaptureManagerService extends UserManager.DISALLOW_CONTENT_CAPTURE); DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ActivityThread.currentApplication().getMainExecutor(), - (namespace, key, value) -> { - if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED - .equals(key)) { - Slog.i(mTag, "Ignoring change on " + key); - return; - } - setDisabledByDeviceConfig(value); - }); - setDisabledByDeviceConfig(); + (namespace, key, value) -> onDeviceConfigChange(key, value)); + setLoggingLevelFromDeviceConfig(); + setDisabledFromDeviceConfig(); + + final int loggingSize = ContentCaptureHelper.getIntDeviceConfigProperty( + ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20); + if (loggingSize > 0) { + if (debug) Slog.d(mTag, "log history size: " + loggingSize); + mRequestsHistory = new LocalLog(loggingSize); + } else { + if (debug) Slog.d(mTag, "disabled log history because size is " + loggingSize); + mRequestsHistory = null; + } // Sets which services are disabled final UserManager um = getContext().getSystemService(UserManager.class); @@ -213,7 +219,33 @@ public final class ContentCaptureManagerService extends return false; } - private void setDisabledByDeviceConfig() { + private void onDeviceConfigChange(@NonNull String key, @Nullable String value) { + switch (key) { + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED: + setDisabledByDeviceConfig(value); + return; + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL: + setLoggingLevelFromDeviceConfig(); + return; + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY: + // TODO(b/123096662): implement it + Slog.d(mTag, "changes on " + key + " not supported yet"); + return; + default: + Slog.i(mTag, "Ignoring change on " + key); + } + } + + private void setLoggingLevelFromDeviceConfig() { + ContentCaptureHelper.setLoggingLevel(); + verbose = ContentCaptureHelper.sVerbose; + debug = ContentCaptureHelper.sDebug; + } + + private void setDisabledFromDeviceConfig() { final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED); setDisabledByDeviceConfig(value); @@ -327,13 +359,6 @@ public final class ContentCaptureManagerService extends } } - /** - * Logs a request so it's dumped later... - */ - void logRequestLocked(@NonNull String historyItem) { - mRequestsHistory.log(historyItem); - } - private ActivityManagerInternal getAmInternal() { synchronized (mLock) { if (mAm == null) { @@ -527,9 +552,13 @@ public final class ContentCaptureManagerService extends synchronized (mLock) { dumpLocked("", pw); } - if (showHistory) { - pw.println(); pw.println("Requests history:"); pw.println(); + pw.print("Requests history: "); + if (mRequestsHistory == null) { + pw.println("disabled by device config"); + } else if (showHistory) { + pw.println(); mRequestsHistory.reverseDump(fd, pw, args); + pw.println(); } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 7102b82d5e18..360f064bdf0d 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -21,6 +21,7 @@ import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED; import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID; import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR; import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE; +import static android.view.contentcapture.ContentCaptureSession.STATE_PACKAGE_NOT_WHITELISTED; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA; @@ -47,7 +48,7 @@ import android.service.contentcapture.ContentCaptureService; import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.ArrayMap; -import android.util.Log; +import android.util.ArraySet; import android.util.Slog; import android.view.contentcapture.UserDataRemovalRequest; @@ -87,6 +88,12 @@ final class ContentCapturePerUserService private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback = new ContentCaptureServiceRemoteCallback(); + /** + * List of packages that are whitelisted to be content captured. + */ + @GuardedBy("mLock") + private final ArraySet<String> mWhitelistedPackages = new ArraySet<>(); + // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's ContentCapturePerUserService(@NonNull ContentCaptureManagerService master, @@ -185,15 +192,19 @@ final class ContentCapturePerUserService final int taskId = activityPresentationInfo.taskId; final int displayId = activityPresentationInfo.displayId; final ComponentName componentName = activityPresentationInfo.componentName; + final boolean whitelisted = isWhitelistedLocked(componentName); final ComponentName serviceComponentName = getServiceComponentName(); final boolean enabled = isEnabledLocked(); - final String historyItem = - "id=" + sessionId + " uid=" + uid - + " a=" + ComponentName.flattenToShortString(componentName) - + " t=" + taskId + " d=" + displayId - + " s=" + ComponentName.flattenToShortString(serviceComponentName) - + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)"); - mMaster.logRequestLocked(historyItem); + if (mMaster.mRequestsHistory != null) { + final String historyItem = + "id=" + sessionId + " uid=" + uid + + " a=" + ComponentName.flattenToShortString(componentName) + + " t=" + taskId + " d=" + displayId + + " s=" + ComponentName.flattenToShortString(serviceComponentName) + + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)") + + " w=" + whitelisted; + mMaster.mRequestsHistory.log(historyItem); + } if (!enabled) { // TODO: it would be better to split in differet reasons, like @@ -212,6 +223,16 @@ final class ContentCapturePerUserService return; } + if (!whitelisted) { + if (mMaster.debug) { + Slog.d(TAG, "startSession(" + componentName + "): not whitelisted"); + } + // TODO(b/122595322): need to return STATE_ACTIVITY_NOT_WHITELISTED as well + setClientState(clientReceiver, STATE_DISABLED | STATE_PACKAGE_NOT_WHITELISTED, + /* binder= */ null); + return; + } + final ContentCaptureServerSession existingSession = mSessions.get(sessionId); if (existingSession != null) { Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken @@ -245,6 +266,26 @@ final class ContentCapturePerUserService newSession.notifySessionStartedLocked(clientReceiver); } + @GuardedBy("mLock") + private boolean isWhitelistedLocked(@NonNull ComponentName componentName) { + // TODO(b/122595322): need to check whitelisted activities as well. + final String packageName = componentName.getPackageName(); + return mWhitelistedPackages.contains(packageName); + } + + private void whitelistPackages(@NonNull List<String> packages) { + // TODO(b/122595322): add CTS test for when it's null + synchronized (mLock) { + if (packages == null) { + if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted packages"); + mWhitelistedPackages.clear(); + } else { + if (mMaster.verbose) Slog.v(TAG, "whitelisting packages: " + packages); + mWhitelistedPackages.addAll(packages); + } + } + } + // TODO(b/119613670): log metrics @GuardedBy("mLock") public void finishSessionLocked(@NonNull String sessionId) { @@ -376,15 +417,23 @@ final class ContentCapturePerUserService mRemoteService.dump(prefix2, pw); } + final int whitelistSize = mWhitelistedPackages.size(); + pw.print(prefix); pw.print("Whitelisted packages: "); pw.println(whitelistSize); + for (int i = 0; i < whitelistSize; i++) { + final String whitelistedPkg = mWhitelistedPackages.valueAt(i); + pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg); + } + if (mSessions.isEmpty()) { pw.print(prefix); pw.println("no sessions"); } else { - final int size = mSessions.size(); - pw.print(prefix); pw.print("number sessions: "); pw.println(size); - for (int i = 0; i < size; i++) { - pw.print(prefix); pw.print("session@"); pw.println(i); + final int sessionsSize = mSessions.size(); + pw.print(prefix); pw.print("number sessions: "); pw.println(sessionsSize); + for (int i = 0; i < sessionsSize; i++) { + pw.print(prefix); pw.print("#"); pw.println(i); final ContentCaptureServerSession session = mSessions.valueAt(i); session.dumpLocked(prefix2, pw); + pw.println(); } } } @@ -410,10 +459,12 @@ final class ContentCapturePerUserService public void setContentCaptureWhitelist(List<String> packages, List<ComponentName> activities) { if (mMaster.verbose) { - Log.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities=" + Slog.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities=" + activities + ")"); } - // TODO(b/122595322): implement + whitelistPackages(packages); + + // TODO(b/122595322): whitelist activities as well // TODO(b/119613670): log metrics } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java index 4ed5c3d263b6..40948432751d 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.os.IBinder; import android.service.contentcapture.ContentCaptureService; import android.service.contentcapture.SnapshotData; +import android.util.LocalLog; import android.util.Slog; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureSessionId; @@ -86,7 +87,10 @@ final class ContentCaptureServerSession { */ @GuardedBy("mLock") public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) { - mService.getMaster().logRequestLocked("snapshot: id=" + mId); + final LocalLog logHistory = mService.getMaster().mRequestsHistory; + if (logHistory != null) { + logHistory.log("snapshot: id=" + mId); + } mRemoteService.onActivitySnapshotRequest(mId, snapshotData); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index dad428acbfee..915c131ff0fb 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -57,8 +57,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.database.ContentObserver; +import android.net.CaptivePortal; import android.net.ConnectionInfo; import android.net.ConnectivityManager; +import android.net.ICaptivePortal; import android.net.IConnectivityManager; import android.net.IIpConnectivityMetrics; import android.net.INetd; @@ -86,6 +88,7 @@ import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; +import android.net.NetworkStackClient; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.NetworkWatchlistManager; @@ -917,7 +920,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mPermissionMonitor = new PermissionMonitor(mContext, mNMS); - //set up the listener for user state for creating user VPNs + // Set up the listener for user state for creating user VPNs. + // Should run on mHandler to avoid any races. IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); @@ -925,7 +929,11 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mIntentReceiver, UserHandle.ALL, intentFilter, null, null); + mIntentReceiver, + UserHandle.ALL, + intentFilter, + null /* broadcastPermission */, + mHandler); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); @@ -936,7 +944,11 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiverAsUser( - mIntentReceiver, UserHandle.ALL, intentFilter, null, null); + mIntentReceiver, + UserHandle.ALL, + intentFilter, + null /* broadcastPermission */, + mHandler); try { mNMS.registerObserver(mTethering); @@ -2690,11 +2702,6 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNai.network.netId)); } - - @Override - public void logCaptivePortalLoginEvent(int eventId, String packageName) { - new MetricsLogger().action(eventId, packageName); - } } private boolean networkRequiresValidation(NetworkAgentInfo nai) { @@ -3249,22 +3256,63 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * NetworkStack endpoint to start the captive portal app. The NetworkStack needs to use this * endpoint as it does not have INTERACT_ACROSS_USERS_FULL itself. + * @param network Network on which the captive portal was detected. * @param appExtras Bundle to use as intent extras for the captive portal application. * Must be treated as opaque to avoid preventing the captive portal app to * update its arguments. */ @Override - public void startCaptivePortalAppInternal(Bundle appExtras) { + public void startCaptivePortalAppInternal(Network network, Bundle appExtras) { mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); appIntent.putExtras(appExtras); + appIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL, + new CaptivePortal(new CaptivePortalImpl(network).asBinder())); appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); Binder.withCleanCallingIdentity(() -> mContext.startActivityAsUser(appIntent, UserHandle.CURRENT)); } + private class CaptivePortalImpl extends ICaptivePortal.Stub { + private final Network mNetwork; + + private CaptivePortalImpl(Network network) { + mNetwork = network; + } + + @Override + public void appResponse(final int response) throws RemoteException { + if (response == CaptivePortal.APP_RETURN_WANTED_AS_IS) { + enforceSettingsPermission(); + } + + // getNetworkAgentInfoForNetwork is thread-safe + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(mNetwork); + if (nai == null) return; + + // nai.networkMonitor() is thread-safe + final INetworkMonitor nm = nai.networkMonitor(); + if (nm == null) return; + + final long token = Binder.clearCallingIdentity(); + try { + nm.notifyCaptivePortalAppFinished(response); + } finally { + // Not using Binder.withCleanCallingIdentity() to keep the checked RemoteException + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void logEvent(int eventId, String packageName) { + enforceSettingsPermission(); + + new MetricsLogger().action(eventId, packageName); + } + } + public boolean avoidBadWifi() { return mMultinetworkPolicyTracker.getAvoidBadWifi(); } @@ -4099,17 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub * handler thread through their agent, this is asynchronous. When the capabilities objects * are computed they will be up-to-date as they are computed synchronously from here and * this is running on the ConnectivityService thread. - * TODO : Fix this and call updateCapabilities inline to remove out-of-order events. */ private void updateAllVpnsCapabilities() { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { for (int i = 0; i < mVpns.size(); i++) { final Vpn vpn = mVpns.valueAt(i); - vpn.updateCapabilities(); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } + private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) { + ensureRunningOnConnectivityServiceThread(); + NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId()); + if (vpnNai == null || nc == null) { + return; + } + updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc); + } + @Override public boolean updateLockdownVpn() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { @@ -4450,22 +4508,28 @@ public class ConnectivityService extends IConnectivityManager.Stub private void onUserAdded(int userId) { mPermissionMonitor.onUserAdded(userId); + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserAdded(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } private void onUserRemoved(int userId) { mPermissionMonitor.onUserRemoved(userId); + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserRemoved(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } @@ -4534,6 +4598,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + ensureRunningOnConnectivityServiceThread(); final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); @@ -5043,6 +5108,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkForRequest(mDefaultRequest.requestId); } + @Nullable + private Network getNetwork(@Nullable NetworkAgentInfo nai) { + return nai != null ? nai.network : null; + } + + private void ensureRunningOnConnectivityServiceThread() { + if (mHandler.getLooper().getThread() != Thread.currentThread()) { + throw new IllegalStateException( + "Not running on ConnectivityService thread: " + + Thread.currentThread().getName()); + } + } + private boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -5099,7 +5177,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("registerNetworkAgent " + nai); final long token = Binder.clearCallingIdentity(); try { - mContext.getSystemService(NetworkStack.class).makeNetworkMonitor( + getNetworkStack().makeNetworkMonitor( toStableParcelable(nai.network), name, new NetworkMonitorCallbacks(nai)); } finally { Binder.restoreCallingIdentity(token); @@ -5111,6 +5189,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return nai.network.netId; } + @VisibleForTesting + protected NetworkStackClient getNetworkStack() { + return NetworkStackClient.getInstance(); + } + private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { nai.onNetworkMonitorCreated(networkMonitor); if (VDBG) log("Got NetworkAgent Messenger"); @@ -5669,6 +5752,8 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes()); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); + // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. + updateAllVpnsCapabilities(); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -6108,6 +6193,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); + if (networkAgent.isVPN()) { + updateAllVpnsCapabilities(); + } + // Consider network even though it is not yet validated. final long now = SystemClock.elapsedRealtime(); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); @@ -6369,7 +6458,11 @@ public class ConnectivityService extends IConnectivityManager.Stub success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { - mHandler.post(() -> notifyIfacesChangedForNetworkStats()); + mHandler.post(() -> { + // Update VPN's capabilities based on updated underlying network set. + updateAllVpnsCapabilities(); + notifyIfacesChangedForNetworkStats(); + }); } return success; } diff --git a/services/core/java/com/android/server/ExtconUEventObserver.java b/services/core/java/com/android/server/ExtconUEventObserver.java index eb591528bc90..775e4c8cf4ed 100644 --- a/services/core/java/com/android/server/ExtconUEventObserver.java +++ b/services/core/java/com/android/server/ExtconUEventObserver.java @@ -68,7 +68,7 @@ public abstract class ExtconUEventObserver extends UEventObserver { * Subclasses of ExtconUEventObserver should override this method to handle UEvents. * * @param extconInfo that matches the {@code DEVPATH} of {@code event} - * @param event the event + * @param event the event */ protected abstract void onUEvent(ExtconInfo extconInfo, UEvent event); @@ -91,6 +91,9 @@ public abstract class ExtconUEventObserver extends UEventObserver { /** Returns a new list of all external connections whose name matches {@code regex}. */ public static List<ExtconInfo> getExtconInfos(@Nullable String regex) { + if (!extconExists()) { + return new ArrayList<>(0); // Always return a new list. + } Pattern p = regex == null ? null : Pattern.compile(regex); File file = new File("/sys/class/extcon"); File[] files = file.listFiles(); diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java index fe30057fc820..5d0e308f6649 100644 --- a/services/core/java/com/android/server/FgThread.java +++ b/services/core/java/com/android/server/FgThread.java @@ -17,9 +17,12 @@ package com.android.server; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.Trace; +import java.util.concurrent.Executor; + /** * Shared singleton foreground thread for the system. This is a thread for regular * foreground service operations, which shouldn't be blocked by anything running in @@ -34,6 +37,7 @@ public final class FgThread extends ServiceThread { private static FgThread sInstance; private static Handler sHandler; + private static HandlerExecutor sHandlerExecutor; private FgThread() { super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); @@ -48,6 +52,7 @@ public final class FgThread extends ServiceThread { looper.setSlowLogThresholdMs( SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); sHandler = new Handler(sInstance.getLooper()); + sHandlerExecutor = new HandlerExecutor(sHandler); } } @@ -64,4 +69,11 @@ public final class FgThread extends ServiceThread { return sHandler; } } + + public static Executor getExecutor() { + synchronized (FgThread.class) { + ensureThreadLocked(); + return sHandlerExecutor; + } + } } diff --git a/services/core/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java index bfe825a3a89e..21fd29c3bbef 100644 --- a/services/core/java/com/android/server/IoThread.java +++ b/services/core/java/com/android/server/IoThread.java @@ -17,8 +17,11 @@ package com.android.server; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Trace; +import java.util.concurrent.Executor; + /** * Shared singleton I/O thread for the system. This is a thread for non-background * service operations that can potential block briefly on network IO operations @@ -27,6 +30,7 @@ import android.os.Trace; public final class IoThread extends ServiceThread { private static IoThread sInstance; private static Handler sHandler; + private static HandlerExecutor sHandlerExecutor; private IoThread() { super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); @@ -38,6 +42,7 @@ public final class IoThread extends ServiceThread { sInstance.start(); sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); sHandler = new Handler(sInstance.getLooper()); + sHandlerExecutor = new HandlerExecutor(sHandler); } } @@ -54,4 +59,11 @@ public final class IoThread extends ServiceThread { return sHandler; } } + + public static Executor getExecutor() { + synchronized (IoThread.class) { + ensureThreadLocked(); + return sHandlerExecutor; + } + } } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 9d92ea2b5b45..5989a46c5a0a 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -2136,6 +2136,13 @@ public class LocationManagerService extends ILocationManager.Stub { } } + @Override + public String[] getIgnoreSettingsWhitelist() { + synchronized (mLock) { + return mIgnoreSettingsPackageWhitelist.toArray(new String[0]); + } + } + @GuardedBy("mLock") private boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) { if (callerIdentity.mUid == Process.SYSTEM_UID) { @@ -2794,8 +2801,7 @@ public class LocationManagerService extends ILocationManager.Stub { } catch (RemoteException e) { // if the remote process registering the listener is already dead, just swallow the // exception and return - Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", - e); + Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", e); return false; } } @@ -2808,8 +2814,7 @@ public class LocationManagerService extends ILocationManager.Stub { } catch (NoSuchElementException e) { // if the death callback isn't connected (it should be...), log error, // swallow the exception and return - Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", - e); + Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", e); return false; } } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 6b57fcd31450..710a0ba34d4f 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -30,11 +30,13 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.os.BatteryManager; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.ServiceType; @@ -354,8 +356,12 @@ final class UiModeManagerService extends SystemService { try { synchronized (mLock) { if (mNightMode != mode) { - Settings.Secure.putIntForUser(getContext().getContentResolver(), - Settings.Secure.UI_NIGHT_MODE, mode, user); + // Only persist setting if not transient night mode or not in car mode + if (!shouldTransientNightWhenInCarMode() || !mCarModeEnabled) { + Settings.Secure.putIntForUser(getContext().getContentResolver(), + Settings.Secure.UI_NIGHT_MODE, mode, user); + } + mNightMode = mode; updateLocked(0, 0); } @@ -438,9 +444,39 @@ final class UiModeManagerService extends SystemService { } } + // Night mode settings in car mode are only persisted below Q. + // When targeting Q, changes are not saved and night mode will be re-read + // from settings when exiting car mode. + private boolean shouldTransientNightWhenInCarMode() { + int uid = Binder.getCallingUid(); + PackageManager packageManager = getContext().getPackageManager(); + String[] packagesForUid = packageManager.getPackagesForUid(uid); + if (packagesForUid == null || packagesForUid.length == 0) { + return false; + } + + try { + ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser( + packagesForUid[0], 0, uid); + + return appInfo.targetSdkVersion >= Build.VERSION_CODES.Q; + } catch (PackageManager.NameNotFoundException ignored) { + } + + return false; + } + void setCarModeLocked(boolean enabled, int flags) { if (mCarModeEnabled != enabled) { mCarModeEnabled = enabled; + + // When transient night mode and exiting car mode, restore night mode from settings + if (shouldTransientNightWhenInCarMode() && !mCarModeEnabled) { + Context context = getContext(); + updateNightModeFromSettings(context, + context.getResources(), + UserHandle.getCallingUserId()); + } } mCarModeEnableFlags = flags; } @@ -498,7 +534,9 @@ final class UiModeManagerService extends SystemService { uiMode |= mNightMode << 4; } - if (mPowerSave) { + // Override night mode in power save mode if not transient night mode or not in car mode + boolean shouldOverrideNight = !mCarModeEnabled || !shouldTransientNightWhenInCarMode(); + if (mPowerSave && shouldOverrideNight) { uiMode &= ~Configuration.UI_MODE_NIGHT_NO; uiMode |= Configuration.UI_MODE_NIGHT_YES; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 93a71e5a2ed4..4e03b72e6ce6 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1692,7 +1692,8 @@ public final class OomAdjuster { (app.curAdj == ProcessList.PREVIOUS_APP_ADJ || app.curAdj == ProcessList.HOME_APP_ADJ)) { mAppCompact.compactAppSome(app); - } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ + } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ + || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ) && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) { mAppCompact.compactAppFull(app); diff --git a/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java index 753d3b0cc10e..3663518bf7b9 100644 --- a/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java +++ b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java @@ -99,7 +99,7 @@ public class CarrierMessagingClientServiceFinder @Override public void startMonitoring() { mRoleManager.addOnRoleHoldersChangedListenerAsUser( - mContext.getMainExecutor(), mRoleHolderChangedListener, UserHandle.ALL); + BackgroundThread.getExecutor(), mRoleHolderChangedListener, UserHandle.ALL); } @Override @@ -120,9 +120,7 @@ public class CarrierMessagingClientServiceFinder private final OnRoleHoldersChangedListener mRoleHolderChangedListener = (role, user) -> { if (RoleManager.ROLE_SMS.equals(role)) { - BackgroundThread.getHandler().post(() -> { - mListener.accept(CarrierMessagingClientServiceFinder.this, user.getIdentifier()); - }); + mListener.accept(CarrierMessagingClientServiceFinder.this, user.getIdentifier()); } }; } diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 9a1d7bf0053d..47c9b8639760 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -104,8 +104,7 @@ public class AttentionManagerService extends SystemService { @Override public void onSwitchUser(int userId) { - cancelAndUnbindLocked(peekUserStateLocked(userId), - AttentionService.ATTENTION_FAILURE_UNKNOWN); + cancelAndUnbindLocked(peekUserStateLocked(userId)); } /** Resolves and sets up the attention service if it had not been done yet. */ @@ -152,7 +151,8 @@ public class AttentionManagerService extends SystemService { } synchronized (mLock) { - unbindAfterTimeoutLocked(); + final long now = SystemClock.uptimeMillis(); + freeIfInactiveLocked(); final UserState userState = getOrCreateCurrentUserStateLocked(); // lazily start the service, which should be very lightweight to start @@ -172,7 +172,7 @@ public class AttentionManagerService extends SystemService { try { // throttle frequent requests final AttentionCheckCache attentionCheckCache = userState.mAttentionCheckCache; - if (attentionCheckCache != null && SystemClock.uptimeMillis() + if (attentionCheckCache != null && now < attentionCheckCache.mLastComputed + STALE_AFTER_MILLIS) { callback.onSuccess(requestCode, attentionCheckCache.mResult, attentionCheckCache.mTimestamp); @@ -190,6 +190,7 @@ public class AttentionManagerService extends SystemService { userState.mAttentionCheckCache = new AttentionCheckCache( SystemClock.uptimeMillis(), result, timestamp); + userState.mCurrentAttentionCheckIsFulfilled = true; } StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, result); @@ -198,14 +199,10 @@ public class AttentionManagerService extends SystemService { @Override public void onFailure(int requestCode, int error) { callback.onFailure(requestCode, error); + userState.mCurrentAttentionCheckIsFulfilled = true; StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, error); } - - @Override - public IBinder asBinder() { - return null; - } }); } catch (RemoteException e) { Slog.e(LOG_TAG, "Cannot call into the AttentionService"); @@ -219,7 +216,10 @@ public class AttentionManagerService extends SystemService { /** Cancels the specified attention check. */ public void cancelAttentionCheck(int requestCode) { synchronized (mLock) { - final UserState userState = getOrCreateCurrentUserStateLocked(); + final UserState userState = peekCurrentUserStateLocked(); + if (userState == null) { + return; + } if (userState.mService == null) { if (userState.mPendingAttentionCheck != null && userState.mPendingAttentionCheck.mRequestCode == requestCode) { @@ -236,8 +236,12 @@ public class AttentionManagerService extends SystemService { } @GuardedBy("mLock") - private void unbindAfterTimeoutLocked() { - mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CONNECTION_EXPIRED, + private void freeIfInactiveLocked() { + // If we are called here, it means someone used the API again - reset the timer then. + mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION); + + // Schedule resources cleanup if no one calls the API again. + mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CHECK_CONNECTION_EXPIRATION, CONNECTION_TTL_MILLIS); } @@ -264,12 +268,14 @@ public class AttentionManagerService extends SystemService { } @GuardedBy("mLock") - UserState peekCurrentUserStateLocked() { + @Nullable + private UserState peekCurrentUserStateLocked() { return peekUserStateLocked(ActivityManager.getCurrentUser()); } @GuardedBy("mLock") - UserState peekUserStateLocked(int userId) { + @Nullable + private UserState peekUserStateLocked(int userId) { return mUserStates.get(userId); } @@ -406,6 +412,8 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") int mCurrentAttentionCheckRequestCode; @GuardedBy("mLock") + boolean mCurrentAttentionCheckIsFulfilled; + @GuardedBy("mLock") PendingAttentionCheck mPendingAttentionCheck; @GuardedBy("mLock") @@ -501,7 +509,7 @@ public class AttentionManagerService extends SystemService { } private class AttentionHandler extends Handler { - private static final int CONNECTION_EXPIRED = 1; + private static final int CHECK_CONNECTION_EXPIRATION = 1; private static final int ATTENTION_CHECK_TIMEOUT = 2; AttentionHandler() { @@ -511,19 +519,26 @@ public class AttentionManagerService extends SystemService { public void handleMessage(Message msg) { switch (msg.what) { // Do not occupy resources when not in use - unbind proactively. - case CONNECTION_EXPIRED: { + case CHECK_CONNECTION_EXPIRATION: { for (int i = 0; i < mUserStates.size(); i++) { - cancelAndUnbindLocked(mUserStates.valueAt(i), - AttentionService.ATTENTION_FAILURE_UNKNOWN); + cancelAndUnbindLocked(mUserStates.valueAt(i)); } - } break; // Callee is no longer interested in the attention check result - cancel. case ATTENTION_CHECK_TIMEOUT: { - cancelAndUnbindLocked(peekCurrentUserStateLocked(), - AttentionService.ATTENTION_FAILURE_TIMED_OUT); + synchronized (mLock) { + final UserState userState = peekCurrentUserStateLocked(); + if (userState != null) { + // If not called back already. + if (!userState.mCurrentAttentionCheckIsFulfilled) { + cancel(userState, + AttentionService.ATTENTION_FAILURE_TIMED_OUT); + } + + } + } } break; @@ -533,25 +548,29 @@ public class AttentionManagerService extends SystemService { } } + private void cancel(UserState userState, @AttentionFailureCodes int failureCode) { + if (userState != null && userState.mService != null) { + try { + userState.mService.cancelAttentionCheck( + userState.mCurrentAttentionCheckRequestCode); + } catch (RemoteException e) { + Slog.e(LOG_TAG, "Unable to cancel attention check"); + } + + if (userState.mPendingAttentionCheck != null) { + userState.mPendingAttentionCheck.cancel(failureCode); + } + } + } + @GuardedBy("mLock") - private void cancelAndUnbindLocked(UserState userState, - @AttentionFailureCodes int failureCode) { + private void cancelAndUnbindLocked(UserState userState) { synchronized (mLock) { - if (userState != null && userState.mService != null) { - try { - userState.mService.cancelAttentionCheck( - userState.mCurrentAttentionCheckRequestCode); - } catch (RemoteException e) { - Slog.e(LOG_TAG, "Unable to cancel attention check"); - } + cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN); - if (userState.mPendingAttentionCheck != null) { - userState.mPendingAttentionCheck.cancel(failureCode); - } - mContext.unbindService(userState.mConnection); - userState.mConnection.cleanupService(); - mUserStates.remove(userState.mUserId); - } + mContext.unbindService(userState.mConnection); + userState.mConnection.cleanupService(); + mUserStates.remove(userState.mUserId); } } @@ -563,8 +582,7 @@ public class AttentionManagerService extends SystemService { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { - cancelAndUnbindLocked(peekCurrentUserStateLocked(), - AttentionService.ATTENTION_FAILURE_UNKNOWN); + cancelAndUnbindLocked(peekCurrentUserStateLocked()); } } } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 6df60d6bdd3a..9af57daa259b 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -280,9 +280,9 @@ import java.util.ArrayList; AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource); sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource); - // Un-mute ringtone stream volume - mAudioService.setUpdateRingerModeServiceInt(); } + // Un-mute ringtone stream volume + mAudioService.postUpdateRingerModeServiceInt(); } /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a6643d49c79f..d902201df212 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -248,6 +248,7 @@ public class AudioService extends IAudioService.Stub private static final int MSG_NOTIFY_VOL_EVENT = 22; private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 23; private static final int MSG_ENABLE_SURROUND_FORMATS = 24; + private static final int MSG_UPDATE_RINGER_MODE = 25; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -753,6 +754,7 @@ public class AudioService extends IAudioService.Stub intentFilter.addAction(Intent.ACTION_USER_FOREGROUND); intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + intentFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false); @@ -2720,7 +2722,11 @@ public class AudioService extends IAudioService.Stub } } - /*package*/ void setUpdateRingerModeServiceInt() { + /*package*/ void postUpdateRingerModeServiceInt() { + sendMsg(mAudioHandler, MSG_UPDATE_RINGER_MODE, SENDMSG_QUEUE, 0, 0, null, 0); + } + + private void onUpdateRingerModeServiceInt() { setRingerModeInt(getRingerModeInternal(), false); } @@ -3217,6 +3223,21 @@ public class AudioService extends IAudioService.Stub if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { return; } + + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + != PackageManager.PERMISSION_GRANTED) { + synchronized (mSetModeDeathHandlers) { + for (SetModeDeathHandler h : mSetModeDeathHandlers) { + if (h.getMode() == AudioSystem.MODE_IN_CALL) { + Log.w(TAG, "getMode is call, Permission Denial: setSpeakerphoneOn from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + return; + } + } + } + } + // for logging only final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on) .append(") from u/pid:").append(Binder.getCallingUid()).append("/") @@ -4944,6 +4965,10 @@ public class AudioService extends IAudioService.Stub case MSG_ENABLE_SURROUND_FORMATS: onEnableSurroundFormats((ArrayList<Integer>) msg.obj); break; + + case MSG_UPDATE_RINGER_MODE: + onUpdateRingerModeServiceInt(); + break; } } } @@ -5159,6 +5184,20 @@ public class AudioService extends IAudioService.Stub } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) || action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) { handleAudioEffectBroadcast(context, intent); + } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { + final int[] suspendedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); + final String[] suspendedPackages = + intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + if (suspendedPackages == null || suspendedUids == null + || suspendedPackages.length != suspendedUids.length) { + return; + } + for (int i = 0; i < suspendedUids.length; i++) { + if (!TextUtils.isEmpty(suspendedPackages[i])) { + mMediaFocusControl.noFocusForSuspendedApp( + suspendedPackages[i], suspendedUids[i]); + } + } } } } // end class AudioServiceBroadcastReceiver @@ -5323,6 +5362,11 @@ public class AudioService extends IAudioService.Stub } } + if (callingPackageName == null || clientId == null || aa == null) { + Log.e(TAG, "Invalid null parameter to request audio focus"); + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd, clientId, callingPackageName, flags, sdk, forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid())); diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index 99f08405a375..db55138e446d 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -45,8 +45,8 @@ public class FocusRequester { private AudioFocusDeathHandler mDeathHandler; // may be null private IAudioFocusDispatcher mFocusDispatcher; // may be null private final IBinder mSourceRef; // may be null - private final String mClientId; - private final String mPackageName; + private final @NonNull String mClientId; + private final @NonNull String mPackageName; private final int mCallingUid; private final MediaFocusControl mFocusController; // never null private final int mSdkTarget; @@ -72,7 +72,7 @@ public class FocusRequester { /** * the audio attributes associated with the focus request */ - private final AudioAttributes mAttributes; + private final @NonNull AudioAttributes mAttributes; /** * Class constructor @@ -87,9 +87,10 @@ public class FocusRequester { * @param uid * @param ctlr cannot be null */ - FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags, - IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, - String pn, int uid, @NonNull MediaFocusControl ctlr, int sdk) { + FocusRequester(@NonNull AudioAttributes aa, int focusRequest, int grantFlags, + IAudioFocusDispatcher afl, IBinder source, @NonNull String id, + AudioFocusDeathHandler hdlr, @NonNull String pn, int uid, + @NonNull MediaFocusControl ctlr, int sdk) { mAttributes = aa; mFocusDispatcher = afl; mSourceRef = source; @@ -124,11 +125,7 @@ public class FocusRequester { } boolean hasSameClient(String otherClient) { - try { - return mClientId.compareTo(otherClient) == 0; - } catch (NullPointerException e) { - return false; - } + return mClientId.compareTo(otherClient) == 0; } boolean isLockedFocusOwner() { @@ -143,12 +140,8 @@ public class FocusRequester { return (mFocusDispatcher != null) && mFocusDispatcher.equals(fd); } - boolean hasSamePackage(String pack) { - try { - return mPackageName.compareTo(pack) == 0; - } catch (NullPointerException e) { - return false; - } + boolean hasSamePackage(@NonNull String pack) { + return mPackageName.compareTo(pack) == 0; } boolean hasSameUid(int uid) { diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index d023bd7827ff..b4bbbc729505 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -24,7 +24,6 @@ import android.media.AudioFocusInfo; import android.media.AudioManager; import android.media.AudioSystem; import android.media.IAudioFocusDispatcher; -import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.IAudioPolicyCallback; import android.os.Binder; import android.os.Build; @@ -35,6 +34,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; +import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -44,7 +44,6 @@ import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.Stack; -import java.text.DateFormat; /** * @hide @@ -138,6 +137,30 @@ public class MediaFocusControl implements PlayerFocusEnforcer { private static final AudioEventLogger mEventLogger = new AudioEventLogger(50, "focus commands as seen by MediaFocusControl"); + /*package*/ void noFocusForSuspendedApp(@NonNull String packageName, int uid) { + synchronized (mAudioFocusLock) { + final Iterator<FocusRequester> stackIterator = mFocusStack.iterator(); + List<String> clientsToRemove = new ArrayList<>(); + while (stackIterator.hasNext()) { + final FocusRequester focusOwner = stackIterator.next(); + if (focusOwner.hasSameUid(uid) && focusOwner.hasSamePackage(packageName)) { + clientsToRemove.add(focusOwner.getClientId()); + mEventLogger.log((new AudioEventLogger.StringEvent( + "focus owner:" + focusOwner.getClientId() + + " in uid:" + uid + " pack: " + packageName + + " getting AUDIOFOCUS_LOSS due to app suspension")) + .printLog(TAG)); + // make the suspended app lose focus through its focus listener (if any) + focusOwner.dispatchFocusChange(AudioManager.AUDIOFOCUS_LOSS); + } + } + for (String clientToRemove : clientsToRemove) { + // update the stack but don't signal the change. + removeFocusStackEntry(clientToRemove, false, true); + } + } + } + /** * Discard the current audio focus owner. * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign @@ -688,9 +711,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */ - protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb, - IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags, - int sdk, boolean forceDuck) { + protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb, + IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName, + int flags, int sdk, boolean forceDuck) { mEventLogger.log((new AudioEventLogger.StringEvent( "requestAudioFocus() from uid/pid " + Binder.getCallingUid() + "/" + Binder.getCallingPid() diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 19bdc0969e6d..c91e1a12078e 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1859,7 +1859,7 @@ public class Tethering extends BaseNetworkObserver { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mDeps.getIpServerDependencies(mContext))); + mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index e1af81b2f658..da547eaf8db2 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -241,7 +241,7 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); loadAlwaysOnPackage(); } @@ -268,22 +268,44 @@ public class Vpn { updateAlwaysOnNotification(detailedState); } - public void updateCapabilities() { - final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null; - // Only apps targeting Q and above can explicitly declare themselves as metered. - final boolean isAlwaysMetered = - mIsPackageTargetingAtLeastQ && (mConfig == null || mConfig.isMetered); - updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks, - mNetworkCapabilities, isAlwaysMetered); + /** + * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a + * defensive copy. + * + * <p>Does not propagate updated capabilities to apps. + * + * @param defaultNetwork underlying network for VPNs following platform's default + */ + public synchronized NetworkCapabilities updateCapabilities( + @Nullable Network defaultNetwork) { + if (mConfig == null) { + // VPN is not running. + return null; + } - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + Network[] underlyingNetworks = mConfig.underlyingNetworks; + if (underlyingNetworks == null && defaultNetwork != null) { + // null underlying networks means to track the default. + underlyingNetworks = new Network[] { defaultNetwork }; } + // Only apps targeting Q and above can explicitly declare themselves as metered. + final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered; + + applyUnderlyingCapabilities( + mContext.getSystemService(ConnectivityManager.class), + underlyingNetworks, + mNetworkCapabilities, + isAlwaysMetered); + + return new NetworkCapabilities(mNetworkCapabilities); } @VisibleForTesting - public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks, - NetworkCapabilities caps, boolean isAlwaysMetered) { + public static void applyUnderlyingCapabilities( + ConnectivityManager cm, + Network[] underlyingNetworks, + NetworkCapabilities caps, + boolean isAlwaysMetered) { int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; @@ -296,6 +318,7 @@ public class Vpn { boolean hadUnderlyingNetworks = false; if (null != underlyingNetworks) { for (Network underlying : underlyingNetworks) { + // TODO(b/124469351): Get capabilities directly from ConnectivityService instead. final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying); if (underlyingCaps == null) continue; hadUnderlyingNetworks = true; @@ -1007,9 +1030,8 @@ public class Vpn { } /** - * Establish a VPN network and return the file descriptor of the VPN - * interface. This methods returns {@code null} if the application is - * revoked or not prepared. + * Establish a VPN network and return the file descriptor of the VPN interface. This methods + * returns {@code null} if the application is revoked or not prepared. * * @param config The parameters to configure the network. * @return The file descriptor of the VPN interface. @@ -1101,8 +1123,6 @@ public class Vpn { // as rules are deleted. This prevents data leakage as the rules are moved over. agentDisconnect(oldNetworkAgent); } - // Set up VPN's capabilities such as meteredness. - updateCapabilities(); if (oldConnection != null) { mContext.unbindService(oldConnection); @@ -1258,6 +1278,11 @@ public class Vpn { return ranges; } + /** + * Updates UID ranges for this VPN and also updates its internal capabilities. + * + * <p>Should be called on primary ConnectivityService thread. + */ public void onUserAdded(int userHandle) { // If the user is restricted tie them to the parent user's VPN UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1268,8 +1293,9 @@ public class Vpn { try { addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications, mConfig.disallowedApplications); + // ConnectivityService will call {@link #updateCapabilities} and apply + // those for VPN network. mNetworkCapabilities.setUids(existingRanges); - updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to add restricted user to owner", e); } @@ -1279,6 +1305,11 @@ public class Vpn { } } + /** + * Updates UID ranges for this VPN and also updates its capabilities. + * + * <p>Should be called on primary ConnectivityService thread. + */ public void onUserRemoved(int userHandle) { // clean up if restricted UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1290,8 +1321,9 @@ public class Vpn { final List<UidRange> removedRanges = uidRangesForUser(userHandle, existingRanges); existingRanges.removeAll(removedRanges); + // ConnectivityService will call {@link #updateCapabilities} and + // apply those for VPN network. mNetworkCapabilities.setUids(existingRanges); - updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to remove restricted user to owner", e); } @@ -1504,6 +1536,12 @@ public class Vpn { return success; } + /** + * Updates underlying network set. + * + * <p>Note: Does not updates capabilities. Call {@link #updateCapabilities} from + * ConnectivityService thread to get updated capabilities. + */ public synchronized boolean setUnderlyingNetworks(Network[] networks) { if (!isCallerEstablishedOwnerLocked()) { return false; @@ -1520,7 +1558,6 @@ public class Vpn { } } } - updateCapabilities(); return true; } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java index 3fddac111ec5..173d7860e4ac 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -61,8 +61,8 @@ public class TetheringDependencies { /** * Get dependencies to be used by IpServer. */ - public IpServer.Dependencies getIpServerDependencies(Context context) { - return new IpServer.Dependencies(context); + public IpServer.Dependencies getIpServerDependencies() { + return new IpServer.Dependencies(); } /** diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java index 45f169ca0b6f..7dd3b363810d 100644 --- a/services/core/java/com/android/server/display/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/ColorDisplayService.java @@ -129,240 +129,9 @@ public final class ColorDisplayService extends SystemService { private final NightDisplayTintController mNightDisplayTintController = new NightDisplayTintController(); - private final TintController mDisplayWhiteBalanceTintController = new TintController() { - // Three chromaticity coordinates per color: X, Y, and Z - private final int NUM_VALUES_PER_PRIMARY = 3; - // Four colors: red, green, blue, and white - private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY; - - private final Object mLock = new Object(); - private int mTemperatureMin; - private int mTemperatureMax; - private int mTemperatureDefault; - private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; - private ColorSpace.Rgb mDisplayColorSpaceRGB; - private float[] mChromaticAdaptationMatrix; - private int mCurrentColorTemperature; - private float[] mCurrentColorTemperatureXYZ; - private boolean mSetUp = false; - private float[] mMatrixDisplayWhiteBalance = new float[16]; - private Boolean mIsAvailable; - - @Override - public void setUp(Context context, boolean needsLinear) { - mSetUp = false; - final Resources res = context.getResources(); - - ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl(); - if (displayColorSpaceRGB == null) { - Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res"); - displayColorSpaceRGB = getDisplayColorSpaceFromResources(res); - if (displayColorSpaceRGB == null) { - Slog.e(TAG, "Failed to get display color space from resources"); - return; - } - } - - final String[] nominalWhiteValues = res.getStringArray( - R.array.config_displayWhiteBalanceDisplayNominalWhite); - float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; - for (int i = 0; i < nominalWhiteValues.length; i++) { - displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]); - } - - final int colorTemperatureMin = res.getInteger( - R.integer.config_displayWhiteBalanceColorTemperatureMin); - if (colorTemperatureMin <= 0) { - Slog.e(TAG, "Display white balance minimum temperature must be greater than 0"); - return; - } - - final int colorTemperatureMax = res.getInteger( - R.integer.config_displayWhiteBalanceColorTemperatureMax); - if (colorTemperatureMax < colorTemperatureMin) { - Slog.e(TAG, "Display white balance max temp must be greater or equal to min"); - return; - } - - final int colorTemperature = res.getInteger( - R.integer.config_displayWhiteBalanceColorTemperatureDefault); - - synchronized (mLock) { - mDisplayColorSpaceRGB = displayColorSpaceRGB; - mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ; - mTemperatureMin = colorTemperatureMin; - mTemperatureMax = colorTemperatureMax; - mTemperatureDefault = colorTemperature; - mSetUp = true; - } - - setMatrix(mTemperatureDefault); - } - - @Override - public float[] getMatrix() { - return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY; - } - - @Override - public void setMatrix(int cct) { - if (!mSetUp) { - Slog.w(TAG, "Can't set display white balance temperature: uninitialized"); - return; - } - - if (cct < mTemperatureMin) { - Slog.w(TAG, "Requested display color temperature is below allowed minimum"); - cct = mTemperatureMin; - } else if (cct > mTemperatureMax) { - Slog.w(TAG, "Requested display color temperature is above allowed maximum"); - cct = mTemperatureMax; - } - - Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct); - - synchronized (mLock) { - mCurrentColorTemperature = cct; - - // Adapt the display's nominal white point to match the requested CCT value - mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct); - - mChromaticAdaptationMatrix = - ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD, - mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ); - - // Convert the adaptation matrix to RGB space - float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix, - mDisplayColorSpaceRGB.getTransform()); - result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result); - - // Normalize the transform matrix to peak white value in RGB space - final float adaptedMaxR = result[0] + result[3] + result[6]; - final float adaptedMaxG = result[1] + result[4] + result[7]; - final float adaptedMaxB = result[2] + result[5] + result[8]; - final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB); - for (int i = 0; i < result.length; i++) { - result[i] /= denum; - } - - Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0); - java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3); - java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3); - java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3); - } - } - - @Override - public int getLevel() { - return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE; - } - - @Override - public boolean isAvailable(Context context) { - if (mIsAvailable == null) { - mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context); - } - return mIsAvailable; - } - - /** - * Format a given matrix into a string. - * - * @param matrix the matrix to format - * @param cols number of columns in the matrix - */ - private String matrixToString(float[] matrix, int cols) { - if (matrix == null || cols <= 0) { - Slog.e(TAG, "Invalid arguments when formatting matrix to string"); - return ""; - } - - StringBuilder sb = new StringBuilder(""); - for (int i = 0; i < matrix.length; i++) { - if (i % cols == 0) { - sb.append("\n "); - } - sb.append(String.format("%9.6f ", matrix[i])); - } - return sb.toString(); - } - - @Override - public void dump(PrintWriter pw) { - synchronized (mLock) { - pw.println(" mSetUp = " + mSetUp); - if (!mSetUp) { - return; - } - - pw.println(" isActivated = " + isActivated()); - pw.println(" mTemperatureMin = " + mTemperatureMin); - pw.println(" mTemperatureMax = " + mTemperatureMax); - pw.println(" mTemperatureDefault = " + mTemperatureDefault); - pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature); - pw.println(" mCurrentColorTemperatureXYZ = " + - matrixToString(mCurrentColorTemperatureXYZ, 3)); - pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " + - matrixToString(mDisplayColorSpaceRGB.getTransform(), 3)); - pw.println(" mChromaticAdaptationMatrix = " + - matrixToString(mChromaticAdaptationMatrix, 3)); - pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " + - matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3)); - pw.println(" mMatrixDisplayWhiteBalance = " + - matrixToString(mMatrixDisplayWhiteBalance, 4)); - } - } - - private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) { - return new ColorSpace.Rgb( - "Display Color Space", - redGreenBlueXYZ, - whiteXYZ, - 2.2f // gamma, unused for display white balance - ); - } - - private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() { - final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); - if (displayToken == null) { - return null; - } - - DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken); - if (primaries == null || primaries.red == null || primaries.green == null || - primaries.blue == null || primaries.white == null) { - return null; - } - - return makeRgbColorSpaceFromXYZ( - new float[] { - primaries.red.X, primaries.red.Y, primaries.red.Z, - primaries.green.X, primaries.green.Y, primaries.green.Z, - primaries.blue.X, primaries.blue.Y, primaries.blue.Z, - }, - new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z } - ); - } - - private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) { - final String[] displayPrimariesValues = res.getStringArray( - R.array.config_displayWhiteBalanceDisplayPrimaries); - float[] displayRedGreenBlueXYZ = - new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY]; - float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; - - for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) { - displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]); - } - - for (int i = 0; i < displayWhiteXYZ.length; i++) { - displayWhiteXYZ[i] = Float.parseFloat( - displayPrimariesValues[displayRedGreenBlueXYZ.length + i]); - } - - return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ); - } - }; + @VisibleForTesting + final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController = + new DisplayWhiteBalanceTintController(); private final TintController mGlobalSaturationTintController = new TintController() { @@ -860,7 +629,8 @@ public final class ColorDisplayService extends SystemService { return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt; } - private void updateDisplayWhiteBalanceStatus() { + @VisibleForTesting + void updateDisplayWhiteBalanceStatus() { boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated(); mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() && !mNightDisplayTintController.isActivated() && @@ -1101,6 +871,7 @@ public final class ColorDisplayService extends SystemService { pw.println("Display white balance:"); if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated()); + mDisplayWhiteBalanceTintController.dump(pw); } else { pw.println(" Not available"); } @@ -1533,6 +1304,244 @@ public final class ColorDisplayService extends SystemService { } } + final class DisplayWhiteBalanceTintController extends TintController { + // Three chromaticity coordinates per color: X, Y, and Z + private final int NUM_VALUES_PER_PRIMARY = 3; + // Four colors: red, green, blue, and white + private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY; + + private final Object mLock = new Object(); + @VisibleForTesting + int mTemperatureMin; + @VisibleForTesting + int mTemperatureMax; + private int mTemperatureDefault; + private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; + @VisibleForTesting + ColorSpace.Rgb mDisplayColorSpaceRGB; + private float[] mChromaticAdaptationMatrix; + @VisibleForTesting + int mCurrentColorTemperature; + private float[] mCurrentColorTemperatureXYZ; + private boolean mSetUp = false; + private float[] mMatrixDisplayWhiteBalance = new float[16]; + private Boolean mIsAvailable; + + @Override + public void setUp(Context context, boolean needsLinear) { + mSetUp = false; + final Resources res = context.getResources(); + + ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl(); + if (displayColorSpaceRGB == null) { + Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res"); + displayColorSpaceRGB = getDisplayColorSpaceFromResources(res); + if (displayColorSpaceRGB == null) { + Slog.e(TAG, "Failed to get display color space from resources"); + return; + } + } + + final String[] nominalWhiteValues = res.getStringArray( + R.array.config_displayWhiteBalanceDisplayNominalWhite); + float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; + for (int i = 0; i < nominalWhiteValues.length; i++) { + displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]); + } + + final int colorTemperatureMin = res.getInteger( + R.integer.config_displayWhiteBalanceColorTemperatureMin); + if (colorTemperatureMin <= 0) { + Slog.e(TAG, "Display white balance minimum temperature must be greater than 0"); + return; + } + + final int colorTemperatureMax = res.getInteger( + R.integer.config_displayWhiteBalanceColorTemperatureMax); + if (colorTemperatureMax < colorTemperatureMin) { + Slog.e(TAG, "Display white balance max temp must be greater or equal to min"); + return; + } + + final int colorTemperature = res.getInteger( + R.integer.config_displayWhiteBalanceColorTemperatureDefault); + + synchronized (mLock) { + mDisplayColorSpaceRGB = displayColorSpaceRGB; + mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ; + mTemperatureMin = colorTemperatureMin; + mTemperatureMax = colorTemperatureMax; + mTemperatureDefault = colorTemperature; + mSetUp = true; + } + + setMatrix(mTemperatureDefault); + } + + @Override + public float[] getMatrix() { + return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY; + } + + @Override + public void setMatrix(int cct) { + if (!mSetUp) { + Slog.w(TAG, "Can't set display white balance temperature: uninitialized"); + return; + } + + if (cct < mTemperatureMin) { + Slog.w(TAG, "Requested display color temperature is below allowed minimum"); + cct = mTemperatureMin; + } else if (cct > mTemperatureMax) { + Slog.w(TAG, "Requested display color temperature is above allowed maximum"); + cct = mTemperatureMax; + } + + Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct); + + synchronized (mLock) { + mCurrentColorTemperature = cct; + + // Adapt the display's nominal white point to match the requested CCT value + mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct); + + mChromaticAdaptationMatrix = + ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD, + mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ); + + // Convert the adaptation matrix to RGB space + float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix, + mDisplayColorSpaceRGB.getTransform()); + result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result); + + // Normalize the transform matrix to peak white value in RGB space + final float adaptedMaxR = result[0] + result[3] + result[6]; + final float adaptedMaxG = result[1] + result[4] + result[7]; + final float adaptedMaxB = result[2] + result[5] + result[8]; + final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB); + for (int i = 0; i < result.length; i++) { + result[i] /= denum; + } + + Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0); + java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3); + java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3); + java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3); + } + } + + @Override + public int getLevel() { + return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE; + } + + @Override + public boolean isAvailable(Context context) { + if (mIsAvailable == null) { + mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context); + } + return mIsAvailable; + } + + /** + * Format a given matrix into a string. + * + * @param matrix the matrix to format + * @param cols number of columns in the matrix + */ + private String matrixToString(float[] matrix, int cols) { + if (matrix == null || cols <= 0) { + Slog.e(TAG, "Invalid arguments when formatting matrix to string"); + return ""; + } + + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < matrix.length; i++) { + if (i % cols == 0) { + sb.append("\n "); + } + sb.append(String.format("%9.6f ", matrix[i])); + } + return sb.toString(); + } + + @Override + public void dump(PrintWriter pw) { + synchronized (mLock) { + pw.println(" mSetUp = " + mSetUp); + if (!mSetUp) { + return; + } + + pw.println(" mTemperatureMin = " + mTemperatureMin); + pw.println(" mTemperatureMax = " + mTemperatureMax); + pw.println(" mTemperatureDefault = " + mTemperatureDefault); + pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature); + pw.println(" mCurrentColorTemperatureXYZ = " + + matrixToString(mCurrentColorTemperatureXYZ, 3)); + pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " + + matrixToString(mDisplayColorSpaceRGB.getTransform(), 3)); + pw.println(" mChromaticAdaptationMatrix = " + + matrixToString(mChromaticAdaptationMatrix, 3)); + pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " + + matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3)); + pw.println(" mMatrixDisplayWhiteBalance = " + + matrixToString(mMatrixDisplayWhiteBalance, 4)); + } + } + + private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) { + return new ColorSpace.Rgb( + "Display Color Space", + redGreenBlueXYZ, + whiteXYZ, + 2.2f // gamma, unused for display white balance + ); + } + + private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() { + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + if (displayToken == null) { + return null; + } + + DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken); + if (primaries == null || primaries.red == null || primaries.green == null || + primaries.blue == null || primaries.white == null) { + return null; + } + + return makeRgbColorSpaceFromXYZ( + new float[] { + primaries.red.X, primaries.red.Y, primaries.red.Z, + primaries.green.X, primaries.green.Y, primaries.green.Z, + primaries.blue.X, primaries.blue.Y, primaries.blue.Z, + }, + new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z } + ); + } + + private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) { + final String[] displayPrimariesValues = res.getStringArray( + R.array.config_displayWhiteBalanceDisplayPrimaries); + float[] displayRedGreenBlueXYZ = + new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY]; + float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; + + for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) { + displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]); + } + + for (int i = 0; i < displayWhiteXYZ.length; i++) { + displayWhiteXYZ[i] = Float.parseFloat( + displayPrimariesValues[displayRedGreenBlueXYZ.length + i]); + } + + return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ); + } + }; + /** * Local service that allows color transforms to be enabled from other system services. */ diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index dc5be6a6a074..15c7ef75866f 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1019,7 +1019,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mDisplayWhiteBalanceController != null) { if (state == Display.STATE_ON && mDisplayWhiteBalanceSettings.isEnabled()) { mDisplayWhiteBalanceController.setEnabled(true); - mDisplayWhiteBalanceController.updateScreenColorTemperature(); + mDisplayWhiteBalanceController.updateDisplayColorTemperature(); } else { mDisplayWhiteBalanceController.setEnabled(false); } diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index b9aa34e89216..d95e92b71357 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -29,14 +29,14 @@ import java.io.PrintWriter; /** * The DisplayWhiteBalanceController drives display white-balance (automatically correcting the - * screen color temperature depending on the ambient color temperature). + * display color temperature depending on the ambient color temperature). * * The DisplayWhiteBalanceController: * - Uses the AmbientColorTemperatureSensor to detect changes in the ambient color temperature; * - Uses the AmbientColorTemperatureFilter to average these changes over time, filter out the * noise, and arrive at an estimate of the actual ambient color temperature; - * - Uses the DisplayWhiteBalanceThrottler to decide whether the screen color tempearture should be - * updated, suppressing changes that are too frequent or too minor. + * - Uses the DisplayWhiteBalanceThrottler to decide whether the display color tempearture should + * be updated, suppressing changes that are too frequent or too minor. */ public class DisplayWhiteBalanceController implements AmbientSensor.AmbientBrightnessSensor.Callbacks, @@ -76,8 +76,8 @@ public class DisplayWhiteBalanceController implements // Override the ambient color temperature for debugging purposes. private float mAmbientColorTemperatureOverride; - // A piecewise linear relationship between ambient and display color temperatures - private Spline.LinearSpline mAmbientToDisplayTemperatureSpline; + // A piecewise linear relationship between ambient and display color temperatures. + private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline; /** * @param brightnessSensor @@ -91,7 +91,7 @@ public class DisplayWhiteBalanceController implements * The filter used to average ambient color temperature changes over time, filter out the * noise and arrive at an estimate of the actual ambient color temperature. * @param throttler - * The throttler used to determine whether the new screen color temperature should be + * The throttler used to determine whether the new display color temperature should be * updated or not. * @param lowLightAmbientBrightnessThreshold * The ambient brightness threshold beneath which we fall back to a fixed ambient color @@ -99,6 +99,12 @@ public class DisplayWhiteBalanceController implements * @param lowLightAmbientColorTemperature * The ambient color temperature to which we fall back when the ambient brightness drops * beneath a certain threshold. + * @param ambientColorTemperatures + * The ambient color tempeartures used to map the ambient color temperature to the display + * color temperature (or null if no mapping is necessary). + * @param displayColorTemperatures + * The display color temperatures used to map the ambient color temperature to the display + * color temperature (or null if no mapping is necessary). * * @throws NullPointerException * - brightnessSensor is null; @@ -114,7 +120,7 @@ public class DisplayWhiteBalanceController implements @NonNull AmbientFilter colorTemperatureFilter, @NonNull DisplayWhiteBalanceThrottler throttler, float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature, - float[] ambientTemperatures, float[] displayTemperatures) { + float[] ambientColorTemperatures, float[] displayColorTemperatures) { validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter, throttler); mLoggingEnabled = false; @@ -134,10 +140,10 @@ public class DisplayWhiteBalanceController implements mAmbientColorTemperatureOverride = -1.0f; try { - mAmbientToDisplayTemperatureSpline = new Spline.LinearSpline(ambientTemperatures, - displayTemperatures); + mAmbientToDisplayColorTemperatureSpline = new Spline.LinearSpline( + ambientColorTemperatures, displayColorTemperatures); } catch (Exception e) { - mAmbientToDisplayTemperatureSpline = null; + mAmbientToDisplayColorTemperatureSpline = null; } mColorDisplayServiceInternal = LocalServices.getService(ColorDisplayServiceInternal.class); @@ -160,7 +166,7 @@ public class DisplayWhiteBalanceController implements } /** - * Set an object to call back to when the screen color temperature should be updated. + * Set an object to call back to when the display color temperature should be updated. * * @param callbacks * The object to call back to. @@ -201,7 +207,7 @@ public class DisplayWhiteBalanceController implements * * This is only applied when the ambient color temperature changes or is updated (in which case * it overrides the ambient color temperature estimate); in other words, it doesn't necessarily - * change the screen color temperature immediately. + * change the display color temperature immediately. * * @param ambientColorTemperatureOverride * The ambient color temperature override. @@ -240,9 +246,8 @@ public class DisplayWhiteBalanceController implements writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature); writer.println(" mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory); writer.println(" mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride); - writer.println(" mAmbientToDisplayTemperatureSpline=" - + (mAmbientToDisplayTemperatureSpline == null ? "unused" : - mAmbientToDisplayTemperatureSpline)); + writer.println(" mAmbientToDisplayColorTemperatureSpline=" + + mAmbientToDisplayColorTemperatureSpline); } @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks @@ -266,9 +271,9 @@ public class DisplayWhiteBalanceController implements final long time = System.currentTimeMillis(); float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); - if (mAmbientToDisplayTemperatureSpline != null) { + if (mAmbientToDisplayColorTemperatureSpline != null) { ambientColorTemperature = - mAmbientToDisplayTemperatureSpline.interpolate(ambientColorTemperature); + mAmbientToDisplayColorTemperatureSpline.interpolate(ambientColorTemperature); } final float ambientBrightness = mBrightnessFilter.getEstimate(time); @@ -290,7 +295,7 @@ public class DisplayWhiteBalanceController implements ambientColorTemperature = mAmbientColorTemperatureOverride; } - // When the screen color temperature needs to be updated, we call DisplayPowerController to + // When the display color temperature needs to be updated, we call DisplayPowerController to // call our updateColorTemperature. The reason we don't call it directly is that we want // all changes to the system to happen in a predictable order in DPC's main loop // (updatePowerState). @@ -308,9 +313,9 @@ public class DisplayWhiteBalanceController implements } /** - * Updates the screen color temperature. + * Updates the display color temperature. */ - public void updateScreenColorTemperature() { + public void updateDisplayColorTemperature() { float ambientColorTemperature = -1.0f; // If both the pending and the current ambient color temperatures are -1, it means the DWBC @@ -353,7 +358,7 @@ public class DisplayWhiteBalanceController implements * Called whenever the display white-balance state has changed. * * Usually, this means the estimated ambient color temperature has changed enough, and the - * screen color temperature should be updated; but it is also called by + * display color temperature should be updated; but it is also called if settings change. */ void updateWhiteBalance(); } diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java index 56f4ca339eb3..449f115ad3e3 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java @@ -67,14 +67,14 @@ public class DisplayWhiteBalanceFactory { final float lowLightAmbientColorTemperature = getFloat(resources, com.android.internal.R.dimen .config_displayWhiteBalanceLowLightAmbientColorTemperature); - final float[] ambientTemperatures = getFloatArray(resources, - com.android.internal.R.array.config_displayWhiteBalanceAmbientTemperatureValues); - final float[] displayTemperatures = getFloatArray(resources, - com.android.internal.R.array.config_displayWhiteBalanceDisplayTemperatureValues); + final float[] ambientColorTemperatures = getFloatArray(resources, + com.android.internal.R.array.config_displayWhiteBalanceAmbientColorTemperatures); + final float[] displayColorTempeartures = getFloatArray(resources, + com.android.internal.R.array.config_displayWhiteBalanceDisplayColorTemperatures); final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController( brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter, throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature, - ambientTemperatures, displayTemperatures); + ambientColorTemperatures, displayColorTempeartures); brightnessSensor.setCallbacks(controller); colorTemperatureSensor.setCallbacks(controller); return controller; diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java index c1f0e983a366..5941bbb62d94 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java @@ -23,7 +23,7 @@ import java.util.Arrays; /** * The DisplayWhiteBalanceController uses the DisplayWhiteBalanceThrottler to decide whether the - * screen color temperature should be updated, suppressing changes that are too frequent or too + * display color temperature should be updated, suppressing changes that are too frequent or too * minor. */ class DisplayWhiteBalanceThrottler { diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index e71b156c3e86..243b6fe7a30e 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -373,6 +373,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final NtpTimeHelper mNtpTimeHelper; private final GnssBatchingProvider mGnssBatchingProvider; private final GnssGeofenceProvider mGnssGeofenceProvider; + // Available only on GNSS HAL 2.0 implementations and later. private GnssVisibilityControl mGnssVisibilityControl; // Handler for processing events @@ -463,8 +464,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } }; - // TODO(b/119326010): replace OnSubscriptionsChangedListener with - // ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED broadcast reseiver. + // TODO: replace OnSubscriptionsChangedListener with ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED + // broadcast receiver. private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = new OnSubscriptionsChangedListener() { @Override @@ -676,8 +677,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mNtpTimeHelper.onNetworkAvailable(); if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { if (mSupportsXtra) { - // Download only if supported, (prevents an unneccesary on-boot - // download) + // Download only if supported, (prevents an unnecessary on-boot download) xtraDownloadRequest(); } } @@ -764,7 +764,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements /** Returns true if the location request is too frequent. */ private boolean isRequestLocationRateLimited() { - // TODO(b/73198123): implement exponential backoff. + // TODO: implement exponential backoff. return false; } diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java index c3f25bfa2e5e..20f872a213fd 100644 --- a/services/core/java/com/android/server/location/GnssVisibilityControl.java +++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java @@ -24,10 +24,13 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.ContentObserver; +import android.location.LocationManager; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.UserHandle; +import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.util.StatsLog; @@ -70,7 +73,7 @@ class GnssVisibilityControl { private final Handler mHandler; private final Context mContext; - private boolean mIsMasterLocationSettingsEnabled = true; + private boolean mIsDeviceLocationSettingsEnabled; // Number of non-framework location access proxy apps is expected to be small (< 5). private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7; @@ -88,13 +91,9 @@ class GnssVisibilityControl { mAppOps = mContext.getSystemService(AppOpsManager.class); mPackageManager = mContext.getPackageManager(); - // Set to empty proxy app list initially until the configuration properties are loaded. - updateNfwLocationAccessProxyAppsInGnssHal(); - - // Listen for proxy app package installation, removal events. - listenForProxyAppsPackageUpdates(); - - // TODO(b/122855984): Handle global location settings on/off. + // Complete initialization as the first event to run in mHandler thread. After that, + // all object state read/update events run in the mHandler thread. + runOnHandler(this::handleInitialize); } void updateProxyApps(List<String> nfwLocationAccessProxyApps) { @@ -105,10 +104,6 @@ class GnssVisibilityControl { runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps)); } - void masterLocationSettingsUpdated(boolean enabled) { - runOnHandler(() -> handleMasterLocationSettingsUpdated(enabled)); - } - void reportNfwNotification(String proxyAppPackageName, byte protocolStack, String otherProtocolStackName, byte requestor, String requestorId, byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { @@ -117,7 +112,19 @@ class GnssVisibilityControl { requestor, requestorId, responseType, inEmergencyMode, isCachedLocation))); } + private void handleInitialize() { + disableNfwLocationAccess(); // Disable until config properties are loaded. + listenForProxyAppsPackageUpdates(); + listenForDeviceLocationSettingsUpdate(); + mIsDeviceLocationSettingsEnabled = getDeviceLocationSettings(); + } + + private boolean getDeviceLocationSettings() { + return mContext.getSystemService(LocationManager.class).isLocationEnabled(); + } + private void listenForProxyAppsPackageUpdates() { + // Listen for proxy apps package installation, removal events. IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -143,11 +150,22 @@ class GnssVisibilityControl { }, UserHandle.ALL, intentFilter, null, mHandler); } + private void listenForDeviceLocationSettingsUpdate() { + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), + true, + new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + handleDeviceLocationSettingsUpdated(); + } + }, UserHandle.USER_ALL); + } + private void handleProxyAppPackageUpdate(String pkgName, String action) { final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName); - // pkgName is not one of the proxy apps in our list. if (locationPermission == null) { - return; + return; // ignore, pkgName is not one of the proxy apps in our list. } Log.i(TAG, "Proxy app " + pkgName + " package changed: " + action); @@ -197,15 +215,33 @@ class GnssVisibilityControl { return true; } } - return false; } - private void handleMasterLocationSettingsUpdated(boolean enabled) { - mIsMasterLocationSettingsEnabled = enabled; - Log.i(TAG, "Master location settings switch changed to " - + (enabled ? "enabled" : "disabled")); - updateNfwLocationAccessProxyAppsInGnssHal(); + private void handleDeviceLocationSettingsUpdated() { + final boolean enabled = getDeviceLocationSettings(); + Log.i(TAG, "Device location settings enabled: " + enabled); + + if (mIsDeviceLocationSettingsEnabled == enabled) { + return; + } + + mIsDeviceLocationSettingsEnabled = enabled; + if (!mIsDeviceLocationSettingsEnabled) { + disableNfwLocationAccess(); + return; + } + + // When device location settings was disabled, we already set the proxy app list + // to empty in GNSS HAL. Update only if the proxy app list is not empty. + String[] locationPermissionEnabledProxyApps = getLocationPermissionEnabledProxyApps(); + if (locationPermissionEnabledProxyApps.length != 0) { + setNfwLocationAccessProxyAppsInGnssHal(locationPermissionEnabledProxyApps); + } + } + + private void disableNfwLocationAccess() { + setNfwLocationAccessProxyAppsInGnssHal(NO_LOCATION_ENABLED_PROXY_APPS); } // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal @@ -316,8 +352,7 @@ class GnssVisibilityControl { return mPackageManager.getApplicationInfo(pkgName, 0).uid; } catch (PackageManager.NameNotFoundException e) { if (DEBUG) { - Log.d(TAG, "Non-framework location access proxy app " - + pkgName + " is not found."); + Log.d(TAG, "Non-framework location access proxy app " + pkgName + " is not found."); } return null; } @@ -329,8 +364,14 @@ class GnssVisibilityControl { } private void updateNfwLocationAccessProxyAppsInGnssHal() { - final String[] locationPermissionEnabledProxyApps = shouldDisableNfwLocationAccess() - ? NO_LOCATION_ENABLED_PROXY_APPS : getLocationPermissionEnabledProxyApps(); + if (!mIsDeviceLocationSettingsEnabled) { + return; // Keep non-framework location access disabled. + } + setNfwLocationAccessProxyAppsInGnssHal(getLocationPermissionEnabledProxyApps()); + } + + private void setNfwLocationAccessProxyAppsInGnssHal( + String[] locationPermissionEnabledProxyApps) { final String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps); Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: " + proxyAppsStr); @@ -341,12 +382,8 @@ class GnssVisibilityControl { } } - private boolean shouldDisableNfwLocationAccess() { - return !mIsMasterLocationSettingsEnabled; - } - private String[] getLocationPermissionEnabledProxyApps() { - // Get a count of proxy apps with location permission enabled to array creation size. + // Get a count of proxy apps with location permission enabled for array creation size. int countLocationPermissionEnabledProxyApps = 0; for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) { if (hasLocationPermissionEnabled) { diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index e479a1539e25..d0c59c1b002e 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -320,6 +320,11 @@ public final class OverlayManagerService extends SystemService { private final class PackageReceiver extends BroadcastReceiver { @Override public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { + final String action = intent.getAction(); + if (action == null) { + Slog.e(TAG, "Cannot handle package broadcast with null action"); + return; + } final Uri data = intent.getData(); if (data == null) { Slog.e(TAG, "Cannot handle package broadcast with null data"); @@ -337,7 +342,7 @@ public final class OverlayManagerService extends SystemService { userIds = new int[] { UserHandle.getUserId(extraUid) }; } - switch (intent.getAction()) { + switch (action) { case ACTION_PACKAGE_ADDED: if (replacing) { onPackageUpgraded(packageName, userIds); diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 33b8641c145e..640b155e69d5 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -19,6 +19,9 @@ per-file BackgroundDexOptService.java = ngeoffray@google.com per-file CompilerStats.java = agampe@google.com per-file CompilerStats.java = calin@google.com per-file CompilerStats.java = ngeoffray@google.com +per-file DynamicCodeLoggingService.java = agampe@google.com +per-file DynamicCodeLoggingService.java = calin@google.com +per-file DynamicCodeLoggingService.java = ngeoffray@google.com per-file InstructionSets.java = agampe@google.com per-file InstructionSets.java = calin@google.com per-file InstructionSets.java = ngeoffray@google.com diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 86083494f3d6..f5d88e3cf56f 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -84,7 +84,7 @@ import com.android.internal.util.ImageUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.IoThread; import com.android.server.LocalServices; -import com.android.server.pm.permission.PermissionManagerInternal; +import com.android.server.pm.permission.PermissionManagerServiceInternal; import libcore.io.IoUtils; @@ -131,7 +131,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private final Context mContext; private final PackageManagerService mPm; private final StagingManager mStagingManager; - private final PermissionManagerInternal mPermissionManager; + private final PermissionManagerServiceInternal mPermissionManager; private AppOpsManager mAppOps; @@ -189,7 +189,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) { mContext = context; mPm = pm; - mPermissionManager = LocalServices.getService(PermissionManagerInternal.class); + mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class); mInstallThread = new HandlerThread(TAG); mInstallThread.start(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 61a1a2f81101..b1c186e9e9f8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -238,7 +238,6 @@ import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; -import android.permission.PermissionControllerManager; import android.provider.DeviceConfig; import android.provider.MediaStore; import android.provider.Settings.Global; @@ -291,7 +290,6 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; -import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; @@ -315,9 +313,9 @@ import com.android.server.pm.dex.ViewCompiler; import com.android.server.pm.permission.BasePermission; import com.android.server.pm.permission.DefaultPermissionGrantPolicy; import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback; -import com.android.server.pm.permission.PermissionManagerInternal; -import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback; import com.android.server.pm.permission.PermissionManagerService; +import com.android.server.pm.permission.PermissionManagerServiceInternal; +import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState; import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; @@ -371,7 +369,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; @@ -445,8 +442,6 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean ENABLE_FREE_CACHE_V2 = SystemProperties.getBoolean("fw.free_cache_v2", true); - private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60); - private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts"; private static final int RADIO_UID = Process.PHONE_UID; @@ -940,7 +935,7 @@ public class PackageManagerService extends IPackageManager.Stub // TODO remove this and go through mPermissonManager directly final DefaultPermissionGrantPolicy mDefaultPermissionPolicy; - private final PermissionManagerInternal mPermissionManager; + private final PermissionManagerServiceInternal mPermissionManager; private final ComponentResolver mComponentResolver; // List of packages names to keep cached, even if they are uninstalled for all users @@ -1940,9 +1935,10 @@ public class PackageManagerService extends IPackageManager.Stub } } - // We may also need to apply pending (restored) runtime - // permission grants within these users. - mSettings.applyPendingPermissionGrantsLPw(packageName, userId); + // We may also need to apply pending (restored) runtime permission grants + // within these users. + mPermissionManager.restoreDelayedRuntimePermissions(packageName, + UserHandle.of(userId)); // Persistent preferred activity might have came into effect due to this // install. @@ -18825,7 +18821,7 @@ public class PackageManagerService extends IPackageManager.Stub // permission as requiring a review as this is the initial state. int flags = 0; if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) { - flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE; } if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) { if (hasInstallState) { @@ -19665,139 +19661,6 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public byte[] getPermissionGrantBackup(int userId) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("Only the system may call getPermissionGrantBackup()"); - } - - AtomicReference<byte[]> backup = new AtomicReference<>(); - mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup( - UserHandle.of(userId), mContext.getMainExecutor(), (b) -> { - synchronized (backup) { - backup.set(b); - backup.notifyAll(); - } - }); - - long start = System.currentTimeMillis(); - synchronized (backup) { - while (backup.get() == null) { - long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis(); - if (timeLeft <= 0) { - return null; - } - - try { - backup.wait(timeLeft); - } catch (InterruptedException ignored) { - return null; - } - } - } - - return backup.get(); - } - - @Override - public void restorePermissionGrants(byte[] backup, int userId) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("Only the system may call restorePermissionGrants()"); - } - - try { - final XmlPullParser parser = Xml.newPullParser(); - parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name()); - restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP, - (parser1, userId1) -> { - synchronized (mPackages) { - processRestoredPermissionGrantsLPr(parser1, userId1); - } - }); - } catch (Exception e) { - if (DEBUG_BACKUP) { - Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage()); - } - } - } - - @GuardedBy("mPackages") - private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId) - throws XmlPullParserException, IOException { - String pkgName = null; - int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - final String tagName = parser.getName(); - if (tagName.equals(TAG_GRANT)) { - pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); - if (DEBUG_BACKUP) { - Slog.v(TAG, "+++ Restoring grants for package " + pkgName); - } - } else if (tagName.equals(TAG_PERMISSION)) { - - final boolean isGranted = "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED)); - final String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME); - - int newFlagSet = 0; - if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) { - newFlagSet |= FLAG_PERMISSION_USER_SET; - } - if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) { - newFlagSet |= FLAG_PERMISSION_USER_FIXED; - } - if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) { - newFlagSet |= FLAG_PERMISSION_REVOKE_ON_UPGRADE; - } - if (DEBUG_BACKUP) { - Slog.v(TAG, " + Restoring grant:" - + " pkg=" + pkgName - + " perm=" + permName - + " granted=" + isGranted - + " bits=0x" + Integer.toHexString(newFlagSet)); - } - final PackageSetting ps = mSettings.mPackages.get(pkgName); - if (ps != null) { - // Already installed so we apply the grant immediately - if (DEBUG_BACKUP) { - Slog.v(TAG, " + already installed; applying"); - } - PermissionsState perms = ps.getPermissionsState(); - BasePermission bp = - (BasePermission) mPermissionManager.getPermissionTEMP(permName); - if (bp != null) { - if (isGranted) { - perms.grantRuntimePermission(bp, userId); - } - if (newFlagSet != 0) { - perms.updatePermissionFlags( - bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet); - } - } - } else { - // Need to wait for post-restore install to apply the grant - if (DEBUG_BACKUP) { - Slog.v(TAG, " - not yet installed; saving for later"); - } - mSettings.processRestoredPermissionGrantLPr(pkgName, permName, - isGranted, newFlagSet, userId); - } - } else { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Unknown element under <" + TAG_PERMISSION_BACKUP + ">: " + tagName); - XmlUtils.skipCurrentTag(parser); - } - } - - scheduleWriteSettingsLocked(); - mSettings.writeRuntimePermissionsForUserLPr(userId, false); - } - - @Override public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage, int sourceUserId, int targetUserId, int flags) { mContext.enforceCallingOrSelfPermission( @@ -21285,10 +21148,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) { - mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState); - } - if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) { // XXX should handle packageName != null by dumping only install data that // the given package is involved with. diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 975ffb25a784..92fe377e9495 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -19,10 +19,6 @@ package com.android.server.pm; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; -import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED; -import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; -import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; @@ -249,23 +245,6 @@ public final class Settings { private static final String ATTR_SDK_VERSION = "sdkVersion"; private static final String ATTR_DATABASE_VERSION = "databaseVersion"; - // Bookkeeping for restored permission grants - private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms"; - // package name: ATTR_PACKAGE_NAME - private static final String TAG_PERMISSION_ENTRY = "perm"; - // permission name: ATTR_NAME - // permission granted (boolean): ATTR_GRANTED - private static final String ATTR_USER_SET = "set"; - private static final String ATTR_USER_FIXED = "fixed"; - private static final String ATTR_REVOKE_ON_UPGRADE = "rou"; - private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr"; - - // Flag mask of restored permission grants that are applied at install time - private static final int USER_RUNTIME_GRANT_MASK = - FLAG_PERMISSION_USER_SET - | FLAG_PERMISSION_USER_FIXED - | FLAG_PERMISSION_REVOKE_ON_UPGRADE; - private final Object mLock; private final RuntimePermissionPersistence mRuntimePermissionsPersistence; @@ -303,26 +282,6 @@ public final class Settings { int[] excludedUserIds; } - // Bookkeeping for restored user permission grants - final class RestoredPermissionGrant { - String permissionName; - boolean granted; - int grantBits; - - RestoredPermissionGrant(String name, boolean isGranted, int theGrantBits) { - permissionName = name; - granted = isGranted; - grantBits = theGrantBits; - } - } - - // This would be more compact as a flat array of restored grants or something, but we - // may have quite a few, especially during early device lifetime, and avoiding all those - // linear lookups will be important. - private final SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>> - mRestoredUserGrants = - new SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>(); - private static int mFirstAvailableUid = 0; /** Map from volume UUID to {@link VersionInfo} */ @@ -461,43 +420,6 @@ public final class Settings { return mRenamedPackages.put(pkgName, origPkgName); } - void applyPendingPermissionGrantsLPw(String packageName, int userId) { - ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage = - mRestoredUserGrants.get(userId); - if (grantsByPackage == null || grantsByPackage.size() == 0) { - return; - } - - ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(packageName); - if (grants == null || grants.size() == 0) { - return; - } - - final PackageSetting ps = mPackages.get(packageName); - if (ps == null) { - Slog.e(TAG, "Can't find supposedly installed package " + packageName); - return; - } - final PermissionsState perms = ps.getPermissionsState(); - - for (RestoredPermissionGrant grant : grants) { - BasePermission bp = mPermissions.getPermission(grant.permissionName); - if (bp != null) { - if (grant.granted) { - perms.grantRuntimePermission(bp, userId); - } - perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, grant.grantBits); - } - } - - // And remove it from the pending-grant bookkeeping - grantsByPackage.remove(packageName); - if (grantsByPackage.size() < 1) { - mRestoredUserGrants.remove(userId); - } - writeRuntimePermissionsForUserLPr(userId, false); - } - public boolean canPropagatePermissionToInstantApp(String permName) { return mPermissions.canPropagatePermissionToInstantApp(permName); } @@ -1982,13 +1904,6 @@ public final class Settings { } } - // Specifically for backup/restore - public void processRestoredPermissionGrantLPr(String pkgName, String permission, - boolean isGranted, int restoredFlagSet, int userId) { - mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr( - pkgName, permission, isGranted, restoredFlagSet, userId); - } - void writeDefaultAppsLPr(XmlSerializer serializer, int userId) throws IllegalArgumentException, IllegalStateException, IOException { serializer.startTag(null, TAG_DEFAULT_APPS); @@ -5014,51 +4929,6 @@ public final class Settings { pw.print(mReadMessages.toString()); } - void dumpRestoredPermissionGrantsLPr(PrintWriter pw, DumpState dumpState) { - if (mRestoredUserGrants.size() > 0) { - pw.println(); - pw.println("Restored (pending) permission grants:"); - for (int userIndex = 0; userIndex < mRestoredUserGrants.size(); userIndex++) { - ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage = - mRestoredUserGrants.valueAt(userIndex); - if (grantsByPackage != null && grantsByPackage.size() > 0) { - final int userId = mRestoredUserGrants.keyAt(userIndex); - pw.print(" User "); pw.println(userId); - - for (int pkgIndex = 0; pkgIndex < grantsByPackage.size(); pkgIndex++) { - ArraySet<RestoredPermissionGrant> grants = grantsByPackage.valueAt(pkgIndex); - if (grants != null && grants.size() > 0) { - final String pkgName = grantsByPackage.keyAt(pkgIndex); - pw.print(" "); pw.print(pkgName); pw.println(" :"); - - for (RestoredPermissionGrant g : grants) { - pw.print(" "); - pw.print(g.permissionName); - if (g.granted) { - pw.print(" GRANTED"); - } - if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) { - pw.print(" user_set"); - } - if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) { - pw.print(" user_fixed"); - } - if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) { - pw.print(" revoke_on_upgrade"); - } - if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) { - pw.print(" revoke_when_requested"); - } - pw.println(); - } - } - } - } - } - pw.println(); - } - } - private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) { if (pkg == null) { pw.print("unknown"); @@ -5328,55 +5198,6 @@ public final class Settings { serializer.endTag(null, TAG_RUNTIME_PERMISSIONS); - // Now any restored permission grants that are waiting for the apps - // in question to be installed. These are stored as per-package - // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some - // number of individual permission grant entities. - if (mRestoredUserGrants.get(userId) != null) { - ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants = - mRestoredUserGrants.get(userId); - if (restoredGrants != null) { - final int pkgCount = restoredGrants.size(); - for (int i = 0; i < pkgCount; i++) { - final ArraySet<RestoredPermissionGrant> pkgGrants = - restoredGrants.valueAt(i); - if (pkgGrants != null && pkgGrants.size() > 0) { - final String pkgName = restoredGrants.keyAt(i); - serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS); - serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName); - - final int N = pkgGrants.size(); - for (int z = 0; z < N; z++) { - RestoredPermissionGrant g = pkgGrants.valueAt(z); - serializer.startTag(null, TAG_PERMISSION_ENTRY); - serializer.attribute(null, ATTR_NAME, g.permissionName); - - if (g.granted) { - serializer.attribute(null, ATTR_GRANTED, "true"); - } - - if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) { - serializer.attribute(null, ATTR_USER_SET, "true"); - } - if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) { - serializer.attribute(null, ATTR_USER_FIXED, "true"); - } - if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) { - serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true"); - } - if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) - != 0) { - serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED, - "true"); - } - serializer.endTag(null, TAG_PERMISSION_ENTRY); - } - serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS); - } - } - } - } - serializer.endDocument(); destination.finishWrite(out); @@ -5455,29 +5276,6 @@ public final class Settings { } } - // Backup/restore support - - public void rememberRestoredUserGrantLPr(String pkgName, String permission, - boolean isGranted, int restoredFlagSet, int userId) { - // This change will be remembered at write-settings time - ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage = - mRestoredUserGrants.get(userId); - if (grantsByPackage == null) { - grantsByPackage = new ArrayMap<String, ArraySet<RestoredPermissionGrant>>(); - mRestoredUserGrants.put(userId, grantsByPackage); - } - - ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(pkgName); - if (grants == null) { - grants = new ArraySet<RestoredPermissionGrant>(); - grantsByPackage.put(pkgName, grants); - } - - RestoredPermissionGrant grant = new RestoredPermissionGrant(permission, - isGranted, restoredFlagSet); - grants.add(grant); - } - // Private internals @GuardedBy("Settings.this.mLock") @@ -5520,50 +5318,6 @@ public final class Settings { } parsePermissionsLPr(parser, sus.getPermissionsState(), userId); } break; - - case TAG_RESTORED_RUNTIME_PERMISSIONS: { - final String pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); - parseRestoredRuntimePermissionsLPr(parser, pkgName, userId); - } break; - } - } - } - - private void parseRestoredRuntimePermissionsLPr(XmlPullParser parser, - final String pkgName, final int userId) throws IOException, XmlPullParserException { - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - - switch (parser.getName()) { - case TAG_PERMISSION_ENTRY: { - final String permName = parser.getAttributeValue(null, ATTR_NAME); - final boolean isGranted = "true".equals( - parser.getAttributeValue(null, ATTR_GRANTED)); - - int permBits = 0; - if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) { - permBits |= FLAG_PERMISSION_USER_SET; - } - if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) { - permBits |= FLAG_PERMISSION_USER_FIXED; - } - if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) { - permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE; - } - if ("true".equals(parser.getAttributeValue(null, - ATTR_REVOKE_WHEN_REQUESTED))) { - permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED; - } - - if (isGranted || permBits != 0) { - rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId); - } - } break; } } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 38940d6241a6..f56b98464cc3 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -30,6 +30,7 @@ import static android.app.AppOpsManager.permissionToOpCode; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED; import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; @@ -43,6 +44,9 @@ import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS; import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE; + +import static java.util.concurrent.TimeUnit.SECONDS; import android.Manifest; import android.annotation.NonNull; @@ -69,7 +73,9 @@ import android.os.UserManager; import android.os.UserManagerInternal; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; +import android.permission.PermissionControllerManager; import android.permission.PermissionManager; +import android.permission.PermissionManagerInternal; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -77,6 +83,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; @@ -91,9 +98,8 @@ import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.PackageSetting; import com.android.server.pm.SharedUserSetting; import com.android.server.pm.UserManagerService; -import com.android.server.pm.permission.DefaultPermissionGrantPolicy - .DefaultPermissionGrantedCallback; -import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback; +import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback; +import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState.PermissionState; import libcore.util.EmptyArray; @@ -106,6 +112,10 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Manages all permissions and handles permissions related tasks. @@ -122,6 +132,8 @@ public class PermissionManagerService { /** Permission grant: grant as runtime a permission that was granted as an install time one. */ private static final int GRANT_UPGRADE = 4; + private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60); + /** Cap the size of permission trees that 3rd party apps can define; in characters of text */ private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; /** Empty array to avoid allocations */ @@ -146,6 +158,9 @@ public class PermissionManagerService { /** Internal connection to the user manager */ private final UserManagerInternal mUserManagerInt; + /** Permission controller: User space permission management */ + private PermissionControllerManager mPermissionControllerManager; + /** Default permission policy to provide proper behaviour out-of-the-box */ private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy; @@ -180,6 +195,16 @@ public class PermissionManagerService { @GuardedBy("mLock") private ArrayMap<String, List<String>> mBackgroundPermissions; + /** + * A permission backup might contain apps that are not installed. In this case we delay the + * restoration until the app is installed. + * + * <p>This array ({@code userId -> noDelayedBackupLeft}) is {@code true} for all the users where + * there is <u>no more</u> delayed backup left. + */ + @GuardedBy("mLock") + private final SparseBooleanArray mHasNoDelayedPermBackup = new SparseBooleanArray(); + PermissionManagerService(Context context, @Nullable DefaultPermissionGrantedCallback defaultGrantCallback, @NonNull Object externalLock) { @@ -218,29 +243,31 @@ public class PermissionManagerService { } } - LocalServices.addService( - PermissionManagerInternal.class, new PermissionManagerInternalImpl()); + PermissionManagerServiceInternalImpl localService = + new PermissionManagerServiceInternalImpl(); + LocalServices.addService(PermissionManagerServiceInternal.class, localService); + LocalServices.addService(PermissionManagerInternal.class, localService); } /** * Creates and returns an initialized, internal service for use by other components. * <p> * The object returned is identical to the one returned by the LocalServices class using: - * {@code LocalServices.getService(PermissionManagerInternal.class);} + * {@code LocalServices.getService(PermissionManagerServiceInternal.class);} * <p> * NOTE: The external lock is temporary and should be removed. This needs to be a * lock created by the permission manager itself. */ - public static PermissionManagerInternal create(Context context, + public static PermissionManagerServiceInternal create(Context context, @Nullable DefaultPermissionGrantedCallback defaultGrantCallback, @NonNull Object externalLock) { - final PermissionManagerInternal permMgrInt = - LocalServices.getService(PermissionManagerInternal.class); + final PermissionManagerServiceInternal permMgrInt = + LocalServices.getService(PermissionManagerServiceInternal.class); if (permMgrInt != null) { return permMgrInt; } new PermissionManagerService(context, defaultGrantCallback, externalLock); - return LocalServices.getService(PermissionManagerInternal.class); + return LocalServices.getService(PermissionManagerServiceInternal.class); } @Nullable BasePermission getPermission(String permName) { @@ -332,6 +359,74 @@ public class PermissionManagerService { } /** + * Get the state of the runtime permissions as xml file. + * + * <p>Can not be called on main thread. + * + * @param user The user the data should be extracted for + * + * @return The state as a xml file + */ + private @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) { + CompletableFuture<byte[]> backup = new CompletableFuture<>(); + mPermissionControllerManager.getRuntimePermissionBackup(user, mContext.getMainExecutor(), + backup::complete); + + try { + return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + Slog.e(TAG, "Cannot create permission backup for " + user, e); + return null; + } + } + + /** + * Restore a permission state previously backed up via {@link #backupRuntimePermissions}. + * + * <p>If not all state can be restored, the un-appliable state will be delayed and can be + * applied via {@link #restoreDelayedRuntimePermissions}. + * + * @param backup The state as an xml file + * @param user The user the data should be restored for + */ + private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) { + synchronized (mLock) { + mHasNoDelayedPermBackup.delete(user.getIdentifier()); + mPermissionControllerManager.restoreRuntimePermissionBackup(backup, user); + } + } + + /** + * Try to apply permission backup that was previously not applied. + * + * <p>Can not be called on main thread. + * + * @param packageName The package that is newly installed + * @param user The user the package is installed for + * + * @see #restoreRuntimePermissions + */ + private void restoreDelayedRuntimePermissions(@NonNull String packageName, + @NonNull UserHandle user) { + synchronized (mLock) { + if (mHasNoDelayedPermBackup.get(user.getIdentifier(), false)) { + return; + } + + mPermissionControllerManager.restoreDelayedRuntimePermissionBackup(packageName, user, + mContext.getMainExecutor(), (hasMoreBackup) -> { + if (hasMoreBackup) { + return; + } + + synchronized (mLock) { + mHasNoDelayedPermBackup.put(user.getIdentifier(), true); + } + }); + } + } + + /** * Returns {@code true} if the permission can be implied from another granted permission. * <p>Some permissions, such as ACCESS_FINE_LOCATION, imply other permissions, * such as ACCESS_COURSE_LOCATION. If the caller holds an umbrella permission, give @@ -741,7 +836,6 @@ public class PermissionManagerService { if (ps == null) { return; } - final boolean isLegacySystemApp = mPackageManagerInt.isLegacySystemApp(pkg); final PermissionsState permissionsState = ps.getPermissionsState(); PermissionsState origPermissions = permissionsState; @@ -828,17 +922,9 @@ public class PermissionManagerService { // For all apps normal permissions are install time ones. grant = GRANT_INSTALL; } else if (bp.isRuntime()) { - // If a permission review is required for legacy apps we represent - // their permissions as always granted runtime ones since we need - // to keep the review required permission flag per user while an - // install permission's state is shared across all users. if (origPermissions.hasInstallPermission(bp.getName())) { - // For legacy apps that became modern, install becomes runtime. - grant = GRANT_UPGRADE; - } else if (isLegacySystemApp) { - // For legacy system apps, install becomes runtime. - // We cannot check hasInstallPermission() for system apps since those - // permissions were granted implicitly and not persisted pre-M. + // Before Q we represented some runtime permissions as install permissions, + // in Q we cannot do this anymore. Hence upgrade them all. grant = GRANT_UPGRADE; } else { // For modern apps keep runtime permissions unchanged. @@ -891,110 +977,111 @@ public class PermissionManagerService { } // Grant an install permission. if (permissionsState.grantInstallPermission(bp) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { + PERMISSION_OPERATION_FAILURE) { changedInstallPermission = true; } } break; case GRANT_RUNTIME: { - // Grant previously granted runtime permissions. - for (int userId : UserManagerService.getInstance().getUserIds()) { - final PermissionState permissionState = origPermissions + for (int userId : currentUserIds) { + PermissionState permState = origPermissions .getRuntimePermissionState(perm, userId); - int flags = permissionState != null - ? permissionState.getFlags() : 0; - if (origPermissions.hasRuntimePermission(perm, userId)) { - // Don't propagate the permission in a permission review - // mode if the former was revoked, i.e. marked to not - // propagate on upgrade. Note that in a permission review - // mode install permissions are represented as constantly - // granted runtime ones since we need to keep a per user - // state associated with the permission. Also the revoke - // on upgrade flag is no longer applicable and is reset. - final boolean revokeOnUpgrade = (flags & PackageManager - .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; - if (revokeOnUpgrade) { - flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - // Since we changed the flags, we have to write. - updatedUserIds = ArrayUtils.appendInt( - updatedUserIds, userId); - } - if (!revokeOnUpgrade) { - if (permissionsState.grantRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // If we cannot put the permission as it was, - // we have to write. - updatedUserIds = ArrayUtils.appendInt( - updatedUserIds, userId); - } + int flags = permState != null ? permState.getFlags() : 0; + + boolean wasChanged = false; + + if (appSupportsRuntimePermissions) { + // Remove review flag as it is not necessary anymore + if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { + flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED; + wasChanged = true; } - // If the app supports runtime permissions no need for a review. - if (appSupportsRuntimePermissions - && (flags & PackageManager - .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; - // Since we changed the flags, we have to write. - updatedUserIds = ArrayUtils.appendInt( - updatedUserIds, userId); + if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) { + flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE; + wasChanged = true; + } else { + if (permState != null && permState.isGranted()) { + if (permissionsState.grantRuntimePermission(bp, userId) + == PERMISSION_OPERATION_FAILURE) { + wasChanged = true; + } + } } - } else if (!appSupportsRuntimePermissions) { - // For legacy apps that need a permission review, every new - // runtime permission is granted but it is pending a review. - // We also need to review only platform defined runtime - // permissions as these are the only ones the platform knows - // how to disable the API to simulate revocation as legacy - // apps don't expect to run with revoked permissions. - if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) { - if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0 - && !bp.isRemoved()) { - flags |= FLAG_PERMISSION_REVIEW_REQUIRED; - // We changed the flags, hence have to write. - updatedUserIds = ArrayUtils.appendInt( - updatedUserIds, userId); + } else { + if (permState == null) { + // New permission + if (PLATFORM_PACKAGE_NAME.equals( + bp.getSourcePackageName())) { + if (!bp.isRemoved()) { + flags |= FLAG_PERMISSION_REVIEW_REQUIRED + | FLAG_PERMISSION_REVOKE_ON_UPGRADE; + wasChanged = true; + } } } + if (permissionsState.grantRuntimePermission(bp, userId) - != PermissionsState.PERMISSION_OPERATION_FAILURE) { - // We changed the permission, hence have to write. - updatedUserIds = ArrayUtils.appendInt( - updatedUserIds, userId); + != PERMISSION_OPERATION_FAILURE) { + wasChanged = true; } } - // Propagate the permission flags. + + if (wasChanged) { + updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); + } + permissionsState.updatePermissionFlags(bp, userId, flags, flags); } } break; case GRANT_UPGRADE: { - // Grant runtime permissions for a previously held install permission. - final PermissionState permissionState = origPermissions + // Upgrade from Pre-Q to Q permission model. Make all permissions + // runtime + PermissionState permState = origPermissions .getInstallPermissionState(perm); - final int flags = - (permissionState != null) ? permissionState.getFlags() : 0; + int flags = (permState != null) ? permState.getFlags() : 0; + // Remove install permission if (origPermissions.revokeInstallPermission(bp) - != PermissionsState.PERMISSION_OPERATION_FAILURE) { - // We will be transferring the permission flags, so clear them. + != PERMISSION_OPERATION_FAILURE) { origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL, PackageManager.MASK_PERMISSION_FLAGS, 0); changedInstallPermission = true; } - // If the permission is not to be promoted to runtime we ignore it and - // also its other flags as they are not applicable to install permissions. - if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) { - for (int userId : currentUserIds) { + for (int userId : currentUserIds) { + boolean wasChanged = false; + + if (appSupportsRuntimePermissions) { + // Remove review flag as it is not necessary anymore + if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { + flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED; + wasChanged = true; + } + + if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) { + flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE; + wasChanged = true; + } else { + if (permissionsState.grantRuntimePermission(bp, userId) != + PERMISSION_OPERATION_FAILURE) { + wasChanged = true; + } + } + } else { if (permissionsState.grantRuntimePermission(bp, userId) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // Transfer the permission flags. - permissionsState.updatePermissionFlags(bp, userId, - flags, flags); - // If we granted the permission, we have to write. - updatedUserIds = ArrayUtils.appendInt( - updatedUserIds, userId); + PERMISSION_OPERATION_FAILURE) { + flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + wasChanged = true; } } + + if (wasChanged) { + updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); + } + + permissionsState.updatePermissionFlags(bp, userId, flags, flags); } } break; @@ -1011,7 +1098,7 @@ public class PermissionManagerService { } } else { if (permissionsState.revokeInstallPermission(bp) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { + PERMISSION_OPERATION_FAILURE) { // Also drop the permission flags. permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, PackageManager.MASK_PERMISSION_FLAGS, 0); @@ -1094,6 +1181,10 @@ public class PermissionManagerService { @NonNull int[] updatedUserIds) { AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + return updatedUserIds; + } + String pkgName = pkg.packageName; int[] users = UserManagerService.getInstance().getUserIds(); @@ -1119,26 +1210,14 @@ public class PermissionManagerService { if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED)) == 0) { - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - if (permissionToOpCode(permission) != OP_NONE) { - setAppOpMode(permission, pkg, userId, MODE_IGNORED); - - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Revoking app-op " - + permissionToOp(permission) + " for " + pkgName - + " as it is now requested"); - } - } - } else { - int revokeResult = ps.revokeRuntimePermission(bp, userId); - if (revokeResult - != PermissionsState.PERMISSION_OPERATION_FAILURE) { - - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Revoking runtime permission " + permission - + " for " + pkgName - + " as it is now requested"); - } + int revokeResult = ps.revokeRuntimePermission(bp, userId); + if (revokeResult + != PERMISSION_OPERATION_FAILURE) { + + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Revoking runtime permission " + permission + + " for " + pkgName + + " as it is now requested"); } } @@ -1925,7 +2004,7 @@ public class PermissionManagerService { // Development permissions must be handled specially, since they are not // normal runtime permissions. For now they apply to all users. if (permissionsState.grantInstallPermission(bp) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { + PERMISSION_OPERATION_FAILURE) { if (callback != null) { callback.onInstallPermissionGranted(); } @@ -1945,7 +2024,7 @@ public class PermissionManagerService { final int result = permissionsState.grantRuntimePermission(bp, userId); switch (result) { - case PermissionsState.PERMISSION_OPERATION_FAILURE: { + case PERMISSION_OPERATION_FAILURE: { return; } @@ -2045,7 +2124,7 @@ public class PermissionManagerService { // Development permissions must be handled specially, since they are not // normal runtime permissions. For now they apply to all users. if (permissionsState.revokeInstallPermission(bp) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { + PERMISSION_OPERATION_FAILURE) { if (callback != null) { callback.onInstallPermissionRevoked(); } @@ -2054,7 +2133,7 @@ public class PermissionManagerService { } if (permissionsState.revokeRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { + PERMISSION_OPERATION_FAILURE) { return; } @@ -2522,6 +2601,8 @@ public class PermissionManagerService { throw new IllegalStateException("Signature|privileged permissions not in " + "privapp-permissions whitelist: " + mPrivappPermissionsViolations); } + + mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class); } private static String getVolumeUuidForPackage(PackageParser.Package pkg) { @@ -2574,7 +2655,7 @@ public class PermissionManagerService { return mBackgroundPermissions; } - private class PermissionManagerInternalImpl extends PermissionManagerInternal { + private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal { @Override public void systemReady() { PermissionManagerService.this.systemReady(); @@ -2737,5 +2818,21 @@ public class PermissionManagerService { return mSettings.getPermissionLocked(permName); } } + + @Override + public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) { + return PermissionManagerService.this.backupRuntimePermissions(user); + } + + @Override + public void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) { + PermissionManagerService.this.restoreRuntimePermissions(backup, user); + } + + @Override + public void restoreDelayedRuntimePermissions(@NonNull String packageName, + @NonNull UserHandle user) { + PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, user); + } } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index f4979746bae3..1dd2408686c1 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,19 +18,22 @@ package com.android.server.pm.permission; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.PackageManager.PermissionInfoFlags; import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.PackageManager.PermissionInfoFlags; +import android.permission.PermissionManagerInternal; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** - * Internal interfaces to be used by other components within the system server. + * Internal interfaces services. + * + * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes. */ -public abstract class PermissionManagerInternal { +public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal { /** * Callbacks invoked when interesting actions have been taken on a permission. * <p> diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING index 0892b32a6b91..2280d3fd9134 100644 --- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING @@ -16,6 +16,9 @@ }, { "include-filter": "android.permission.cts.SplitPermissionTest" + }, + { + "include-filter": "android.permission.cts.PermissionFlagsTest" } ] }, diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java index fdcafa77a378..0c6b773396c8 100644 --- a/services/core/java/com/android/server/policy/DisplayFoldController.java +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -42,10 +42,12 @@ class DisplayFoldController { private final WindowManagerInternal mWindowManagerInternal; private final DisplayManagerInternal mDisplayManagerInternal; private final int mDisplayId; + private final Handler mHandler; /** The display area while device is folded. */ private final Rect mFoldedArea; - private final Handler mHandler; + /** The display area to override the original folded area. */ + private Rect mOverrideFoldedArea = new Rect(); private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo(); private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>(); @@ -70,14 +72,23 @@ class DisplayFoldController { return; } if (folded) { + Rect foldedArea; + if (!mOverrideFoldedArea.isEmpty()) { + foldedArea = mOverrideFoldedArea; + } else if (!mFoldedArea.isEmpty()) { + foldedArea = mFoldedArea; + } else { + return; + } + mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mNonOverrideDisplayInfo); - final int dx = (mNonOverrideDisplayInfo.logicalWidth - mFoldedArea.width()) / 2 - - mFoldedArea.left; - final int dy = (mNonOverrideDisplayInfo.logicalHeight - mFoldedArea.height()) / 2 - - mFoldedArea.top; + final int dx = (mNonOverrideDisplayInfo.logicalWidth - foldedArea.width()) / 2 + - foldedArea.left; + final int dy = (mNonOverrideDisplayInfo.logicalHeight - foldedArea.height()) / 2 + - foldedArea.top; - mWindowManagerInternal.setForcedDisplaySize(mDisplayId, mFoldedArea.width(), - mFoldedArea.height()); + mWindowManagerInternal.setForcedDisplaySize(mDisplayId, + foldedArea.width(), foldedArea.height()); mDisplayManagerInternal.setDisplayOffsets(mDisplayId, -dx, -dy); } else { mWindowManagerInternal.clearForcedDisplaySize(mDisplayId); @@ -114,6 +125,18 @@ class DisplayFoldController { mListeners.unregister(listener); } + void setOverrideFoldedArea(Rect area) { + mOverrideFoldedArea.set(area); + } + + Rect getFoldedArea() { + if (!mOverrideFoldedArea.isEmpty()) { + return mOverrideFoldedArea; + } else { + return mFoldedArea; + } + } + /** * Only used for the case that persist.debug.force_foldable is set. * This is using proximity sensor to simulate the fold state switch. @@ -125,7 +148,7 @@ class DisplayFoldController { return null; } - final DisplayFoldController result = create(displayId); + final DisplayFoldController result = create(context, displayId); sensorManager.registerListener(new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { @@ -141,13 +164,17 @@ class DisplayFoldController { return result; } - static DisplayFoldController create(int displayId) { + static DisplayFoldController create(Context context, int displayId) { final DisplayManagerInternal displayService = LocalServices.getService(DisplayManagerInternal.class); - final DisplayInfo displayInfo = new DisplayInfo(); - displayService.getNonOverrideDisplayInfo(displayId, displayInfo); - final Rect foldedArea = new Rect(0, displayInfo.logicalHeight / 2, - displayInfo.logicalWidth, displayInfo.logicalHeight); + final String configFoldedArea = context.getResources().getString( + com.android.internal.R.string.config_foldedArea); + final Rect foldedArea; + if (configFoldedArea == null || configFoldedArea.isEmpty()) { + foldedArea = new Rect(); + } else { + foldedArea = Rect.unflattenFromString(configFoldedArea); + } return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class), displayService, displayId, foldedArea, DisplayThread.getHandler()); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2e3e3e430839..c87a81db16e4 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -125,6 +125,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.PixelFormat; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.hdmi.HdmiAudioSystemClient; @@ -1858,7 +1859,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { readConfigurationDependentBehaviors(); if (mLidControlsDisplayFold) { - mDisplayFoldController = DisplayFoldController.create(DEFAULT_DISPLAY); + mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY); } else if (SystemProperties.getBoolean("persist.debug.force_foldable", false)) { mDisplayFoldController = DisplayFoldController.createWithProxSensor(context, DEFAULT_DISPLAY); @@ -3221,6 +3222,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public void setOverrideFoldedArea(Rect area) { + if (mDisplayFoldController != null) { + mDisplayFoldController.setOverrideFoldedArea(area); + } + } + + @Override + public Rect getFoldedArea() { + if (mDisplayFoldController != null) { + return mDisplayFoldController.getFoldedArea(); + } + return new Rect(); + } + + @Override public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { synchronized (mLock) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 870d61b2ab90..d7e4b6cff4d8 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -64,6 +64,7 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WindowConfiguration; import android.content.Context; @@ -1470,6 +1471,20 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { default void unregisterDisplayFoldListener(IDisplayFoldListener listener) {} /** + * Overrides the folded area. + * + * @param area the overriding folded area or an empty {@code Rect} to clear the override. + */ + default void setOverrideFoldedArea(@NonNull Rect area) {} + + /** + * Get the display folded area. + */ + default @NonNull Rect getFoldedArea() { + return new Rect(); + } + + /** * Updates the flag about whether AOD is showing. * * @return whether the value was changed. diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index d8531210cad8..c145a22de6cd 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -196,7 +196,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } performInitialGrantsIfNecessary(userId); } - }, UserHandle.SYSTEM, intentFilter, null /* broadcastPermission */, null /* handler */); + }, UserHandle.ALL, intentFilter, null, null); getContext().getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED), false, diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index f3393e2f29da..4815e5cd7b83 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -85,7 +85,9 @@ import android.os.SystemProperties; import android.os.Temperature; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.DiskInfo; import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; import android.telephony.ModemActivityInfo; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -1942,6 +1944,41 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + private void pullTimeZoneDataInfo(int tagId, + long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { + String tzDbVersion = "Unknown"; + try { + tzDbVersion = android.icu.util.TimeZone.getTZDataVersion(); + } catch (Exception e) { + Log.e(TAG, "Getting tzdb version failed: ", e); + } + + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeString(tzDbVersion); + pulledData.add(e); + } + + private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos, + List<StatsLogEventWrapper> pulledData) { + StorageManager storageManager = mContext.getSystemService(StorageManager.class); + if (storageManager != null) { + List<VolumeInfo> volumes = storageManager.getVolumes(); + for (VolumeInfo vol : volumes) { + final String envState = VolumeInfo.getEnvironmentForState(vol.getState()); + final DiskInfo diskInfo = vol.getDisk(); + if (diskInfo != null && diskInfo.isSd()) { + if (envState.equals(Environment.MEDIA_MOUNTED)) { + StatsLogEventWrapper e = + new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeInt(vol.getType() + 1); + e.writeLong(diskInfo.size); + pulledData.add(e); + } + } + } + } + } + /** * Pulls various data. */ @@ -2130,6 +2167,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullDangerousPermissionState(elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.TIME_ZONE_DATA_INFO: { + pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret); + break; + } + case StatsLog.SDCARD_INFO: { + pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java index 7a3f030f9dd7..f581bc0bca46 100644 --- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java +++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java @@ -44,7 +44,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.UserManagerService; import com.android.server.pm.permission.DefaultPermissionGrantPolicy; -import com.android.server.pm.permission.PermissionManagerInternal; +import com.android.server.pm.permission.PermissionManagerServiceInternal; /** * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup @@ -133,7 +133,7 @@ public class TelecomLoaderService extends SystemService { } private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() { - return LocalServices.getService(PermissionManagerInternal.class) + return LocalServices.getService(PermissionManagerServiceInternal.class) .getDefaultPermissionGrantPolicy(); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b0ef8a0d4209..071dde74f103 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2243,12 +2243,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub synchronized (mLock) { mInAmbientMode = inAmbientMode; final WallpaperData data = mWallpaperMap.get(mCurrentUserId); - final boolean hasConnection = data != null && data.connection != null; - final WallpaperInfo info = hasConnection ? data.connection.mInfo : null; - // The wallpaper info is null for image wallpaper, also use the engine in this case. - if (hasConnection && (info == null && isAodImageWallpaperEnabled() - || info != null && info.supportsAmbientMode())) { + if (data != null && data.connection != null && (data.connection.mInfo == null + || data.connection.mInfo.supportsAmbientMode())) { // TODO(multi-display) Extends this method with specific display. engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine; } else { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index c33a2c179ab7..d40948b305a2 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -830,12 +830,25 @@ class ActivityStarter { new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT, null); - final int flags = intent.getFlags(); Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS); - newIntent.setFlags(flags - | FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_MULTIPLE_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + + int flags = intent.getFlags(); + flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; + + /* + * Prevent reuse of review activity: Each app needs their own review activity. By + * default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities + * with the same launch parameters (extras are ignored). Hence to avoid possible + * reuse force a new activity via the MULTIPLE_TASK flag. + * + * Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used, + * hence no need to add the flag in this case. + */ + if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) { + flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK; + } + newIntent.setFlags(flags); + newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName); newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target)); if (resultRecord != null) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 168c9adb61be..7beee0e33355 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; @@ -3759,6 +3760,41 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.unregisterDisplayFoldListener(listener); } + /** + * Overrides the folded area. + * + * @param area the overriding folded area or an empty {@code Rect} to clear the override. + */ + void setOverrideFoldedArea(@NonNull Rect area) { + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); + } + + long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + mPolicy.setOverrideFoldedArea(area); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + /** + * Get the display folded area. + */ + @NonNull Rect getFoldedArea() { + long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + return mPolicy.getFoldedArea(); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + @Override public int getPreferredOptionsPanelGravity(int displayId) { synchronized (mGlobalLock) { @@ -4826,11 +4862,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForcedDisplaySize(int displayId, int width, int height) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); @@ -4848,11 +4882,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForcedDisplayScalingMode(int displayId, int mode) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); @@ -4917,11 +4949,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void clearForcedDisplaySize(int displayId) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); @@ -4962,11 +4992,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForcedDisplayDensityForUser(int displayId, int density, int userId) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), @@ -4987,11 +5015,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void clearForcedDisplayDensityForUser(int displayId, int userId) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), @@ -5056,11 +5082,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setOverscan(int displayId, int left, int top, int right, int bottom) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); try { @@ -5090,11 +5114,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void startWindowTrace(){ - try { - mWindowTracing.startTrace(null /* printwriter */); - } catch (IOException e) { - throw new RuntimeException(e); - } + mWindowTracing.startTrace(null /* printwriter */); } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 83e3c71cbee3..d13ee459c115 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -62,6 +62,8 @@ public class WindowManagerShellCommand extends ShellCommand { return runDisplaySize(pw); case "density": return runDisplayDensity(pw); + case "folded-area": + return runDisplayFoldedArea(pw); case "overscan": return runDisplayOverscan(pw); case "scaling": @@ -207,6 +209,40 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private void printFoldedArea(PrintWriter pw) { + final Rect foldedArea = mInternal.getFoldedArea(); + if (foldedArea.isEmpty()) { + pw.println("Folded area: none"); + } else { + pw.println("Folded area: " + foldedArea.left + "," + foldedArea.top + "," + + foldedArea.right + "," + foldedArea.bottom); + } + } + + private int runDisplayFoldedArea(PrintWriter pw) { + final String areaStr = getNextArg(); + final Rect rect = new Rect(); + if (areaStr == null) { + printFoldedArea(pw); + return 0; + } else if ("reset".equals(areaStr)) { + rect.setEmpty(); + } else { + final Pattern flattenedPattern = Pattern.compile( + "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)"); + final Matcher matcher = flattenedPattern.matcher(areaStr); + if (!matcher.matches()) { + getErrPrintWriter().println("Error: area should be LEFT,TOP,RIGHT,BOTTOM"); + return -1; + } + rect.set(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)), Integer.parseInt(matcher.group(4))); + } + + mInternal.setOverrideFoldedArea(rect); + return 0; + } + private int runDisplayOverscan(PrintWriter pw) throws RemoteException { String overscanStr = getNextArgRequired(); Rect rect = new Rect(); @@ -335,6 +371,8 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" width and height in pixels unless suffixed with 'dp'."); pw.println(" density [reset|DENSITY] [-d DISPLAY_ID]"); pw.println(" Return or override display density."); + pw.println(" folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]"); + pw.println(" Return or override folded area."); pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]"); pw.println(" Set overscan area for display."); pw.println(" scaling [off|auto] [-d DISPLAY_ID]"); diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java index e4461ea90c91..2ce6e6c1d049 100644 --- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java +++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java @@ -20,7 +20,6 @@ import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER; import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H; import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L; -import android.os.Trace; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; @@ -36,24 +35,30 @@ import java.util.Queue; /** * Buffer used for window tracing. */ -abstract class WindowTraceBuffer { +class WindowTraceBuffer { private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; - final Object mBufferLock = new Object(); - final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>(); - final File mTraceFile; - int mBufferSize; - private final int mBufferCapacity; + private final Object mBufferLock = new Object(); - WindowTraceBuffer(int size, File traceFile) throws IOException { - mBufferCapacity = size; - mTraceFile = traceFile; + private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>(); + private int mBufferUsedSize; + private int mBufferCapacity; - initTraceFile(); + WindowTraceBuffer(int bufferCapacity) { + mBufferCapacity = bufferCapacity; + resetBuffer(); } int getAvailableSpace() { - return mBufferCapacity - mBufferSize; + return mBufferCapacity - mBufferUsedSize; + } + + int size() { + return mBuffer.size(); + } + + void setCapacity(int capacity) { + mBufferCapacity = capacity; } /** @@ -70,42 +75,37 @@ abstract class WindowTraceBuffer { + mBufferCapacity + " Object size: " + protoLength); } synchronized (mBufferLock) { - boolean canAdd = canAdd(protoLength); - if (canAdd) { - mBuffer.add(proto); - mBufferSize += protoLength; - } + discardOldest(protoLength); + mBuffer.add(proto); + mBufferUsedSize += protoLength; mBufferLock.notify(); } } - /** - * Stops the buffer execution and flush all buffer content to the disk. - * - * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile} - */ - void dump() throws IOException, InterruptedException { - try { - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFile"); - writeTraceToFile(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); - } - } - - @VisibleForTesting boolean contains(byte[] other) { return mBuffer.stream() .anyMatch(p -> Arrays.equals(p.getBytes(), other)); } - private void initTraceFile() throws IOException { - mTraceFile.delete(); - try (OutputStream os = new FileOutputStream(mTraceFile)) { - mTraceFile.setReadable(true, false); - ProtoOutputStream proto = new ProtoOutputStream(os); - proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); - proto.flush(); + /** + * Writes the trace buffer to disk. + */ + void writeTraceToFile(File traceFile) throws IOException { + synchronized (mBufferLock) { + traceFile.delete(); + traceFile.setReadable(true, false); + try (OutputStream os = new FileOutputStream(traceFile)) { + ProtoOutputStream proto = new ProtoOutputStream(); + proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); + os.write(proto.getBytes()); + while (!mBuffer.isEmpty()) { + proto = mBuffer.poll(); + mBufferUsedSize -= proto.getRawSize(); + byte[] protoBytes = proto.getBytes(); + os.write(protoBytes); + } + os.flush(); + } } } @@ -114,59 +114,48 @@ abstract class WindowTraceBuffer { * smaller than the overall buffer size. * * @param protoLength byte array representation of the Proto object to add - * @return {@code true} if the element can be added to the buffer or not - */ - abstract boolean canAdd(int protoLength); - - /** - * Flush all buffer content to the disk. - * - * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile} */ - abstract void writeTraceToFile() throws IOException, InterruptedException; - - /** - * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceRingBuffer} for - * continuous mode or a {@link WindowTraceQueueBuffer} otherwise - */ - static class Builder { - private boolean mContinuous; - private File mTraceFile; - private int mBufferCapacity; - - Builder setContinuousMode(boolean continuous) { - mContinuous = continuous; - return this; - } + private void discardOldest(int protoLength) { + long availableSpace = getAvailableSpace(); - Builder setTraceFile(File traceFile) { - mTraceFile = traceFile; - return this; - } + while (availableSpace < protoLength) { - Builder setBufferCapacity(int size) { - mBufferCapacity = size; - return this; + ProtoOutputStream item = mBuffer.poll(); + if (item == null) { + throw new IllegalStateException("No element to discard from buffer"); + } + mBufferUsedSize -= item.getRawSize(); + availableSpace = getAvailableSpace(); } + } - File getFile() { - return mTraceFile; + /** + * Removes all elements form the buffer + */ + void resetBuffer() { + synchronized (mBufferLock) { + mBuffer.clear(); + mBufferUsedSize = 0; } + } - WindowTraceBuffer build() throws IOException { - if (mBufferCapacity <= 0) { - throw new IllegalStateException("Buffer capacity must be greater than 0."); - } - - if (mTraceFile == null) { - throw new IllegalArgumentException("A valid trace file must be specified."); - } + @VisibleForTesting + int getBufferSize() { + return mBufferUsedSize; + } - if (mContinuous) { - return new WindowTraceRingBuffer(mBufferCapacity, mTraceFile); - } else { - return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile); - } + String getStatus() { + synchronized (mBufferLock) { + return "Buffer size: " + + mBufferCapacity + + " bytes" + + "\n" + + "Buffer usage: " + + mBufferUsedSize + + " bytes" + + "\n" + + "Elements in the buffer: " + + mBuffer.size(); } } } diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java deleted file mode 100644 index 5888b7a799cf..000000000000 --- a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import static android.os.Build.IS_USER; - -import android.util.Log; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first - * {@code #size size} bytes of window trace elements. - * Once the buffer is full it will no longer accepts new elements. - */ -class WindowTraceQueueBuffer extends WindowTraceBuffer { - private static final String TAG = "WindowTracing"; - - private Thread mConsumerThread; - private boolean mCancel; - - @VisibleForTesting - WindowTraceQueueBuffer(int size, File traceFile, boolean startConsumerThread) - throws IOException { - super(size, traceFile); - if (startConsumerThread) { - initializeConsumerThread(); - } - } - - WindowTraceQueueBuffer(int size, File traceFile) throws IOException { - this(size, traceFile, !IS_USER); - } - - private void initializeConsumerThread() { - mCancel = false; - mConsumerThread = new Thread(() -> { - try { - loop(); - } catch (InterruptedException e) { - Log.i(TAG, "Interrupting trace consumer thread"); - } catch (IOException e) { - Log.e(TAG, "Failed to execute trace consumer thread", e); - } - }, "window_tracing"); - mConsumerThread.start(); - } - - private void loop() throws IOException, InterruptedException { - while (!mCancel) { - ProtoOutputStream proto; - synchronized (mBufferLock) { - mBufferLock.wait(); - proto = mBuffer.poll(); - if (proto != null) { - mBufferSize -= proto.getRawSize(); - } - } - if (proto != null) { - try (OutputStream os = new FileOutputStream(mTraceFile, true)) { - byte[] protoBytes = proto.getBytes(); - os.write(protoBytes); - } - } - } - } - - @Override - boolean canAdd(int protoLength) { - long availableSpace = getAvailableSpace(); - return availableSpace >= protoLength; - } - - @Override - void writeTraceToFile() throws InterruptedException { - synchronized (mBufferLock) { - mCancel = true; - mBufferLock.notify(); - } - if (mConsumerThread != null) { - mConsumerThread.join(); - mConsumerThread = null; - } - } -} diff --git a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java deleted file mode 100644 index 77d30be816bc..000000000000 --- a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import android.util.proto.ProtoOutputStream; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * A ring buffer to store the {@code #size size} bytes of window trace data. - * The buffer operates on a trace entry level, that is, if the new trace data is larger than the - * available buffer space, the buffer will discard as many full trace entries as necessary to fit - * the new trace. - */ -class WindowTraceRingBuffer extends WindowTraceBuffer { - WindowTraceRingBuffer(int size, File traceFile) throws IOException { - super(size, traceFile); - } - - @Override - boolean canAdd(int protoLength) { - long availableSpace = getAvailableSpace(); - - while (availableSpace < protoLength) { - discardOldest(); - availableSpace = getAvailableSpace(); - } - - return true; - } - - @Override - void writeTraceToFile() throws IOException { - synchronized (mBufferLock) { - try (OutputStream os = new FileOutputStream(mTraceFile, true)) { - while (!mBuffer.isEmpty()) { - ProtoOutputStream proto = mBuffer.poll(); - mBufferSize -= proto.getRawSize(); - byte[] protoBytes = proto.getBytes(); - os.write(protoBytes); - } - } - } - } - - private void discardOldest() { - ProtoOutputStream item = mBuffer.poll(); - if (item == null) { - throw new IllegalStateException("No element to discard from buffer"); - } - mBufferSize -= item.getRawSize(); - } -} diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index abc474d756b7..0ce215c88dad 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -31,8 +31,6 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; -import com.android.internal.annotations.VisibleForTesting; - import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -47,139 +45,191 @@ class WindowTracing { * Maximum buffer size, currently defined as 512 KB * Size was experimentally defined to fit between 100 to 150 elements. */ - private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024; + private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024; + private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024; + private static final int BUFFER_CAPACITY_ALL = 4096 * 1024; + private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb"; private static final String TAG = "WindowTracing"; private final WindowManagerService mService; private final Choreographer mChoreographer; private final WindowManagerGlobalLock mGlobalLock; - private final Object mLock = new Object(); - private final WindowTraceBuffer.Builder mBufferBuilder; - - private WindowTraceBuffer mTraceBuffer; + private final Object mEnabledLock = new Object(); + private final File mTraceFile; + private final WindowTraceBuffer mBuffer; + private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) -> + log("onFrame" /* where */); - private @WindowTraceLogLevel int mWindowTraceLogLevel = WindowTraceLogLevel.TRIM; - private boolean mContinuousMode; + private @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM; + private boolean mLogOnFrame = false; private boolean mEnabled; private volatile boolean mEnabledLockFree; private boolean mScheduled; - private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) -> - log("onFrame" /* where */); - private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) { - this(file, service, choreographer, service.mGlobalLock); + static WindowTracing createDefaultAndStartLooper(WindowManagerService service, + Choreographer choreographer) { + File file = new File(TRACE_FILENAME); + return new WindowTracing(file, service, choreographer, BUFFER_CAPACITY_TRIM); } - @VisibleForTesting - WindowTracing(File file, WindowManagerService service, Choreographer choreographer, - WindowManagerGlobalLock globalLock) { - mBufferBuilder = new WindowTraceBuffer.Builder() - .setTraceFile(file) - .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE); + private WindowTracing(File file, WindowManagerService service, Choreographer choreographer, + int bufferCapacity) { + this(file, service, choreographer, service.mGlobalLock, bufferCapacity); + } + WindowTracing(File file, WindowManagerService service, Choreographer choreographer, + WindowManagerGlobalLock globalLock, int bufferCapacity) { mChoreographer = choreographer; mService = service; mGlobalLock = globalLock; + mTraceFile = file; + mBuffer = new WindowTraceBuffer(bufferCapacity); + setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */); } - void startTrace(@Nullable PrintWriter pw) throws IOException { + void startTrace(@Nullable PrintWriter pw) { if (IS_USER) { logAndPrintln(pw, "Error: Tracing is not supported on user builds."); return; } - synchronized (mLock) { - logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + "."); - if (mTraceBuffer != null) { - writeTraceToFileLocked(); - } - mTraceBuffer = mBufferBuilder - .setContinuousMode(mContinuousMode) - .build(); + synchronized (mEnabledLock) { + logAndPrintln(pw, "Start tracing to " + mTraceFile + "."); + mBuffer.resetBuffer(); mEnabled = mEnabledLockFree = true; } } - private void logAndPrintln(@Nullable PrintWriter pw, String msg) { - Log.i(TAG, msg); - if (pw != null) { - pw.println(msg); - pw.flush(); - } - } - void stopTrace(@Nullable PrintWriter pw) { if (IS_USER) { logAndPrintln(pw, "Error: Tracing is not supported on user builds."); return; } - synchronized (mLock) { - logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile() - + ". Waiting for traces to flush."); + synchronized (mEnabledLock) { + logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush."); mEnabled = mEnabledLockFree = false; - synchronized (mLock) { - if (mEnabled) { - logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush."); - throw new IllegalStateException("tracing enabled while waiting for flush."); - } - writeTraceToFileLocked(); - mTraceBuffer = null; + if (mEnabled) { + logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush."); + throw new IllegalStateException("tracing enabled while waiting for flush."); } - logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + "."); + writeTraceToFileLocked(); + logAndPrintln(pw, "Trace written to " + mTraceFile + "."); } } - @VisibleForTesting - void setContinuousMode(boolean continuous, PrintWriter pw) { - logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous); + private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) { + logAndPrintln(pw, "Setting window tracing log level to " + logLevel); + mLogLevel = logLevel; - if (mEnabled) { - logAndPrintln(pw, "Trace is currently active, change will take effect once the " - + "trace is restarted."); + switch (logLevel) { + case WindowTraceLogLevel.ALL: { + setBufferCapacity(BUFFER_CAPACITY_ALL, pw); + break; + } + case WindowTraceLogLevel.TRIM: { + setBufferCapacity(BUFFER_CAPACITY_TRIM, pw); + break; + } + case WindowTraceLogLevel.CRITICAL: { + setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw); + break; + } } - mContinuousMode = continuous; - mWindowTraceLogLevel = (continuous) ? WindowTraceLogLevel.CRITICAL : - WindowTraceLogLevel.TRIM; } - boolean isEnabled() { - return mEnabledLockFree; + private void setLogFrequency(boolean onFrame, PrintWriter pw) { + logAndPrintln(pw, "Setting window tracing log frequency to " + + ((onFrame) ? "frame" : "transaction")); + mLogOnFrame = onFrame; } - static WindowTracing createDefaultAndStartLooper(WindowManagerService service, - Choreographer choreographer) { - File file = new File("/data/misc/wmtrace/wm_trace.pb"); - return new WindowTracing(file, service, choreographer); + private void setBufferCapacity(int capacity, PrintWriter pw) { + logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes"); + mBuffer.setCapacity(capacity); + } + + boolean isEnabled() { + return mEnabledLockFree; } int onShellCommand(ShellCommand shell) { PrintWriter pw = shell.getOutPrintWriter(); - try { - String cmd = shell.getNextArgRequired(); - switch (cmd) { - case "start": - startTrace(pw); - return 0; - case "stop": - stopTrace(pw); - return 0; - case "continuous": - setContinuousMode(Boolean.valueOf(shell.getNextArgRequired()), pw); - return 0; - default: - pw.println("Unknown command: " + cmd); - return -1; - } - } catch (IOException e) { - logAndPrintln(pw, e.toString()); - throw new RuntimeException(e); + String cmd = shell.getNextArgRequired(); + switch (cmd) { + case "start": + startTrace(pw); + return 0; + case "stop": + stopTrace(pw); + return 0; + case "status": + logAndPrintln(pw, getStatus()); + return 0; + case "frame": + setLogFrequency(true /* onFrame */, pw); + mBuffer.resetBuffer(); + return 0; + case "transaction": + setLogFrequency(false /* onFrame */, pw); + mBuffer.resetBuffer(); + return 0; + case "level": + String logLevelStr = shell.getNextArgRequired().toLowerCase(); + switch (logLevelStr) { + case "all": { + setLogLevel(WindowTraceLogLevel.ALL, pw); + break; + } + case "trim": { + setLogLevel(WindowTraceLogLevel.TRIM, pw); + break; + } + case "critical": { + setLogLevel(WindowTraceLogLevel.CRITICAL, pw); + break; + } + default: { + setLogLevel(WindowTraceLogLevel.TRIM, pw); + break; + } + } + mBuffer.resetBuffer(); + return 0; + case "size": + setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw); + mBuffer.resetBuffer(); + return 0; + default: + pw.println("Unknown command: " + cmd); + pw.println("Window manager trace options:"); + pw.println(" start: Start logging"); + pw.println(" stop: Stop logging"); + pw.println(" frame: Log trace once per frame"); + pw.println(" transaction: Log each transaction"); + pw.println(" size: Set the maximum log size (in KB)"); + pw.println(" level [lvl]: Set the log level between"); + pw.println(" lvl may be one of:"); + pw.println(" critical: Only visible windows with reduced information"); + pw.println(" trim: All windows with reduced"); + pw.println(" all: All window and information"); + return -1; } } + private String getStatus() { + return "Status: " + + ((isEnabled()) ? "Enabled" : "Disabled") + + "\n" + + "Log level: " + + mLogLevel + + "\n" + + mBuffer.getStatus(); + } + /** * If tracing is enabled, log the current state or schedule the next frame to be logged, - * according to {@link #mContinuousMode}. + * according to {@link #mLogOnFrame}. * * @param where Logging point descriptor */ @@ -188,7 +238,7 @@ class WindowTracing { return; } - if (mContinuousMode) { + if (mLogOnFrame) { schedule(); } else { log(where); @@ -215,25 +265,24 @@ class WindowTracing { private void log(String where) { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked"); try { - synchronized (mGlobalLock) { - ProtoOutputStream os = new ProtoOutputStream(); - long tokenOuter = os.start(ENTRY); - os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); - os.write(WHERE, where); + ProtoOutputStream os = new ProtoOutputStream(); + long tokenOuter = os.start(ENTRY); + os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); + os.write(WHERE, where); + long tokenInner = os.start(WINDOW_MANAGER_SERVICE); + synchronized (mGlobalLock) { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked"); try { - long tokenInner = os.start(WINDOW_MANAGER_SERVICE); - mService.writeToProtoLocked(os, mWindowTraceLogLevel); - os.end(tokenInner); + mService.writeToProtoLocked(os, mLogLevel); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } - os.end(tokenOuter); - mTraceBuffer.add(os); - - mScheduled = false; } + os.end(tokenInner); + os.end(tokenOuter); + mBuffer.add(os); + mScheduled = false; } catch (Exception e) { Log.wtf(TAG, "Exception while tracing state", e); } finally { @@ -242,31 +291,37 @@ class WindowTracing { } /** - * Writes the trace buffer to disk. This method has no internal synchronization and should be - * externally synchronized + * Writes the trace buffer to new file for the bugreport. + * + * This method is synchronized with {@code #startTrace(PrintWriter)} and + * {@link #stopTrace(PrintWriter)}. */ - private void writeTraceToFileLocked() { - if (mTraceBuffer == null) { - return; + void writeTraceToFile() { + synchronized (mEnabledLock) { + writeTraceToFileLocked(); } + } - try { - mTraceBuffer.dump(); - } catch (IOException e) { - Log.e(TAG, "Unable to write buffer to file", e); - } catch (InterruptedException e) { - Log.e(TAG, "Unable to interrupt window tracing file write thread", e); + private void logAndPrintln(@Nullable PrintWriter pw, String msg) { + Log.i(TAG, msg); + if (pw != null) { + pw.println(msg); + pw.flush(); } } /** - * Writes the trace buffer to disk and clones it into a new file for the bugreport. - * This method is synchronized with {@code #startTrace(PrintWriter)} and - * {@link #stopTrace(PrintWriter)}. + * Writes the trace buffer to disk. This method has no internal synchronization and should be + * externally synchronized */ - void writeTraceToFile() { - synchronized (mLock) { - writeTraceToFileLocked(); + private void writeTraceToFileLocked() { + try { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked"); + mBuffer.writeTraceToFile(mTraceFile); + } catch (IOException e) { + Log.e(TAG, "Unable to write buffer to file", e); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } -} +}
\ No newline at end of file diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a6017f2c1e86..aae159c2edcb 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -36,6 +36,7 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; +import android.net.NetworkStackClient; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -1350,9 +1351,7 @@ public final class SystemServer { traceBeginAndSlog("StartNetworkStack"); try { - final android.net.NetworkStack networkStack = - context.getSystemService(android.net.NetworkStack.class); - networkStack.start(context); + NetworkStackClient.getInstance().start(context); } catch (Throwable e) { reportWtf("starting Network Stack", e); } diff --git a/services/net/Android.bp b/services/net/Android.bp index 9946cc3db0e8..8ad4d7679107 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -3,6 +3,7 @@ java_library_static { srcs: ["java/**/*.java"], static_libs: [ "netd_aidl_interface-java", + "networkstack-aidl-interfaces-java", ] } diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java new file mode 100644 index 000000000000..1eb7b98d801a --- /dev/null +++ b/services/net/java/android/net/NetworkStackClient.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpServerCallbacks; +import android.net.ip.IIpClientCallbacks; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +/** + * Service used to communicate with the network stack, which is running in a separate module. + * @hide + */ +public class NetworkStackClient { + private static final String TAG = NetworkStackClient.class.getSimpleName(); + + private static final int NETWORKSTACK_TIMEOUT_MS = 10_000; + + private static NetworkStackClient sInstance; + + @NonNull + @GuardedBy("mPendingNetStackRequests") + private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>(); + @Nullable + @GuardedBy("mPendingNetStackRequests") + private INetworkStackConnector mConnector; + + private volatile boolean mNetworkStackStartRequested = false; + + private interface NetworkStackCallback { + void onNetworkStackConnected(INetworkStackConnector connector); + } + + private NetworkStackClient() { } + + /** + * Get the NetworkStackClient singleton instance. + */ + public static synchronized NetworkStackClient getInstance() { + if (sInstance == null) { + sInstance = new NetworkStackClient(); + } + return sInstance; + } + + /** + * Create a DHCP server according to the specified parameters. + * + * <p>The server will be returned asynchronously through the provided callbacks. + */ + public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params, + final IDhcpServerCallbacks cb) { + requestConnector(connector -> { + try { + connector.makeDhcpServer(ifName, params, cb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); + } + + /** + * Create an IpClient on the specified interface. + * + * <p>The IpClient will be returned asynchronously through the provided callbacks. + */ + public void makeIpClient(String ifName, IIpClientCallbacks cb) { + requestConnector(connector -> { + try { + connector.makeIpClient(ifName, cb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); + } + + /** + * Create a NetworkMonitor. + * + * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks. + */ + public void makeNetworkMonitor( + NetworkParcelable network, String name, INetworkMonitorCallbacks cb) { + requestConnector(connector -> { + try { + connector.makeNetworkMonitor(network, name, cb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); + } + + private class NetworkStackConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + registerNetworkStackService(service); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // TODO: crash/reboot the system ? + Slog.wtf(TAG, "Lost network stack connector"); + } + }; + + private void registerNetworkStackService(@NonNull IBinder service) { + final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service); + + ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */, + DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); + + final ArrayList<NetworkStackCallback> requests; + synchronized (mPendingNetStackRequests) { + requests = new ArrayList<>(mPendingNetStackRequests); + mPendingNetStackRequests.clear(); + mConnector = connector; + } + + for (NetworkStackCallback r : requests) { + r.onNetworkStackConnected(connector); + } + } + + /** + * Start the network stack. Should be called only once on device startup. + * + * <p>This method will start the network stack either in the network stack process, or inside + * the system server on devices that do not support the network stack module. The network stack + * connector will then be delivered asynchronously to clients that requested it before it was + * started. + */ + public void start(Context context) { + mNetworkStackStartRequested = true; + // Try to bind in-process if the library is available + IBinder connector = null; + try { + final Class service = Class.forName( + "com.android.server.NetworkStackService", + true /* initialize */, + context.getClassLoader()); + connector = (IBinder) service.getMethod("makeConnector", Context.class) + .invoke(null, context); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService"); + // TODO: crash/reboot system here ? + return; + } catch (ClassNotFoundException e) { + // Normal behavior if stack is provided by the app: fall through + } + + // In-process network stack. Add the service to the service manager here. + if (connector != null) { + registerNetworkStackService(connector); + return; + } + // Start the network stack process. The service will be added to the service manager in + // NetworkStackConnection.onServiceConnected(). + final Intent intent = new Intent(INetworkStackConnector.class.getName()); + final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); + intent.setComponent(comp); + + if (comp == null) { + Slog.wtf(TAG, "Could not resolve the network stack with " + intent); + // TODO: crash/reboot system server ? + return; + } + final PackageManager pm = context.getPackageManager(); + int uid = -1; + try { + uid = pm.getPackageUid(comp.getPackageName(), UserHandle.USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + Slog.wtf("Network stack package not found", e); + // Fall through + } + if (uid != Process.NETWORK_STACK_UID) { + throw new SecurityException("Invalid network stack UID: " + uid); + } + + final int hasPermission = + pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName()); + if (hasPermission != PERMISSION_GRANTED) { + throw new SecurityException( + "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK); + } + + if (!context.bindServiceAsUser(intent, new NetworkStackConnection(), + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) { + Slog.wtf(TAG, + "Could not bind to network stack in-process, or in app with " + intent); + // TODO: crash/reboot system server if no network stack after a timeout ? + } + } + + /** + * For non-system server clients, get the connector registered by the system server. + */ + private INetworkStackConnector getRemoteConnector() { + // Block until the NetworkStack connector is registered in ServiceManager. + // <p>This is only useful for non-system processes that do not have a way to be notified of + // registration completion. Adding a callback system would be too heavy weight considering + // that the connector is registered on boot, so it is unlikely that a client would request + // it before it is registered. + // TODO: consider blocking boot on registration and simplify much of the logic in this class + IBinder connector; + try { + final long before = System.currentTimeMillis(); + while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) { + Thread.sleep(20); + if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { + Slog.e(TAG, "Timeout waiting for NetworkStack connector"); + return null; + } + } + } catch (InterruptedException e) { + Slog.e(TAG, "Error waiting for NetworkStack connector", e); + return null; + } + + return INetworkStackConnector.Stub.asInterface(connector); + } + + private void requestConnector(@NonNull NetworkStackCallback request) { + // TODO: PID check. + final int caller = Binder.getCallingUid(); + if (caller != Process.SYSTEM_UID && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)) { + // Don't even attempt to obtain the connector and give a nice error message + throw new SecurityException( + "Only the system server should try to bind to the network stack."); + } + + if (!mNetworkStackStartRequested) { + // The network stack is not being started in this process, e.g. this process is not + // the system server. Get a remote connector registered by the system server. + final INetworkStackConnector connector = getRemoteConnector(); + synchronized (mPendingNetStackRequests) { + mConnector = connector; + } + request.onNetworkStackConnected(connector); + return; + } + + final INetworkStackConnector connector; + synchronized (mPendingNetStackRequests) { + connector = mConnector; + if (connector == null) { + mPendingNetStackRequests.add(request); + return; + } + } + + request.onNetworkStackConnected(connector); + } +} diff --git a/core/java/android/net/dhcp/DhcpServerCallbacks.java b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java index bb56876c77f5..bb56876c77f5 100644 --- a/core/java/android/net/dhcp/DhcpServerCallbacks.java +++ b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java diff --git a/core/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java index db01ae4d4d9c..db01ae4d4d9c 100644 --- a/core/java/android/net/ip/IpClientCallbacks.java +++ b/services/net/java/android/net/ip/IpClientCallbacks.java diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java index 2a2a67a92a86..bf917bf88b2d 100644 --- a/services/net/java/android/net/ip/IpClientUtil.java +++ b/services/net/java/android/net/ip/IpClientUtil.java @@ -23,8 +23,7 @@ import android.content.Context; import android.net.DhcpResultsParcelable; import android.net.LinkProperties; import android.net.LinkPropertiesParcelable; -import android.net.NetworkStack; -import android.net.ip.IIpClientCallbacks; +import android.net.NetworkStackClient; import android.os.ConditionVariable; import java.io.FileDescriptor; @@ -76,30 +75,17 @@ public class IpClientUtil { * * <p>This is a convenience method to allow clients to use {@link IpClientCallbacks} instead of * {@link IIpClientCallbacks}. - * @see {@link NetworkStack#makeIpClient(String, IIpClientCallbacks)} + * @see {@link NetworkStackClient#makeIpClient(String, IIpClientCallbacks)} */ public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) { - context.getSystemService(NetworkStack.class) - .makeIpClient(ifName, new IpClientCallbacksProxy(callback)); - } - - /** - * Create a new IpClient. - * - * <p>This is a convenience method to allow clients to use {@link IpClientCallbacksProxy} - * instead of {@link IIpClientCallbacks}. - * @see {@link NetworkStack#makeIpClient(String, IIpClientCallbacks)} - */ - public static void makeIpClient( - Context context, String ifName, IpClientCallbacksProxy callback) { - context.getSystemService(NetworkStack.class) - .makeIpClient(ifName, callback); + // TODO: migrate clients and remove context argument + NetworkStackClient.getInstance().makeIpClient(ifName, new IpClientCallbacksProxy(callback)); } /** * Wrapper to relay calls from {@link IIpClientCallbacks} to {@link IpClientCallbacks}. */ - public static class IpClientCallbacksProxy extends IIpClientCallbacks.Stub { + private static class IpClientCallbacksProxy extends IIpClientCallbacks.Stub { protected final IpClientCallbacks mCb; /** diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java index 7910c9a69310..34fc7354d63e 100644 --- a/services/net/java/android/net/ip/IpServer.java +++ b/services/net/java/android/net/ip/IpServer.java @@ -22,7 +22,6 @@ import static android.net.util.NetworkConstants.FF; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; -import android.content.Context; import android.net.ConnectivityManager; import android.net.INetd; import android.net.INetworkStackStatusCallback; @@ -31,7 +30,7 @@ import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.NetworkStack; +import android.net.NetworkStackClient; import android.net.RouteInfo; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; @@ -132,10 +131,6 @@ public class IpServer extends StateMachine { } public static class Dependencies { - private final Context mContext; - public Dependencies(Context context) { - mContext = context; - } public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { return new RouterAdvertisementDaemon(ifParams); } @@ -153,7 +148,7 @@ public class IpServer extends StateMachine { */ public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb) { - mContext.getSystemService(NetworkStack.class).makeDhcpServer(ifName, params, cb); + NetworkStackClient.getInstance().makeDhcpServer(ifName, params, cb); } } diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java index 0355e84d884d..5cb6cbb93b5b 100644 --- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java +++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java @@ -556,16 +556,6 @@ public class IPackageManagerStub implements IPackageManager { } @Override - public byte[] getPermissionGrantBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restorePermissionGrants(byte[] backup, int userId) throws RemoteException { - - } - - @Override public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates) throws RemoteException { return null; diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java index 5900fc57296c..01759d2e8f4a 100644 --- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java @@ -98,6 +98,8 @@ public class ColorDisplayServiceTest { mColorDisplayService = new ColorDisplayService(mContext); mBinderService = mColorDisplayService.new BinderService(); + LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class, + mColorDisplayService.new ColorDisplayServiceInternal()); } @After @@ -110,6 +112,8 @@ public class ColorDisplayServiceTest { mUserId = UserHandle.USER_NULL; mContext = null; + + LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); } @AfterClass @@ -979,6 +983,99 @@ public class ColorDisplayServiceTest { assertActiveColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); } + @Test + public void displayWhiteBalance_enable() { + setWhiteBalance(true /* Enable DWB Setting */); + setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */); + mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); + startService(); + assertDwbActive(true); + } + + @Test + public void displayWhiteBalance_disableAfterNightDisplayEnable() { + setWhiteBalance(true /* Enable DWB Setting */); + + startService(); + /* Enable nightlight */ + setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */); + setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */); + + /* Since we are using FakeSettingsProvider which could not trigger observer change, + * force an update here.*/ + mColorDisplayService.updateDisplayWhiteBalanceStatus(); + assertDwbActive(false); + } + + @Test + public void displayWhiteBalance_enableAfterNightDisplayDisable() { + setWhiteBalance(true /* Enable DWB Setting */); + startService(); + /* Enable nightlight */ + setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */); + setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */); + + mColorDisplayService.updateDisplayWhiteBalanceStatus(); + assertDwbActive(false); + + /* Disable nightlight */ + setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */); + mColorDisplayService.updateDisplayWhiteBalanceStatus(); + assertDwbActive(true); + } + + @Test + public void displayWhiteBalance_enableAfterLinearColorMode() { + setWhiteBalance(true /* Enable DWB Setting */); + setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */); + startService(); + mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); + + mColorDisplayService.updateDisplayWhiteBalanceStatus(); + assertDwbActive(true); + } + + @Test + public void displayWhiteBalance_setTemperatureOverMax() { + int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax; + + ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService( + ColorDisplayService.ColorDisplayServiceInternal.class); + cdsInternal.setDisplayWhiteBalanceColorTemperature(max+1); + + assertWithMessage("Unexpected temperature set") + .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature) + .isEqualTo(max); + } + + @Test + public void displayWhiteBalance_setTemperatureBelowMin() { + int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin; + + ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService( + ColorDisplayService.ColorDisplayServiceInternal.class); + cdsInternal.setDisplayWhiteBalanceColorTemperature(min - 1); + + assertWithMessage("Unexpected temperature set") + .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature) + .isEqualTo(min); + } + + @Test + public void displayWhiteBalance_setValidTemperature() { + int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin; + int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax; + int valToSet = (min + max) / 2; + + ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService( + ColorDisplayService.ColorDisplayServiceInternal.class); + cdsInternal.setDisplayWhiteBalanceColorTemperature(valToSet); + + assertWithMessage("Unexpected temperature set") + .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature) + .isEqualTo(valToSet); + } + /** * Configures Night display to use a custom schedule. * @@ -1041,6 +1138,16 @@ public class ColorDisplayServiceTest { } /** + * Configures the Display White Balance setting state. + * + * @param state {@code true} if display white balance should be enabled + */ + private void setWhiteBalance(boolean state) { + Secure.putIntForUser(mContext.getContentResolver(), + Secure.DISPLAY_WHITE_BALANCE_ENABLED, state ? 1 : 0, mUserId); + } + + /** * Configures color mode. */ private void setColorMode(int colorMode) { @@ -1111,6 +1218,17 @@ public class ColorDisplayServiceTest { } /** + * Convenience method for asserting that the DWB active status matches expectation. + * + * @param enabled the expected active status. + */ + private void assertDwbActive(boolean enabled) { + assertWithMessage("Incorrect Display White Balance state") + .that(mColorDisplayService.mDisplayWhiteBalanceTintController.isActivated()) + .isEqualTo(enabled); + } + + /** * Convenience for making a {@link LocalTime} instance with an offset relative to now. * * @param offsetMinutes the offset relative to now (in minutes) diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 6d28ed19af4f..50734efacac9 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -55,8 +55,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.AtomicFile; import com.android.server.LocalServices; -import com.android.server.pm.permission.PermissionManagerInternal; import com.android.server.pm.permission.PermissionManagerService; +import com.android.server.pm.permission.PermissionManagerServiceInternal; import org.junit.After; import org.junit.Before; @@ -88,7 +88,8 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); Settings settings = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -103,7 +104,8 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); Settings settings = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -120,7 +122,8 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); Settings settings = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -143,7 +146,8 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); Settings settings = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -313,7 +317,8 @@ public class PackageManagerSettingsTests { writeOldFiles(); final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); Settings settings = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); assertThat(settings.readLPw(createFakeUsers()), is(true)); @@ -507,7 +512,8 @@ public class PackageManagerSettingsTests { public void testUpdatePackageSetting03() { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); final Settings testSettings01 = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); final SharedUserSetting testUserSetting01 = createSharedUserSetting( @@ -625,7 +631,8 @@ public class PackageManagerSettingsTests { public void testCreateNewSetting03() { final Context context = InstrumentationRegistry.getContext(); final Object lock = new Object(); - PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock); + PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null, + lock); final Settings testSettings01 = new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock); final SharedUserSetting testUserSetting01 = createSharedUserSetting( diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java index 2b8e307e23b7..b299f0dd7253 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java @@ -36,11 +36,10 @@ import org.junit.Before; import org.junit.Test; import java.io.File; -import java.io.IOException; /** - * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}. + * Test class for {@link WindowTraceBuffer}. * * Build/Install/Run: * atest WmTests:WindowTraceBufferTest @@ -49,12 +48,15 @@ import java.io.IOException; @Presubmit public class WindowTraceBufferTest { private File mFile; + private WindowTraceBuffer mBuffer; @Before public void setUp() throws Exception { final Context testContext = getInstrumentation().getContext(); mFile = testContext.getFileStreamPath("tracing_test.dat"); mFile.delete(); + + mBuffer = new WindowTraceBuffer(10); } @After @@ -63,145 +65,112 @@ public class WindowTraceBufferTest { } @Test - public void testTraceQueueBuffer_addItem() throws Exception { - ProtoOutputStream toWrite1 = getDummy(1); - ProtoOutputStream toWrite2 = getDummy(2); - ProtoOutputStream toWrite3 = getDummy(3); - final int objectSize = toWrite1.getRawSize(); - final int bufferCapacity = objectSize * 2; - - final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity); - - buffer.add(toWrite1); - byte[] toWrite1Bytes = toWrite1.getBytes(); - assertTrue("First element should be in the list", - buffer.contains(toWrite1Bytes)); - - buffer.add(toWrite2); - byte[] toWrite2Bytes = toWrite2.getBytes(); - assertTrue("First element should be in the list", - buffer.contains(toWrite1Bytes)); - assertTrue("Second element should be in the list", - buffer.contains(toWrite2Bytes)); - - buffer.add(toWrite3); - byte[] toWrite3Bytes = toWrite3.getBytes(); - assertTrue("First element should be in the list", - buffer.contains(toWrite1Bytes)); - assertTrue("Second element should be in the list", - buffer.contains(toWrite2Bytes)); - assertTrue("Third element should not be in the list", - !buffer.contains(toWrite3Bytes)); - - assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2); - assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity), - buffer.mBufferSize, bufferCapacity); - assertEquals("Buffer is full, available space should be 0", - buffer.getAvailableSpace(), 0); - } - - @Test - public void testTraceRingBuffer_addItem() throws Exception { + public void test_addItem() { ProtoOutputStream toWrite = getDummy(1); final int objectSize = toWrite.getRawSize(); + mBuffer.setCapacity(objectSize); + mBuffer.resetBuffer(); - final WindowTraceBuffer buffer = buildRingBuffer(objectSize); - - Preconditions.checkArgument(buffer.mBuffer.isEmpty()); + Preconditions.checkArgument(mBuffer.size() == 0); - buffer.add(toWrite); + mBuffer.add(toWrite); - assertEquals("Item was not added to the buffer", buffer.mBuffer.size(), 1); + assertEquals("Item was not added to the buffer", 1, mBuffer.size()); assertEquals("Total buffer getSize differs from inserted object", - buffer.mBufferSize, objectSize); - assertEquals("Available buffer space does not match used one", - buffer.getAvailableSpace(), 0); + mBuffer.getBufferSize(), objectSize); + assertEquals("Available buffer space does not match used one", 0, + mBuffer.getAvailableSpace()); } @Test - public void testTraceRingBuffer_addItemMustOverwriteOne() throws Exception { + public void test_addItemMustOverwriteOne() { ProtoOutputStream toWrite1 = getDummy(1); ProtoOutputStream toWrite2 = getDummy(2); ProtoOutputStream toWrite3 = getDummy(3); final int objectSize = toWrite1.getRawSize(); - final int bufferCapacity = objectSize * 2 + 1; - final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity); + mBuffer.setCapacity(bufferCapacity); + mBuffer.resetBuffer(); - buffer.add(toWrite1); + mBuffer.add(toWrite1); byte[] toWrite1Bytes = toWrite1.getBytes(); assertTrue("First element should be in the list", - buffer.contains(toWrite1Bytes)); + mBuffer.contains(toWrite1Bytes)); - buffer.add(toWrite2); + mBuffer.add(toWrite2); byte[] toWrite2Bytes = toWrite2.getBytes(); assertTrue("First element should be in the list", - buffer.contains(toWrite1Bytes)); + mBuffer.contains(toWrite1Bytes)); assertTrue("Second element should be in the list", - buffer.contains(toWrite2Bytes)); + mBuffer.contains(toWrite2Bytes)); - buffer.add(toWrite3); + mBuffer.add(toWrite3); byte[] toWrite3Bytes = toWrite3.getBytes(); assertTrue("First element should not be in the list", - !buffer.contains(toWrite1Bytes)); + !mBuffer.contains(toWrite1Bytes)); assertTrue("Second element should be in the list", - buffer.contains(toWrite2Bytes)); + mBuffer.contains(toWrite2Bytes)); assertTrue("Third element should be in the list", - buffer.contains(toWrite3Bytes)); - assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2); + mBuffer.contains(toWrite3Bytes)); + assertEquals("Buffer should have 2 elements", 2, mBuffer.size()); assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity), - buffer.mBufferSize, bufferCapacity - 1); - assertEquals(" Buffer is full, available space should be 0", - buffer.getAvailableSpace(), 1); + mBuffer.getBufferSize(), bufferCapacity - 1); + assertEquals(" Buffer is full, available space should be 0", 1, + mBuffer.getAvailableSpace()); } @Test - public void testTraceRingBuffer_addItemMustOverwriteMultiple() throws Exception { + public void test_addItemMustOverwriteMultiple() { ProtoOutputStream toWriteSmall1 = getDummy(1); ProtoOutputStream toWriteSmall2 = getDummy(2); final int objectSize = toWriteSmall1.getRawSize(); - final int bufferCapacity = objectSize * 2; - final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity); + mBuffer.setCapacity(bufferCapacity); + mBuffer.resetBuffer(); ProtoOutputStream toWriteBig = new ProtoOutputStream(); toWriteBig.write(MAGIC_NUMBER, 1); toWriteBig.write(MAGIC_NUMBER, 2); - buffer.add(toWriteSmall1); + mBuffer.add(toWriteSmall1); byte[] toWriteSmall1Bytes = toWriteSmall1.getBytes(); assertTrue("First element should be in the list", - buffer.contains(toWriteSmall1Bytes)); + mBuffer.contains(toWriteSmall1Bytes)); - buffer.add(toWriteSmall2); + mBuffer.add(toWriteSmall2); byte[] toWriteSmall2Bytes = toWriteSmall2.getBytes(); assertTrue("First element should be in the list", - buffer.contains(toWriteSmall1Bytes)); + mBuffer.contains(toWriteSmall1Bytes)); assertTrue("Second element should be in the list", - buffer.contains(toWriteSmall2Bytes)); + mBuffer.contains(toWriteSmall2Bytes)); - buffer.add(toWriteBig); + mBuffer.add(toWriteBig); byte[] toWriteBigBytes = toWriteBig.getBytes(); assertTrue("Third element should overwrite all others", - !buffer.contains(toWriteSmall1Bytes)); + !mBuffer.contains(toWriteSmall1Bytes)); assertTrue("Third element should overwrite all others", - !buffer.contains(toWriteSmall2Bytes)); + !mBuffer.contains(toWriteSmall2Bytes)); assertTrue("Third element should overwrite all others", - buffer.contains(toWriteBigBytes)); + mBuffer.contains(toWriteBigBytes)); - assertEquals(" Buffer should have only 1 big element", buffer.mBuffer.size(), 1); + assertEquals(" Buffer should have only 1 big element", 1, mBuffer.size()); assertEquals(String.format(" Buffer is full, used space should be %d", bufferCapacity), - buffer.mBufferSize, bufferCapacity); - assertEquals(" Buffer is full, available space should be 0", - buffer.getAvailableSpace(), 0); + mBuffer.getBufferSize(), bufferCapacity); + assertEquals(" Buffer is full, available space should be 0", 0, + mBuffer.getAvailableSpace()); } - private WindowTraceBuffer buildRingBuffer(int capacity) throws IOException { - return new WindowTraceBuffer.Builder() - .setContinuousMode(true) - .setBufferCapacity(capacity) - .setTraceFile(mFile) - .build(); + @Test + public void test_startResetsBuffer() { + ProtoOutputStream toWrite = getDummy(1); + mBuffer.resetBuffer(); + Preconditions.checkArgument(mBuffer.size() == 0); + + mBuffer.add(toWrite); + assertEquals("Item was not added to the buffer", 1, mBuffer.size()); + mBuffer.resetBuffer(); + assertEquals("Buffer should be empty after reset", 0, mBuffer.size()); + assertEquals("Buffer size should be 0 after reset", 0, mBuffer.getBufferSize()); } private ProtoOutputStream getDummy(int value) { @@ -212,7 +181,4 @@ public class WindowTraceBufferTest { return toWrite; } - private WindowTraceBuffer buildQueueBuffer(int size) throws IOException { - return new WindowTraceQueueBuffer(size, mFile, false); - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java index 3c6e2405adff..8358fdd18e0e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java @@ -88,8 +88,7 @@ public class WindowTracingTest { mFile.delete(); mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer, - new WindowManagerGlobalLock()); - mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */); + new WindowManagerGlobalLock(), 1024); } @After @@ -103,13 +102,13 @@ public class WindowTracingTest { } @Test - public void isEnabled_returnsTrueAfterStart() throws Exception { + public void isEnabled_returnsTrueAfterStart() { mWindowTracing.startTrace(mock(PrintWriter.class)); assertTrue(mWindowTracing.isEnabled()); } @Test - public void isEnabled_returnsFalseAfterStop() throws Exception { + public void isEnabled_returnsFalseAfterStop() { mWindowTracing.startTrace(mock(PrintWriter.class)); mWindowTracing.stopTrace(mock(PrintWriter.class)); assertFalse(mWindowTracing.isEnabled()); @@ -133,6 +132,8 @@ public class WindowTracingTest { mWindowTracing.startTrace(mock(PrintWriter.class)); mWindowTracing.stopTrace(mock(PrintWriter.class)); + assertTrue("Trace file should exist", mFile.exists()); + byte[] header = new byte[MAGIC_HEADER.length]; try (InputStream is = new FileInputStream(mFile)) { assertEquals(MAGIC_HEADER.length, is.read(header)); diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index f1ddfe4cd0d5..8feed7fdb785 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -15,7 +15,6 @@ */ package com.android.server.usage; -import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED; import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED; import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED; import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED; @@ -302,27 +301,6 @@ public class IntervalStats { UsageStats usageStats = packageStats.valueAt(i); usageStats.update(null, timeStamp, eventType, instanceId); } - } else if (eventType == ACTIVITY_DESTROYED) { - UsageStats usageStats = packageStats.get(packageName); - if (usageStats != null) { - // If previous event is not ACTIVITY_STOPPED, convert ACTIVITY_DESTROYED - // to ACTIVITY_STOPPED and add to event list. - // Otherwise do not add anything to event list. (Because we want to save space - // and we do not want a ACTIVITY_STOPPED followed by - // ACTIVITY_DESTROYED in event list). - final int index = usageStats.mActivities.indexOfKey(instanceId); - if (index >= 0) { - final int type = usageStats.mActivities.valueAt(index); - if (type != ACTIVITY_STOPPED) { - Event event = new Event(ACTIVITY_STOPPED, timeStamp); - event.mPackage = packageName; - event.mClass = className; - event.mInstanceId = instanceId; - addEvent(event); - } - } - usageStats.update(className, timeStamp, ACTIVITY_DESTROYED, instanceId); - } } else { UsageStats usageStats = getOrCreateUsageStats(packageName); usageStats.update(className, timeStamp, eventType, instanceId); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index af5278f222b8..ebb0210cb553 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -145,8 +145,16 @@ public class UsageStatsService extends SystemService implements AppTimeLimitController mAppTimeLimit; final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray(); - final SparseArray<String> mVisibleActivities = new SparseArray(); + final SparseArray<ActivityData> mVisibleActivities = new SparseArray(); + private static class ActivityData { + private final String mTaskRootPackage; + private final String mTaskRootClass; + private ActivityData(String taskRootPackage, String taskRootClass) { + mTaskRootPackage = taskRootPackage; + mTaskRootClass = taskRootClass; + } + } private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener = new UsageStatsManagerInternal.AppIdleStateChangeListener() { @@ -464,47 +472,57 @@ public class UsageStatsService extends SystemService implements final long elapsedRealtime = SystemClock.elapsedRealtime(); convertToSystemTimeLocked(event); - if (event.getPackageName() != null - && mPackageManagerInternal.isPackageEphemeral(userId, event.getPackageName())) { + if (event.mPackage != null + && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) { event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP; } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); - service.reportEvent(event); - - mAppStandby.reportEvent(event, elapsedRealtime, userId); - - String packageName; - - switch(mUsageSource) { - case USAGE_SOURCE_CURRENT_ACTIVITY: - packageName = event.getPackageName(); - break; - case USAGE_SOURCE_TASK_ROOT_ACTIVITY: - default: - packageName = event.getTaskRootPackageName(); - if (packageName == null) { - packageName = event.getPackageName(); - } - break; - } - switch (event.mEventType) { case Event.ACTIVITY_RESUMED: - synchronized (mVisibleActivities) { - // check if this activity has already been resumed - if (mVisibleActivities.get(event.mInstanceId) != null) break; - mVisibleActivities.put(event.mInstanceId, event.getClassName()); - try { - mAppTimeLimit.noteUsageStart(packageName, userId); - } catch (IllegalArgumentException iae) { - Slog.e(TAG, "Failed to note usage start", iae); + // check if this activity has already been resumed + if (mVisibleActivities.get(event.mInstanceId) != null) break; + mVisibleActivities.put(event.mInstanceId, + new ActivityData(event.mTaskRootPackage, event.mTaskRootClass)); + try { + switch(mUsageSource) { + case USAGE_SOURCE_CURRENT_ACTIVITY: + mAppTimeLimit.noteUsageStart(event.mPackage, userId); + break; + case USAGE_SOURCE_TASK_ROOT_ACTIVITY: + default: + mAppTimeLimit.noteUsageStart(event.mTaskRootPackage, userId); + break; + } + } catch (IllegalArgumentException iae) { + Slog.e(TAG, "Failed to note usage start", iae); + } + break; + case Event.ACTIVITY_PAUSED: + if (event.mTaskRootPackage == null) { + // Task Root info is missing. Repair the event based on previous data + final ActivityData prevData = mVisibleActivities.get(event.mInstanceId); + if (prevData == null) { + Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage + + "/" + event.mClass + " event : " + event.mEventType + + " instanceId : " + event.mInstanceId + ")"); + } else { + event.mTaskRootPackage = prevData.mTaskRootPackage; + event.mTaskRootClass = prevData.mTaskRootClass; } } break; - case Event.ACTIVITY_STOPPED: case Event.ACTIVITY_DESTROYED: + // Treat activity destroys like activity stops. + event.mEventType = Event.ACTIVITY_STOPPED; + // Fallthrough + case Event.ACTIVITY_STOPPED: + final ActivityData prevData = + mVisibleActivities.removeReturnOld(event.mInstanceId); + if (prevData == null) { + // The activity stop was already handled. + return; + } + ArraySet<String> tokens; synchronized (mUsageReporters) { tokens = mUsageReporters.removeReturnOld(event.mInstanceId); @@ -517,7 +535,7 @@ public class UsageStatsService extends SystemService implements final String token = tokens.valueAt(i); try { mAppTimeLimit.noteUsageStop( - buildFullToken(event.getPackageName(), token), userId); + buildFullToken(event.mPackage, token), userId); } catch (IllegalArgumentException iae) { Slog.w(TAG, "Failed to stop usage for during reporter death: " + iae); @@ -525,18 +543,32 @@ public class UsageStatsService extends SystemService implements } } } - - synchronized (mVisibleActivities) { - if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) { - try { - mAppTimeLimit.noteUsageStop(packageName, userId); - } catch (IllegalArgumentException iae) { - Slog.w(TAG, "Failed to note usage stop", iae); - } + if (event.mTaskRootPackage == null) { + // Task Root info is missing. Repair the event based on previous data + event.mTaskRootPackage = prevData.mTaskRootPackage; + event.mTaskRootClass = prevData.mTaskRootClass; + } + try { + switch(mUsageSource) { + case USAGE_SOURCE_CURRENT_ACTIVITY: + mAppTimeLimit.noteUsageStop(event.mPackage, userId); + break; + case USAGE_SOURCE_TASK_ROOT_ACTIVITY: + default: + mAppTimeLimit.noteUsageStop(event.mTaskRootPackage, userId); + break; } + } catch (IllegalArgumentException iae) { + Slog.w(TAG, "Failed to note usage stop", iae); } break; } + + final UserUsageStatsService service = + getUserDataAndInitializeIfNeededLocked(userId, timeNow); + service.reportEvent(event); + + mAppStandby.reportEvent(event, elapsedRealtime, userId); } } diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index bd0d4ae27800..ae12a17e1e2f 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -623,7 +623,7 @@ public abstract class Connection extends Conferenceable { "android.telecom.event.HANDOVER_FAILED"; /** - * Connection extra key used to store SIP invite fields for an incoming call for IMS calls + * String Connection extra key used to store SIP invite fields for an incoming call for IMS call */ public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE"; diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index a1c32b5f80a3..2462beeb28a8 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -2123,6 +2123,11 @@ public final class Telephony { * @hide - not meant for public use */ public interface RcsColumns { + // TODO(sahinc): Turn this to true once the schema finalizes, so that people can update + // their messaging databases. NOTE: move the switch/case update in MmsSmsDatabaseHelper to + // the latest version of the database before turning this flag to true. + boolean IS_RCS_TABLE_SCHEMA_CODE_COMPLETE = false; + /** * The authority for the content provider */ diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index 099015fd3d0e..2aa4768d3f00 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -981,4 +981,13 @@ public class SmsMessage { return false; } + + /** + * {@hide} + * Returns the recipient address(receiver) of this SMS message in String form or null if + * unavailable. + */ + public String getRecipientAddress() { + return mWrappedSmsMessage.getRecipientAddress(); + } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 836a50bf05c7..94f26a8a8d61 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1236,7 +1236,7 @@ public class SubscriptionManager { @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public List<SubscriptionInfo> getActiveSubscriptionInfoList() { - return getActiveSubscriptionInfoList(false); + return getActiveSubscriptionInfoList(/* userVisibleonly */true); } /** @@ -2858,15 +2858,24 @@ public class SubscriptionManager { /** * Whether system UI should hide a subscription. If it's a bundled opportunistic * subscription, it shouldn't show up in anywhere in Settings app, dialer app, - * or status bar. + * or status bar. Exception is if caller is carrier app, in which case they will + * want to see their own hidden subscriptions. * * @param info the subscriptionInfo to check against. * @return true if this subscription should be hidden. * * @hide */ - public static boolean shouldHideSubscription(SubscriptionInfo info) { - return (info != null && !TextUtils.isEmpty(info.getGroupUuid()) && info.isOpportunistic()); + private boolean shouldHideSubscription(SubscriptionInfo info) { + if (info == null) return false; + + // If hasCarrierPrivileges or canManageSubscription returns true, it means caller + // has carrier privilege. + boolean hasCarrierPrivilegePermission = (info.isEmbedded() && canManageSubscription(info)) + || TelephonyManager.from(mContext).hasCarrierPrivileges(info.getSubscriptionId()); + + return (!TextUtils.isEmpty(info.getGroupUuid()) && info.isOpportunistic() + && !hasCarrierPrivilegePermission); } /** diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 73f055649b3f..d5c70793d3bc 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -266,6 +266,11 @@ public final class ImsCallProfile implements Parcelable { public static final String EXTRA_DISPLAY_TEXT = "DisplayText"; public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo"; public static final String EXTRA_IS_CALL_PULL = "CallPull"; + + /** + * String extra property + * Containing fields from the SIP INVITE message for an IMS call + */ public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS"; diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index 190eac4d8c02..ffdc4b676f90 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -41,6 +41,9 @@ public abstract class SmsMessageBase { @UnsupportedAppUsage protected SmsAddress mOriginatingAddress; + /** {@hide} The address of the receiver */ + protected SmsAddress mRecipientAddress; + /** {@hide} The message body as a string. May be null if the message isn't text */ @UnsupportedAppUsage protected String mMessageBody; @@ -457,4 +460,17 @@ public abstract class SmsMessageBase { return ted; } + + /** + * {@hide} + * Returns the receiver address of this SMS message in String + * form or null if unavailable + */ + public String getRecipientAddress() { + if (mRecipientAddress == null) { + return null; + } + + return mRecipientAddress.getAddressString(); + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 1da5eac27002..a31fa0b6a725 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -601,18 +601,24 @@ public class SmsMessage extends SmsMessageBase { } else if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK) { if (numberType == 2) - Rlog.e(LOG_TAG, "TODO: Originating Addr is email id"); + Rlog.e(LOG_TAG, "TODO: Addr is email id"); else Rlog.e(LOG_TAG, - "TODO: Originating Addr is data network address"); + "TODO: Addr is data network address"); } else { - Rlog.e(LOG_TAG, "Originating Addr is of incorrect type"); + Rlog.e(LOG_TAG, "Addr is of incorrect type"); } } else { Rlog.e(LOG_TAG, "Incorrect Digit mode"); } addr.origBytes = data; - Rlog.i(LOG_TAG, "Originating Addr=" + addr.toString()); + Rlog.pii(LOG_TAG, "Addr=" + addr.toString()); + mOriginatingAddress = addr; + if (parameterId == DESTINATION_ADDRESS) { + // Original address awlays indicates one sender's address for 3GPP2 + // Here add recipient address support along with 3GPP + mRecipientAddress = addr; + } break; case ORIGINATING_SUB_ADDRESS: case DESTINATION_SUB_ADDRESS: @@ -667,7 +673,7 @@ public class SmsMessage extends SmsMessageBase { } /** - * Parses a SMS message from its BearerData stream. (mobile-terminated only) + * Parses a SMS message from its BearerData stream. */ public void parseSms() { // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6 @@ -697,16 +703,15 @@ public class SmsMessage extends SmsMessageBase { } if (mOriginatingAddress != null) { - mOriginatingAddress.address = new String(mOriginatingAddress.origBytes); - if (mOriginatingAddress.ton == CdmaSmsAddress.TON_INTERNATIONAL_OR_IP) { - if (mOriginatingAddress.address.charAt(0) != '+') { - mOriginatingAddress.address = "+" + mOriginatingAddress.address; - } - } + decodeSmsDisplayAddress(mOriginatingAddress); if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: " + mOriginatingAddress.address); } + if (mRecipientAddress != null) { + decodeSmsDisplayAddress(mRecipientAddress); + } + if (mBearerData.msgCenterTimeStamp != null) { mScTimeMillis = mBearerData.msgCenterTimeStamp.toMillis(true); } @@ -731,7 +736,8 @@ public class SmsMessage extends SmsMessageBase { status = mBearerData.errorClass << 8; status |= mBearerData.messageStatus; } - } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER) { + } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER + && mBearerData.messageType != BearerData.MESSAGE_TYPE_SUBMIT) { throw new RuntimeException("Unsupported message type: " + mBearerData.messageType); } @@ -743,6 +749,16 @@ public class SmsMessage extends SmsMessageBase { } } + private void decodeSmsDisplayAddress(SmsAddress addr) { + addr.address = new String(addr.origBytes); + if (addr.ton == CdmaSmsAddress.TON_INTERNATIONAL_OR_IP) { + if (addr.address.charAt(0) != '+') { + addr.address = "+" + addr.address; + } + } + Rlog.pii(LOG_TAG, " decodeSmsDisplayAddress = " + addr.address); + } + /** * Parses a broadcast SMS, possibly containing a CMAS alert. * diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index 015efa6a0c7d..19465a44e4e8 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -71,9 +71,6 @@ public class SmsMessage extends SmsMessageBase { // e.g. 23.040 9.2.2.1 private boolean mReplyPathPresent = false; - /** The address of the receiver. */ - private GsmSmsAddress mRecipientAddress; - /** * TP-Status - status of a previously submitted SMS. * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt index ab10800ac534..0cb8f22d8070 100644 --- a/test-mock/api/test-current.txt +++ b/test-mock/api/test-current.txt @@ -9,10 +9,12 @@ package android.test.mock { method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); method public String[] getNamesForUids(int[]); method public String getPermissionControllerPackageName(); + method public int getPermissionFlags(String, String, android.os.UserHandle); method @NonNull public String getServicesSystemSharedLibraryPackageName(); method @NonNull public String getSharedSystemSharedLibraryPackageName(); method public void grantRuntimePermission(String, String, android.os.UserHandle); method public void revokeRuntimePermission(String, String, android.os.UserHandle); + method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle); } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e57d838bcf92..a10fb4ee1305 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; @@ -123,7 +124,7 @@ import android.net.NetworkMisc; import android.net.NetworkParcelable; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.NetworkStack; +import android.net.NetworkStackClient; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; @@ -245,7 +246,7 @@ public class ConnectivityServiceTest { @Mock INetworkStatsService mStatsService; @Mock INetworkPolicyManager mNpm; @Mock INetd mMockNetd; - @Mock NetworkStack mNetworkStack; + @Mock NetworkStackClient mNetworkStack; private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); @@ -901,11 +902,14 @@ public class ConnectivityServiceTest { public void setUids(Set<UidRange> uids) { mNetworkCapabilities.setUids(uids); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); } @Override public int getNetId() { + if (mMockNetworkAgent == null) { + return NETID_UNSET; + } return mMockNetworkAgent.getNetwork().netId; } @@ -927,12 +931,13 @@ public class ConnectivityServiceTest { } @Override - public void updateCapabilities() { - if (!mConnected) return; - super.updateCapabilities(); - // Because super.updateCapabilities will update the capabilities of the agent but not - // the mock agent, the mock agent needs to know about them. + public NetworkCapabilities updateCapabilities(Network defaultNetwork) { + if (!mConnected) return null; + super.updateCapabilities(defaultNetwork); + // Because super.updateCapabilities will update the capabilities of the agent but + // not the mock agent, the mock agent needs to know about them. copyCapabilitiesToNetworkAgent(); + return new NetworkCapabilities(mNetworkCapabilities); } private void copyCapabilitiesToNetworkAgent() { @@ -1077,6 +1082,11 @@ public class ConnectivityServiceTest { } @Override + protected NetworkStackClient getNetworkStack() { + return mNetworkStack; + } + + @Override public WakeupMessage makeWakeupMessage( Context context, Handler handler, String cmdName, int cmd, Object obj) { return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj); @@ -4690,6 +4700,7 @@ public class ConnectivityServiceTest { vpnNetworkAgent.connect(false); mMockVpn.connect(); + mMockVpn.setUnderlyingNetworks(new Network[0]); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4722,6 +4733,7 @@ public class ConnectivityServiceTest { ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); + vpnNetworkAgent.setUids(ranges); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4755,12 +4767,11 @@ public class ConnectivityServiceTest { } @Test - public void testVpnWithAndWithoutInternet() { + public void testVpnWithoutInternet() { final int uid = Process.myUid(); final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); @@ -4782,11 +4793,30 @@ public class ConnectivityServiceTest { vpnNetworkAgent.disconnect(); defaultCallback.assertNoCallback(); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + mCm.unregisterNetworkCallback(defaultCallback); + } + + @Test + public void testVpnWithInternet() { + final int uid = Process.myUid(); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); mMockVpn.connect(); + defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -4794,14 +4824,6 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - ranges.clear(); - mMockVpn.setNetworkAgent(vpnNetworkAgent); - mMockVpn.setUids(ranges); - vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); - mMockVpn.connect(); - defaultCallback.assertNoCallback(); - mCm.unregisterNetworkCallback(defaultCallback); } @@ -4904,6 +4926,70 @@ public class ConnectivityServiceTest { } @Test + public void testNullUnderlyingNetworks() { + final int uid = Process.myUid(); + + final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); + final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_NOT_VPN) + .addTransportType(TRANSPORT_VPN) + .build(); + NetworkCapabilities nc; + mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); + vpnNetworkCallback.assertNoCallback(); + + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.connect(); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); + + vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); + assertTrue(nc.hasTransport(TRANSPORT_VPN)); + assertFalse(nc.hasTransport(TRANSPORT_CELLULAR)); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + // By default, VPN is set to track default network (i.e. its underlying networks is null). + // In case of no default network, VPN is considered metered. + assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); + + // Connect to Cell; Cell is the default network. + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Connect to WiFi; WiFi is the new default. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) + && caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Disconnect Cell. The default network did not change, so there shouldn't be any changes in + // the capabilities. + mCellNetworkAgent.disconnect(); + + // Disconnect wifi too. Now we have no default network. + mWiFiNetworkAgent.disconnect(); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + mMockVpn.disconnect(); + } + + @Test public void testNetworkBlockedStatus() { final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index e877a8f7e6c1..5057443eee07 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -38,7 +38,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkMisc; -import android.net.NetworkStack; import android.os.INetworkManagementService; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -75,16 +74,12 @@ public class LingerMonitorTest { @Mock NetworkMisc mMisc; @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; - @Mock NetworkStack mNetworkStack; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mCtx.getResources()).thenReturn(mResources); when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity"); - when(mCtx.getSystemServiceName(NetworkStack.class)) - .thenReturn(Context.NETWORK_STACK_SERVICE); - when(mCtx.getSystemService(Context.NETWORK_STACK_SERVICE)).thenReturn(mNetworkStack); mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT); } diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index a4a735d1a89d..533d7ad2a472 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -195,10 +195,6 @@ public class TetheringTest { } public class MockIpServerDependencies extends IpServer.Dependencies { - MockIpServerDependencies() { - super(null); - } - @Override public RouterAdvertisementDaemon getRouterAdvertisementDaemon( InterfaceParams ifParams) { @@ -266,7 +262,7 @@ public class TetheringTest { } @Override - public IpServer.Dependencies getIpServerDependencies(Context context) { + public IpServer.Dependencies getIpServerDependencies() { return mIpServerDependencies; } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 46de3d0608ff..f169d6b5bee3 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -566,7 +566,7 @@ public class VpnTest { final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.updateCapabilities( + Vpn.applyUnderlyingCapabilities( mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); @@ -577,7 +577,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities( + Vpn.applyUnderlyingCapabilities( mConnectivityManager, new Network[] {mobile}, caps, @@ -591,7 +591,7 @@ public class VpnTest { assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities( + Vpn.applyUnderlyingCapabilities( mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); @@ -602,7 +602,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities( + Vpn.applyUnderlyingCapabilities( mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); @@ -613,7 +613,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities( + Vpn.applyUnderlyingCapabilities( mConnectivityManager, new Network[] {mobile, wifi}, caps, diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 5f664f5fdd5c..98324850f3f5 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -435,7 +435,7 @@ void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* const size_t NS = pool->size(); for (size_t s=0; s<NS; s++) { String8 str = pool->string8ObjectAt(s); - printer->Print(StringPrintf("String #%zd: %s\n", s, str.string())); + printer->Print(StringPrintf("String #%zd : %s\n", s, str.string())); } } diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 2f8ca2d62061..c1887822ce7d 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -1084,7 +1084,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource // Create a overlayable entry grouping that represents this <overlayable> auto overlayable = std::make_shared<Overlayable>( overlayable_name.value(), (overlayable_actor) ? overlayable_actor.value() : "", - out_resource->source); + source_); bool error = false; std::string comment; @@ -1113,6 +1113,13 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource const std::string& element_name = parser->element_name(); const std::string& element_namespace = parser->element_namespace(); if (element_namespace.empty() && element_name == "item") { + if (current_policies == OverlayableItem::Policy::kNone) { + diag_->Error(DiagMessage(element_source) + << "<item> within an <overlayable> must be inside a <policy> block"); + error = true; + continue; + } + // Items specify the name and type of resource that should be overlayable Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name"); if (!item_name) { @@ -1169,6 +1176,8 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource current_policies |= OverlayableItem::Policy::kSystem; } else if (trimmed_part == "vendor") { current_policies |= OverlayableItem::Policy::kVendor; + } else if (trimmed_part == "signature") { + current_policies |= OverlayableItem::Policy::kSignature; } else { diag_->Error(DiagMessage(element_source) << "<policy> has unsupported type '" << trimmed_part << "'"); @@ -1176,6 +1185,11 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource continue; } } + } else { + diag_->Error(DiagMessage(element_source) + << "<policy> must have a 'type' attribute"); + error = true; + continue; } } else if (!ShouldIgnoreElement(element_namespace, element_name)) { diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> " diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 827c7deaf452..25b76b0c1fa0 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -894,8 +894,10 @@ TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) { TEST_F(ResourceParserTest, ParseOverlayable) { std::string input = R"( <overlayable name="Name" actor="overlay://theme"> - <item type="string" name="foo" /> - <item type="drawable" name="bar" /> + <policy type="signature"> + <item type="string" name="foo" /> + <item type="drawable" name="bar" /> + </policy> </overlayable>)"; ASSERT_TRUE(TestParse(input)); @@ -906,7 +908,7 @@ TEST_F(ResourceParserTest, ParseOverlayable) { OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); + EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar")); ASSERT_TRUE(search_result); @@ -915,7 +917,7 @@ TEST_F(ResourceParserTest, ParseOverlayable) { result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); + EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); } TEST_F(ResourceParserTest, ParseOverlayableRequiresName) { @@ -931,7 +933,6 @@ TEST_F(ResourceParserTest, ParseOverlayableBadActorFail) { TEST_F(ResourceParserTest, ParseOverlayablePolicy) { std::string input = R"( <overlayable name="Name"> - <item type="string" name="foo" /> <policy type="product"> <item type="string" name="bar" /> </policy> @@ -944,23 +945,18 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { <policy type="public"> <item type="string" name="faz" /> </policy> + <policy type="signature"> + <item type="string" name="foz" /> + </policy> </overlayable>)"; ASSERT_TRUE(TestParse(input)); - auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo")); + auto search_result = table_.FindResource(test::ParseNameOrDie("string/bar")); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); - - search_result = table_.FindResource(test::ParseNameOrDie("string/bar")); - ASSERT_TRUE(search_result); - ASSERT_THAT(search_result.value().entry, NotNull()); - ASSERT_TRUE(search_result.value().entry->overlayable_item); - result_overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct)); search_result = table_.FindResource(test::ParseNameOrDie("string/fiz")); @@ -986,6 +982,30 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/foz")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); + EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); +} + +TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) { + std::string input = R"( + <overlayable name="Name"> + <item type="string" name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable name="Name"> + <policy> + <item name="foo" /> + </policy> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); } TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) { diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index 7ca99ea42b50..32dfd260e53c 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -92,6 +92,9 @@ struct OverlayableItem { // The resource can be overlaid by any overlay on the product partition. kProduct = 0x08, + + // The resource can be overlaid by any overlay signed with the same signature as its actor. + kSignature = 0x010, }; std::shared_ptr<Overlayable> overlayable; diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index ab4805f626a5..0032960ff93e 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -727,7 +727,7 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config // This must be a FileReference. std::unique_ptr<FileReference> file_ref = util::make_unique<FileReference>(dst_pool->MakeRef( - str, StringPool::Context(StringPool::Context::kHighPriority, config), data)); + str, StringPool::Context(StringPool::Context::kHighPriority, config))); if (type == ResourceType::kRaw) { file_ref->type = ResourceFile::Type::kUnknown; } else if (util::EndsWith(*file_ref->path, ".xml")) { @@ -739,7 +739,7 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config } // There are no styles associated with this string, so treat it as a simple string. - return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config), data)); + return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config))); } } break; diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 9a1d94288363..a2fd7c664b04 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -138,10 +138,10 @@ message AllowNew { // Represents a set of overlayable resources. message Overlayable { - // The name of the <overlyabale>. + // The name of the <overlayable>. string name = 1; - // The location of the <overlyabale> declaration in the source. + // The location of the <overlayable> declaration in the source. Source source = 2; // The component responsible for enabling and disabling overlays targeting this <overlayable>. diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp index a8c26668b3a5..8eabd3225d87 100644 --- a/tools/aapt2/StringPool.cpp +++ b/tools/aapt2/StringPool.cpp @@ -165,13 +165,12 @@ StringPool::Ref StringPool::MakeRef(const StringPiece& str) { return MakeRefImpl(str, Context{}, true); } -StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context, - Maybe<size_t> index) { - return MakeRefImpl(str, context, true, index); +StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context) { + return MakeRefImpl(str, context, true); } StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str, const Context& context, - bool unique, Maybe<size_t> index) { + bool unique) { if (unique) { auto range = indexed_strings_.equal_range(str); for (auto iter = range.first; iter != range.second; ++iter) { @@ -181,26 +180,15 @@ StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str, const Context& c } } - const size_t size = strings_.size(); - // Insert the string at the end of the string vector if no index is specified - const size_t insertion_index = index ? index.value() : size; - std::unique_ptr<Entry> entry(new Entry()); entry->value = str.to_string(); entry->context = context; - entry->index_ = insertion_index; + entry->index_ = strings_.size(); entry->ref_ = 0; entry->pool_ = this; Entry* borrow = entry.get(); - if (insertion_index == size) { - strings_.emplace_back(std::move(entry)); - } else { - // Allocate enough space for the string at the index - strings_.resize(std::max(insertion_index + 1, size)); - strings_[insertion_index] = std::move(entry); - } - + strings_.emplace_back(std::move(entry)); indexed_strings_.insert(std::make_pair(StringPiece(borrow->value), borrow)); return Ref(borrow); } diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h index 115d5d315b8f..1006ca970dc5 100644 --- a/tools/aapt2/StringPool.h +++ b/tools/aapt2/StringPool.h @@ -166,8 +166,7 @@ class StringPool { // Adds a string to the pool, unless it already exists, with a context object that can be used // when sorting the string pool. Returns a reference to the string in the pool. - Ref MakeRef(const android::StringPiece& str, const Context& context, - Maybe<size_t> index = {}); + Ref MakeRef(const android::StringPiece& str, const Context& context); // Adds a string from another string pool. Returns a reference to the string in the string pool. Ref MakeRef(const Ref& ref); @@ -211,8 +210,7 @@ class StringPool { static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag); - Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique, - Maybe<size_t> index = {}); + Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique); void ReAssignIndices(); std::vector<std::unique_ptr<Entry>> strings_; diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp index 648be7d33754..9a7238b584ba 100644 --- a/tools/aapt2/StringPool_test.cpp +++ b/tools/aapt2/StringPool_test.cpp @@ -84,24 +84,6 @@ TEST(StringPoolTest, MaintainInsertionOrderIndex) { EXPECT_THAT(ref_c.index(), Eq(2u)); } -TEST(StringPoolTest, AssignStringIndex) { - StringPool pool; - - StringPool::Ref ref_a = pool.MakeRef("0", StringPool::Context{}, 0u); - StringPool::Ref ref_b = pool.MakeRef("1", StringPool::Context{}, 1u); - StringPool::Ref ref_c = pool.MakeRef("5", StringPool::Context{}, 5u); - StringPool::Ref ref_d = pool.MakeRef("2", StringPool::Context{}, 2u); - StringPool::Ref ref_e = pool.MakeRef("4", StringPool::Context{}, 4u); - StringPool::Ref ref_f = pool.MakeRef("3", StringPool::Context{}, 3u); - - EXPECT_THAT(ref_a.index(), Eq(0u)); - EXPECT_THAT(ref_b.index(), Eq(1u)); - EXPECT_THAT(ref_d.index(), Eq(2u)); - EXPECT_THAT(ref_f.index(), Eq(3u)); - EXPECT_THAT(ref_e.index(), Eq(4u)); - EXPECT_THAT(ref_c.index(), Eq(5u)); -} - TEST(StringPoolTest, PruneStringsWithNoReferences) { StringPool pool; diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp index 7a74ba925ba0..0cf86ccdd59f 100644 --- a/tools/aapt2/cmd/Convert.cpp +++ b/tools/aapt2/cmd/Convert.cpp @@ -43,7 +43,8 @@ namespace aapt { class IApkSerializer { public: - IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {} + IApkSerializer(IAaptContext* context, const Source& source) : context_(context), + source_(source) {} virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16, IArchiveWriter* writer, uint32_t compression_flags) = 0; @@ -167,7 +168,7 @@ class ProtoApkSerializer : public IApkSerializer { std::unique_ptr<io::IData> data = file->file->OpenAsData(); if (!data) { context_->GetDiagnostics()->Error(DiagMessage(source_) - << "failed to open file " << *file->path); + << "failed to open file " << *file->path); return false; } @@ -175,7 +176,7 @@ class ProtoApkSerializer : public IApkSerializer { std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error); if (xml == nullptr) { context_->GetDiagnostics()->Error(DiagMessage(source_) << "failed to parse binary XML: " - << error); + << error); return false; } @@ -256,9 +257,6 @@ class Context : public IAaptContext { int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer, ApkFormat output_format, TableFlattenerOptions table_flattener_options, XmlFlattenerOptions xml_flattener_options) { - // Do not change the ordering of strings in the values string pool - table_flattener_options.sort_stringpool_entries = false; - unique_ptr<IApkSerializer> serializer; if (output_format == ApkFormat::kBinary) { serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), table_flattener_options, @@ -274,7 +272,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath); if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, output_writer, (manifest != nullptr && manifest->WasCompressed()) - ? ArchiveEntry::kCompress : 0u)) { + ? ArchiveEntry::kCompress : 0u)) { context->GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "failed to serialize AndroidManifest.xml"); return 1; @@ -303,8 +301,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer if (files_written.insert(*file->path).second) { if (!serializer->SerializeFile(file, output_writer)) { context->GetDiagnostics()->Error(DiagMessage(apk->GetSource()) - << "failed to serialize file " - << *file->path); + << "failed to serialize file " << *file->path); return 1; } } @@ -338,7 +335,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer if (!io::CopyFileToArchivePreserveCompression(context, file, path, output_writer)) { context->GetDiagnostics()->Error(DiagMessage(apk->GetSource()) - << "failed to copy file " << path); + << "failed to copy file " << path); return 1; } } diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 8463046a80eb..4961aa51dc16 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -400,7 +400,8 @@ static bool IsTransitionElement(const std::string& name) { static bool IsVectorElement(const std::string& name) { return name == "vector" || name == "animated-vector" || name == "pathInterpolator" || - name == "objectAnimator" || name == "gradient" || name == "animated-selector"; + name == "objectAnimator" || name == "gradient" || name == "animated-selector" || + name == "set"; } template <typename T> diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index 40aaa05c2b30..59eb9ec2d418 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -401,7 +401,6 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, if (entry->flags & ResTable_entry::FLAG_PUBLIC) { Visibility visibility; visibility.level = Visibility::Level::kPublic; - visibility.source = source_.WithLine(0); if (!table_->SetVisibilityWithIdMangled(name, visibility, res_id, diag_)) { return false; } @@ -448,7 +447,6 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { arraysize(header->name))); overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor, arraysize(header->name))); - overlayable->source = source_.WithLine(0); ResChunkPullParser parser(GetChunkData(chunk), GetChunkDataLen(chunk)); @@ -473,6 +471,10 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) { policies |= OverlayableItem::Policy::kProduct; } + if (policy_header->policy_flags + & ResTable_overlayable_policy_header::POLICY_SIGNATURE) { + policies |= OverlayableItem::Policy::kSignature; + } const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>( ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize)); @@ -491,7 +493,6 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { } OverlayableItem overlayable_item(overlayable); - overlayable_item.source = source_.WithLine(0); overlayable_item.policies = policies; if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) { return false; diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 9d341cc1ca4a..d677317dc98d 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -274,7 +274,9 @@ class PackageFlattener { FlattenLibrarySpec(buffer); } - FlattenOverlayable(buffer); + if (!FlattenOverlayable(buffer)) { + return false; + } pkg_writer.Finish(); return true; @@ -468,23 +470,29 @@ class PackageFlattener { overlayable_chunk = &chunk; } + if (item.policies == 0) { + context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source) + << "overlayable " + << entry->name + << " does not specify policy"); + return false; + } + uint32_t policy_flags = 0; - if (item.policies == OverlayableItem::Policy::kNone) { - // Encode overlayable entries defined without a policy as publicly overlayable + if (item.policies & OverlayableItem::Policy::kPublic) { policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } else { - if (item.policies & OverlayableItem::Policy::kPublic) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - if (item.policies & OverlayableItem::Policy::kSystem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kVendor) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kProduct) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; - } + } + if (item.policies & OverlayableItem::Policy::kSystem) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kVendor) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kProduct) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kSignature) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE; } auto policy = overlayable_chunk->policy_ids.find(policy_flags); @@ -702,17 +710,15 @@ class PackageFlattener { } // namespace bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { - if (options_.sort_stringpool_entries) { - // We must do this before writing the resources, since the string pool IDs may change. - table->string_pool.Prune(); - table->string_pool.Sort([](const StringPool::Context &a, const StringPool::Context &b) -> int { - int diff = util::compare(a.priority, b.priority); - if (diff == 0) { - diff = a.config.compare(b.config); - } - return diff; - }); - } + // We must do this before writing the resources, since the string pool IDs may change. + table->string_pool.Prune(); + table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int { + int diff = util::compare(a.priority, b.priority); + if (diff == 0) { + diff = a.config.compare(b.config); + } + return diff; + }); // Write the ResTable header. ChunkWriter table_writer(buffer_); diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h index 71330e3fb74f..73c17295556b 100644 --- a/tools/aapt2/format/binary/TableFlattener.h +++ b/tools/aapt2/format/binary/TableFlattener.h @@ -44,9 +44,6 @@ struct TableFlattenerOptions { // Set of whitelisted resource names to avoid altering in key stringpool std::set<std::string> whitelisted_resources; - // When true, sort the entries in the values string pool by priority and configuration. - bool sort_stringpool_entries = true; - // Map from original resource paths to shortened resource paths. std::map<std::string, std::string> shortened_path_map; }; diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index ddc117399390..4c5dbec8ade8 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -671,9 +671,6 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; - std::string name_three = "com.app.test:integer/overlayable_three_item"; - OverlayableItem overlayable_item_three(overlayable); - std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) @@ -683,8 +680,6 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { .SetOverlayable(name_one, overlayable_item_one) .AddSimple(name_two, ResourceId(0x7f020002)) .SetOverlayable(name_two, overlayable_item_two) - .AddSimple(name_three, ResourceId(0x7f020003)) - .SetOverlayable(name_three, overlayable_item_three) .Build(); ResourceTable output_table; @@ -713,16 +708,6 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem | OverlayableItem::Policy::kProduct | OverlayableItem::Policy::kVendor); - - search_result = output_table.FindResource(test::ParseNameOrDie(name_three)); - ASSERT_TRUE(search_result); - ASSERT_THAT(search_result.value().entry, NotNull()); - ASSERT_TRUE(search_result.value().entry->overlayable_item); - overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); - EXPECT_EQ(overlayable_item.overlayable->name, "TestName"); - EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme"); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); } TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { @@ -745,6 +730,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { std::string name_three = "com.app.test:integer/overlayable_three"; OverlayableItem overlayable_item_three(group_one); + overlayable_item_three.policies |= OverlayableItem::Policy::kSignature; + std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) @@ -793,7 +780,22 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSignature); +} + +TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { + auto group = std::make_shared<Overlayable>("TestName", "overlay://theme"); + std::string name_zero = "com.app.test:integer/overlayable_zero"; + OverlayableItem overlayable_item_zero(group); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .SetPackageId("com.app.test", 0x7f) + .AddSimple(name_zero, ResourceId(0x7f020000)) + .SetOverlayable(name_zero, overlayable_item_zero) + .Build(); + ResourceTable output_table; + ASSERT_FALSE(Flatten(context_.get(), {}, table.get(), &output_table)); } } // namespace aapt diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index aff1b391f861..06f1bf74d7e7 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -390,6 +390,9 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, case pb::OverlayableItem::PRODUCT: out_overlayable->policies |= OverlayableItem::Policy::kProduct; break; + case pb::OverlayableItem::SIGNATURE: + out_overlayable->policies |= OverlayableItem::Policy::kSignature; + break; default: *out_error = "unknown overlayable policy"; return false; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index b549e2369f98..eb2b1a2f35d3 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -309,6 +309,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item if (overlayable_item.policies & OverlayableItem::Policy::kVendor) { pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR); } + if (overlayable_item.policies & OverlayableItem::Policy::kSignature) { + pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE); + } SerializeSourceToPb(overlayable_item.source, source_pool, pb_overlayable_item->mutable_source()); diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index cce3939704cf..d369ac4c8816 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -526,6 +526,10 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { "FontPack", "overlay://theme")); overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic; + OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>( + "IconPack", "overlay://theme")); + overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature; + OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>( "Other", "overlay://customization")); overlayable_item_biz.comment ="comment"; @@ -536,6 +540,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { .SetOverlayable("com.app.a:bool/foo", overlayable_item_foo) .SetOverlayable("com.app.a:bool/bar", overlayable_item_bar) .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz) + .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz) .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz) .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true")) .Build(); @@ -576,6 +581,14 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic)); + search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz")); + ASSERT_TRUE(search_result); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack")); + EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); + EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); + search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz")); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java index 72e57a16712b..8a1b21c990c7 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java @@ -67,7 +67,7 @@ public class WifiP2pGroup implements Parcelable { /** The network id in the wpa_supplicant */ private int mNetId; - /** The frequency used by this group */ + /** The frequency (in MHz) used by this group */ private int mFrequency; /** P2P group started string pattern */ @@ -273,7 +273,7 @@ public class WifiP2pGroup implements Parcelable { this.mNetId = netId; } - /** Get the operating frequency of the p2p group */ + /** Get the operating frequency (in MHz) of the p2p group */ public int getFrequency() { return mFrequency; } |