Merge "Keep ringer changes in priority only dnd"
diff --git a/Android.bp b/Android.bp
index ea1ed91..1b9210c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -498,7 +498,7 @@
"telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl",
"telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl",
"telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl",
- "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
+ "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl",
@@ -683,7 +683,8 @@
// Loaded with System.loadLibrary by android.view.textclassifier
required: [
"libtextclassifier",
- "libmedia2_jni",],
+ "libmedia2_jni",
+ ],
javac_shard_size: 150,
@@ -833,7 +834,7 @@
" -I . " +
" $(in)",
- output_extension = "proto.h",
+ output_extension: "proto.h",
}
subdirs = [
diff --git a/Android.mk b/Android.mk
index 58e21ff..c4fffc89 100644
--- a/Android.mk
+++ b/Android.mk
@@ -143,7 +143,6 @@
bouncycastle \
okhttp \
ext \
- icu4j \
framework \
voip-common \
@@ -195,6 +194,7 @@
-since $(SRC_API_DIR)/25.txt 25 \
-since $(SRC_API_DIR)/26.txt 26 \
-since $(SRC_API_DIR)/27.txt 27 \
+ -since ./frameworks/base/api/current.txt P \
-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
-overview $(LOCAL_PATH)/core/java/overview.html \
@@ -664,6 +664,7 @@
-toroot / \
-hdf android.whichdoc online \
-devsite \
+ -yamlV2 \
$(sample_groups) \
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index b7b87dd..6156a0c 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -16,6 +16,7 @@
LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_PACKAGE_NAME := CorePerfTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JNI_SHARED_LIBRARIES := libperftestscore_jni
diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk
index 2db0dd6..a803369 100644
--- a/apct-tests/perftests/multiuser/Android.mk
+++ b/apct-tests/perftests/multiuser/Android.mk
@@ -24,6 +24,7 @@
ub-uiautomator
LOCAL_PACKAGE_NAME := MultiUserPerfTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
diff --git a/api/current.txt b/api/current.txt
index 573e635..e9902b1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1378,6 +1378,7 @@
field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e
field public static final int textEditSuggestionItemLayout = 16843636; // 0x1010374
field public static final int textFilterEnabled = 16843007; // 0x10100ff
+ field public static final int textFontWeight = 16844166; // 0x1010586
field public static final int textIsSelectable = 16843542; // 0x1010316
field public static final int textOff = 16843045; // 0x1010125
field public static final int textOn = 16843044; // 0x1010124
@@ -1548,6 +1549,7 @@
field public static final int windowHideAnimation = 16842935; // 0x10100b7
field public static final int windowIsFloating = 16842839; // 0x1010057
field public static final int windowIsTranslucent = 16842840; // 0x1010058
+ field public static final int windowLayoutInDisplayCutoutMode = 16844167; // 0x1010587
field public static final int windowLightNavigationBar = 16844140; // 0x101056c
field public static final int windowLightStatusBar = 16844000; // 0x10104e0
field public static final int windowMinWidthMajor = 16843606; // 0x1010356
@@ -3882,6 +3884,7 @@
method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
+ method public boolean isBackgroundRestricted();
method public deprecated boolean isInLockTaskMode();
method public boolean isLowRamDevice();
method public static boolean isRunningInTestHarness();
@@ -6702,11 +6705,6 @@
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
- field public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; // 0x4
- field public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; // 0x2
- field public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; // 0x3
- field public static final int USER_OPERATION_ERROR_UNKNOWN = 1; // 0x1
- field public static final int USER_OPERATION_SUCCESS = 0; // 0x0
field public static final int WIPE_EUICC = 4; // 0x4
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
@@ -8972,6 +8970,7 @@
public class ClipboardManager extends android.text.ClipboardManager {
method public void addPrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener);
+ method public void clearPrimaryClip();
method public android.content.ClipData getPrimaryClip();
method public android.content.ClipDescription getPrimaryClipDescription();
method public deprecated java.lang.CharSequence getText();
@@ -13595,7 +13594,7 @@
}
public class EmbossMaskFilter extends android.graphics.MaskFilter {
- ctor public EmbossMaskFilter(float[], float, float, float);
+ ctor public deprecated EmbossMaskFilter(float[], float, float, float);
}
public final class ImageDecoder implements java.lang.AutoCloseable {
@@ -13608,16 +13607,16 @@
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source) throws java.io.IOException;
method public android.util.Size getSampledSize(int);
- method public void setAllocator(int);
- method public void setAsAlphaMask(boolean);
- method public void setCrop(android.graphics.Rect);
- method public void setMutable(boolean);
- method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
- method public void setPostProcessor(android.graphics.PostProcessor);
- method public void setPreferRamOverQuality(boolean);
- method public void setRequireUnpremultiplied(boolean);
- method public void setResize(int, int);
- method public void setResize(int);
+ method public android.graphics.ImageDecoder setAllocator(int);
+ method public android.graphics.ImageDecoder setAsAlphaMask(boolean);
+ method public android.graphics.ImageDecoder setConserveMemory(boolean);
+ method public android.graphics.ImageDecoder setCrop(android.graphics.Rect);
+ method public android.graphics.ImageDecoder setMutable(boolean);
+ method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
+ method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
+ method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
+ method public android.graphics.ImageDecoder setResize(int, int);
+ method public android.graphics.ImageDecoder setResize(int);
field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
@@ -14819,6 +14818,10 @@
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
+ method public int getResId();
+ method public java.lang.String getResPackage();
+ method public int getType();
+ method public android.net.Uri getUri();
method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
method public void loadDrawableAsync(android.content.Context, android.os.Message);
method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
@@ -14827,6 +14830,11 @@
method public android.graphics.drawable.Icon setTintMode(android.graphics.PorterDuff.Mode);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR;
+ field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+ field public static final int TYPE_BITMAP = 1; // 0x1
+ field public static final int TYPE_DATA = 3; // 0x3
+ field public static final int TYPE_RESOURCE = 2; // 0x2
+ field public static final int TYPE_URI = 4; // 0x4
}
public static abstract interface Icon.OnDrawableLoadedListener {
@@ -22520,8 +22528,8 @@
method public java.io.FileDescriptor getFileDescriptor();
method public long getFileDescriptorLength();
method public long getFileDescriptorOffset();
- method public long getId();
method public android.media.Media2DataSource getMedia2DataSource();
+ method public java.lang.String getMediaId();
method public long getStartPosition();
method public int getType();
method public android.net.Uri getUri();
@@ -22545,7 +22553,7 @@
method public android.media.DataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri);
method public android.media.DataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>, java.util.List<java.net.HttpCookie>);
method public android.media.DataSourceDesc.Builder setEndPosition(long);
- method public android.media.DataSourceDesc.Builder setId(long);
+ method public android.media.DataSourceDesc.Builder setMediaId(java.lang.String);
method public android.media.DataSourceDesc.Builder setStartPosition(long);
}
@@ -22750,6 +22758,7 @@
method public abstract void close();
method public android.graphics.Rect getCropRect();
method public abstract int getFormat();
+ method public android.hardware.HardwareBuffer getHardwareBuffer();
method public abstract int getHeight();
method public abstract android.media.Image.Plane[] getPlanes();
method public abstract long getTimestamp();
@@ -22842,6 +22851,27 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
+ public class MediaBrowser2 extends android.media.MediaController2 {
+ ctor public MediaBrowser2(android.content.Context, android.media.SessionToken2, java.util.concurrent.Executor, android.media.MediaBrowser2.BrowserCallback);
+ method public void getChildren(java.lang.String, int, int, android.os.Bundle);
+ method public void getItem(java.lang.String);
+ method public void getLibraryRoot(android.os.Bundle);
+ method public void getSearchResult(java.lang.String, int, int, android.os.Bundle);
+ method public void search(java.lang.String, android.os.Bundle);
+ method public void subscribe(java.lang.String, android.os.Bundle);
+ method public void unsubscribe(java.lang.String);
+ }
+
+ public static class MediaBrowser2.BrowserCallback extends android.media.MediaController2.ControllerCallback {
+ ctor public MediaBrowser2.BrowserCallback();
+ method public void onChildrenChanged(java.lang.String, int, android.os.Bundle);
+ method public void onGetChildrenDone(java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
+ method public void onGetItemDone(java.lang.String, android.media.MediaItem2);
+ method public void onGetLibraryRootDone(android.os.Bundle, java.lang.String, android.os.Bundle);
+ method public void onGetSearchResultDone(java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
+ method public void onSearchResultChanged(java.lang.String, int, android.os.Bundle);
+ }
+
public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
method public void close();
@@ -23318,6 +23348,75 @@
field public static final int REGULAR_CODECS = 0; // 0x0
}
+ public class MediaController2 implements java.lang.AutoCloseable android.media.MediaPlaylistController {
+ ctor public MediaController2(android.content.Context, android.media.SessionToken2, java.util.concurrent.Executor, android.media.MediaController2.ControllerCallback);
+ method public void addPlaylistItem(int, android.media.MediaItem2);
+ method public void adjustVolume(int, int);
+ method public void close();
+ method public void fastForward();
+ method public long getBufferedPosition();
+ method public android.media.MediaItem2 getCurrentPlaylistItem();
+ method public android.media.MediaController2.PlaybackInfo getPlaybackInfo();
+ method public float getPlaybackSpeed();
+ method public int getPlayerState();
+ method public java.util.List<android.media.MediaItem2> getPlaylist();
+ method public android.media.MediaSession2.PlaylistParams getPlaylistParams();
+ method public long getPosition();
+ method public android.app.PendingIntent getSessionActivity();
+ method public android.media.SessionToken2 getSessionToken();
+ method public boolean isConnected();
+ method public void pause();
+ method public void play();
+ method public void playFromMediaId(java.lang.String, android.os.Bundle);
+ method public void playFromSearch(java.lang.String, android.os.Bundle);
+ method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
+ method public void removePlaylistItem(android.media.MediaItem2);
+ method public void replacePlaylistItem(int, android.media.MediaItem2);
+ method public void rewind();
+ method public void seekTo(long);
+ method public void sendCustomCommand(android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
+ method public void setPlaybackSpeed(float);
+ method public void setPlaylistParams(android.media.MediaSession2.PlaylistParams);
+ method public void setRating(java.lang.String, android.media.Rating2);
+ method public void setVolumeTo(int, int);
+ method public void skipToNext();
+ method public void skipToPlaylistItem(android.media.MediaItem2);
+ method public void skipToPrevious();
+ method public void stop();
+ }
+
+ public static abstract class MediaController2.ControllerCallback {
+ ctor public MediaController2.ControllerCallback();
+ method public void onAllowedCommandsChanged(android.media.MediaSession2.CommandGroup);
+ method public void onBufferedPositionChanged(long);
+ method public void onConnected(android.media.MediaSession2.CommandGroup);
+ method public void onCurrentPlaylistItemChanged(android.media.MediaItem2);
+ method public void onCustomCommand(android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
+ method public void onCustomLayoutChanged(java.util.List<android.media.MediaSession2.CommandButton>);
+ method public void onDisconnected();
+ method public void onError(int, android.os.Bundle);
+ method public void onPlaybackInfoChanged(android.media.MediaController2.PlaybackInfo);
+ method public void onPlaybackSpeedChanged(float);
+ method public void onPlayerStateChanged(int);
+ method public void onPlaylistChanged(java.util.List<android.media.MediaItem2>);
+ method public void onPlaylistParamsChanged(android.media.MediaSession2.PlaylistParams);
+ method public void onPositionChanged(long, long);
+ }
+
+ public static final class MediaController2.PlaybackInfo {
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public int getControlType();
+ method public int getCurrentVolume();
+ method public int getMaxVolume();
+ method public int getPlaybackType();
+ field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+ field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+ }
+
public final class MediaCrypto {
ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
method protected void finalize();
@@ -23344,6 +23443,11 @@
method protected void finalize();
method public boolean requiresSecureDecoderComponent(java.lang.String);
method public void setMediaCasSession(android.media.MediaCas.Session);
+ field public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2; // 0x2
+ field public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3; // 0x3
+ field public static final byte SCRAMBLE_CONTROL_RESERVED = 1; // 0x1
+ field public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0; // 0x0
+ field public static final byte SCRAMBLE_FLAG_PES_HEADER = 1; // 0x1
}
public class MediaDescription implements android.os.Parcelable {
@@ -23713,6 +23817,71 @@
field public static final java.lang.String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
}
+ public class MediaItem2 {
+ method public static android.media.MediaItem2 fromBundle(android.content.Context, android.os.Bundle);
+ method public android.media.DataSourceDesc getDataSourceDesc();
+ method public int getFlags();
+ method public java.lang.String getMediaId();
+ method public android.media.MediaMetadata2 getMetadata();
+ method public boolean isBrowsable();
+ method public boolean isPlayable();
+ method public void setMetadata(android.media.MediaMetadata2);
+ method public android.os.Bundle toBundle();
+ field public static final int FLAG_BROWSABLE = 1; // 0x1
+ field public static final int FLAG_PLAYABLE = 2; // 0x2
+ }
+
+ public static final class MediaItem2.Builder {
+ ctor public MediaItem2.Builder(android.content.Context, int);
+ method public android.media.MediaItem2 build();
+ method public android.media.MediaItem2.Builder setDataSourceDesc(android.media.DataSourceDesc);
+ method public android.media.MediaItem2.Builder setMediaId(java.lang.String);
+ method public android.media.MediaItem2.Builder setMetadata(android.media.MediaMetadata2);
+ }
+
+ public abstract class MediaLibraryService2 extends android.media.MediaSessionService2 {
+ ctor public MediaLibraryService2();
+ method public abstract android.media.MediaLibraryService2.MediaLibrarySession onCreateSession(java.lang.String);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaLibraryService2";
+ }
+
+ public static final class MediaLibraryService2.LibraryRoot {
+ ctor public MediaLibraryService2.LibraryRoot(android.content.Context, java.lang.String, android.os.Bundle);
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getRootId();
+ field public static final java.lang.String EXTRA_OFFLINE = "android.media.extra.OFFLINE";
+ field public static final java.lang.String EXTRA_RECENT = "android.media.extra.RECENT";
+ field public static final java.lang.String EXTRA_SUGGESTED = "android.media.extra.SUGGESTED";
+ }
+
+ public static final class MediaLibraryService2.MediaLibrarySession extends android.media.MediaSession2 {
+ method public void notifyChildrenChanged(android.media.MediaSession2.ControllerInfo, java.lang.String, int, android.os.Bundle);
+ method public void notifyChildrenChanged(java.lang.String, int, android.os.Bundle);
+ method public void notifySearchResultChanged(android.media.MediaSession2.ControllerInfo, java.lang.String, int, android.os.Bundle);
+ }
+
+ public static final class MediaLibraryService2.MediaLibrarySession.Builder {
+ ctor public MediaLibraryService2.MediaLibrarySession.Builder(android.media.MediaLibraryService2, java.util.concurrent.Executor, android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback);
+ method public android.media.MediaLibraryService2.MediaLibrarySession build();
+ method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setId(java.lang.String);
+ method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setPlayer(android.media.MediaPlayerBase);
+ method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setPlaylistController(android.media.MediaPlaylistController);
+ method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setSessionActivity(android.app.PendingIntent);
+ method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setSessionCallback(java.util.concurrent.Executor, android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback);
+ method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setVolumeProvider(android.media.VolumeProvider2);
+ }
+
+ public static class MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback extends android.media.MediaSession2.SessionCallback {
+ ctor public MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback(android.content.Context);
+ method public java.util.List<android.media.MediaItem2> onGetChildren(android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
+ method public android.media.MediaItem2 onGetItem(android.media.MediaSession2.ControllerInfo, java.lang.String);
+ method public android.media.MediaLibraryService2.LibraryRoot onGetLibraryRoot(android.media.MediaSession2.ControllerInfo, android.os.Bundle);
+ method public java.util.List<android.media.MediaItem2> onGetSearchResult(android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
+ method public void onSearch(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onSubscribe(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onUnsubscribe(android.media.MediaSession2.ControllerInfo, java.lang.String);
+ }
+
public final class MediaMetadata implements android.os.Parcelable {
method public boolean containsKey(java.lang.String);
method public int describeContents();
@@ -23768,6 +23937,79 @@
method public android.media.MediaMetadata.Builder putText(java.lang.String, java.lang.CharSequence);
}
+ public final class MediaMetadata2 {
+ method public boolean containsKey(java.lang.String);
+ method public static android.media.MediaMetadata2 fromBundle(android.content.Context, android.os.Bundle);
+ method public android.graphics.Bitmap getBitmap(java.lang.String);
+ method public android.os.Bundle getExtras();
+ method public float getFloat(java.lang.String);
+ method public long getLong(java.lang.String);
+ method public java.lang.String getMediaId();
+ method public android.media.Rating2 getRating(java.lang.String);
+ method public java.lang.String getString(java.lang.String);
+ method public java.lang.CharSequence getText(java.lang.String);
+ method public java.util.Set<java.lang.String> keySet();
+ method public int size();
+ method public android.os.Bundle toBundle();
+ field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+ field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+ field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+ field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+ field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+ field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+ field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+ field public static final java.lang.String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+ field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+ field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+ field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+ field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+ field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+ field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+ field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+ field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+ field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+ field public static final java.lang.String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+ field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+ field public static final java.lang.String METADATA_KEY_EXTRAS = "android.media.metadata.EXTRAS";
+ field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+ field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+ field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+ field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+ field public static final java.lang.String METADATA_KEY_RADIO_CALLSIGN = "android.media.metadata.RADIO_CALLSIGN";
+ field public static final java.lang.String METADATA_KEY_RADIO_FREQUENCY = "android.media.metadata.RADIO_FREQUENCY";
+ field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+ field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+ field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+ field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+ field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+ field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+ field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+ field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+ field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+ }
+
+ public static final class MediaMetadata2.Builder {
+ ctor public MediaMetadata2.Builder(android.content.Context);
+ ctor public MediaMetadata2.Builder(android.content.Context, android.media.MediaMetadata2);
+ method public android.media.MediaMetadata2 build();
+ method public android.media.MediaMetadata2.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+ method public android.media.MediaMetadata2.Builder putFloat(java.lang.String, float);
+ method public android.media.MediaMetadata2.Builder putLong(java.lang.String, long);
+ method public android.media.MediaMetadata2.Builder putRating(java.lang.String, android.media.Rating2);
+ method public android.media.MediaMetadata2.Builder putString(java.lang.String, java.lang.String);
+ method public android.media.MediaMetadata2.Builder putText(java.lang.String, java.lang.CharSequence);
+ method public android.media.MediaMetadata2.Builder setExtras(android.os.Bundle);
+ }
+
public abstract deprecated class MediaMetadataEditor {
method public synchronized void addEditableKey(int);
method public abstract void apply();
@@ -24075,68 +24317,79 @@
field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
}
- public abstract class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable {
- method public abstract void addPlaylistItem(int, android.media.DataSourceDesc);
+ public abstract class MediaPlayer2 extends android.media.MediaPlayerBase implements android.media.AudioRouting {
method public abstract void attachAuxEffect(int);
+ method public abstract void clearDrmEventCallback();
+ method public abstract void clearMediaPlayer2EventCallback();
method public abstract void clearPendingCommands();
method public abstract void close();
method public static final android.media.MediaPlayer2 create();
method public abstract void deselectTrack(int);
- method public abstract android.media.DataSourceDesc editPlaylistItem(int, android.media.DataSourceDesc);
- method public abstract android.media.AudioAttributes getAudioAttributes();
method public abstract int getAudioSessionId();
- method public abstract android.media.DataSourceDesc getCurrentDataSource();
- method public abstract int getCurrentPlaylistItemIndex();
+ method public abstract long getBufferedPosition();
method public abstract long getCurrentPosition();
method public abstract android.media.MediaPlayer2.DrmInfo getDrmInfo();
+ method public abstract android.media.MediaDrm.KeyRequest getDrmKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
method public abstract java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException;
method public abstract long getDuration();
- method public abstract android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
- method public abstract int getLoopingMode();
+ method public abstract int getMediaPlayer2State();
method public abstract android.os.PersistableBundle getMetrics();
method public abstract android.media.PlaybackParams getPlaybackParams();
- method public abstract java.util.List<android.media.DataSourceDesc> getPlaylist();
method public abstract int getSelectedTrack(int);
method public abstract android.media.SyncParams getSyncParams();
method public abstract android.media.MediaTimestamp getTimestamp();
method public abstract java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo();
method public abstract int getVideoHeight();
method public abstract int getVideoWidth();
- method public abstract boolean isPlaying();
- method public abstract void movePlaylistItem(int, int);
- method public abstract void pause();
- method public abstract void play();
- method public abstract void prepareAsync();
+ method public void notifyWhenCommandLabelReached(java.lang.Object);
method public abstract void prepareDrm(java.util.UUID) throws android.media.MediaPlayer2.ProvisioningNetworkErrorException, android.media.MediaPlayer2.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
- method public abstract byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer2.NoDrmSchemeException;
- method public abstract void registerDrmEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.DrmEventCallback);
- method public abstract void registerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.EventCallback);
+ method public abstract byte[] provideDrmKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer2.NoDrmSchemeException;
method public abstract void releaseDrm() throws android.media.MediaPlayer2.NoDrmSchemeException;
- method public abstract android.media.DataSourceDesc removePlaylistItem(int);
method public abstract void reset();
- method public abstract void restoreKeys(byte[]) throws android.media.MediaPlayer2.NoDrmSchemeException;
+ method public abstract void restoreDrmKeys(byte[]) throws android.media.MediaPlayer2.NoDrmSchemeException;
+ method public void seekTo(long);
method public abstract void seekTo(long, int);
method public abstract void selectTrack(int);
- method public abstract void setAudioAttributes(android.media.AudioAttributes);
method public abstract void setAudioSessionId(int);
method public abstract void setAuxEffectSendLevel(float);
- method public abstract void setCurrentPlaylistItem(int);
- method public abstract void setDataSource(android.media.DataSourceDesc) throws java.io.IOException;
+ method public abstract void setDrmEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.DrmEventCallback);
method public abstract void setDrmPropertyString(java.lang.String, java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException;
- method public abstract void setLoopingMode(int);
- method public abstract void setNextPlaylistItem(int);
+ method public abstract void setMediaPlayer2EventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.MediaPlayer2EventCallback);
method public abstract void setOnDrmConfigHelper(android.media.MediaPlayer2.OnDrmConfigHelper);
method public abstract void setPlaybackParams(android.media.PlaybackParams);
- method public abstract void setPlaylist(java.util.List<android.media.DataSourceDesc>, int) throws java.io.IOException;
method public abstract void setSurface(android.view.Surface);
method public abstract void setSyncParams(android.media.SyncParams);
- method public abstract void setVolume(float, float);
- method public abstract void unregisterDrmEventCallback(android.media.MediaPlayer2.DrmEventCallback);
- method public abstract void unregisterEventCallback(android.media.MediaPlayer2.EventCallback);
- field public static final int LOOPING_MODE_FULL = 1; // 0x1
- field public static final int LOOPING_MODE_NONE = 0; // 0x0
- field public static final int LOOPING_MODE_SHUFFLE = 3; // 0x3
- field public static final int LOOPING_MODE_SINGLE = 2; // 0x2
+ field public static final int MEDIAPLAYER2_STATE_ERROR = 5; // 0x5
+ field public static final int MEDIAPLAYER2_STATE_IDLE = 1; // 0x1
+ field public static final int MEDIAPLAYER2_STATE_PAUSED = 3; // 0x3
+ field public static final int MEDIAPLAYER2_STATE_PLAYING = 4; // 0x4
+ field public static final int MEDIAPLAYER2_STATE_PREPARED = 2; // 0x2
+ field public static final int MEDIA_CALL_ATTACH_AUX_EFFECT = 1; // 0x1
+ field public static final int MEDIA_CALL_DESELECT_TRACK = 2; // 0x2
+ field public static final int MEDIA_CALL_LOOP_CURRENT = 3; // 0x3
+ field public static final int MEDIA_CALL_PAUSE = 4; // 0x4
+ field public static final int MEDIA_CALL_PLAY = 5; // 0x5
+ field public static final int MEDIA_CALL_PREPARE = 6; // 0x6
+ field public static final int MEDIA_CALL_PREPARE_DRM = 7; // 0x7
+ field public static final int MEDIA_CALL_PROVIDE_DRM_KEY_RESPONSE = 8; // 0x8
+ field public static final int MEDIA_CALL_RELEASE_DRM = 12; // 0xc
+ field public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13; // 0xd
+ field public static final int MEDIA_CALL_SEEK_TO = 14; // 0xe
+ field public static final int MEDIA_CALL_SELECT_TRACK = 15; // 0xf
+ field public static final int MEDIA_CALL_SET_AUDIO_ATTRIBUTES = 16; // 0x10
+ field public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17; // 0x11
+ field public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12
+ field public static final int MEDIA_CALL_SET_DATA_SOURCE = 19; // 0x13
+ field public static final int MEDIA_CALL_SET_DRM_CONFIG_HELPER = 20; // 0x14
+ field public static final int MEDIA_CALL_SET_DRM_PROPERTY_STRING = 21; // 0x15
+ field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22; // 0x16
+ field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23; // 0x17
+ field public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24; // 0x18
+ field public static final int MEDIA_CALL_SET_PLAYBACK_SPEED = 25; // 0x19
+ field public static final int MEDIA_CALL_SET_PLAYER_VOLUME = 26; // 0x1a
+ field public static final int MEDIA_CALL_SET_SURFACE = 27; // 0x1b
+ field public static final int MEDIA_CALL_SET_SYNC_PARAMS = 28; // 0x1c
+ field public static final int MEDIA_CALL_SKIP_TO_NEXT = 29; // 0x1d
field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14
field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11
field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8
@@ -24148,9 +24401,7 @@
field public static final int MEDIA_INFO_BAD_INTERLEAVING = 800; // 0x320
field public static final int MEDIA_INFO_BUFFERING_END = 702; // 0x2be
field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd
- field public static final int MEDIA_INFO_COMPLETE_CALL_PAUSE = 102; // 0x66
- field public static final int MEDIA_INFO_COMPLETE_CALL_PLAY = 101; // 0x65
- field public static final int MEDIA_INFO_COMPLETE_CALL_SEEK = 103; // 0x67
+ field public static final int MEDIA_INFO_BUFFERING_UPDATE = 704; // 0x2c0
field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322
field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321
field public static final int MEDIA_INFO_PLAYBACK_COMPLETE = 5; // 0x5
@@ -24176,8 +24427,8 @@
public static abstract class MediaPlayer2.DrmEventCallback {
ctor public MediaPlayer2.DrmEventCallback();
- method public void onDrmInfo(android.media.MediaPlayer2, long, android.media.MediaPlayer2.DrmInfo);
- method public void onDrmPrepared(android.media.MediaPlayer2, long, int);
+ method public void onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
+ method public void onDrmPrepared(android.media.MediaPlayer2, android.media.DataSourceDesc, int);
}
public static abstract class MediaPlayer2.DrmInfo {
@@ -24186,13 +24437,15 @@
method public abstract java.util.List<java.util.UUID> getSupportedSchemes();
}
- public static abstract class MediaPlayer2.EventCallback {
- ctor public MediaPlayer2.EventCallback();
- method public void onBufferingUpdate(android.media.MediaPlayer2, long, int);
- method public void onError(android.media.MediaPlayer2, long, int, int);
- method public void onInfo(android.media.MediaPlayer2, long, int, int);
- method public void onTimedMetaDataAvailable(android.media.MediaPlayer2, long, android.media.TimedMetaData);
- method public void onVideoSizeChanged(android.media.MediaPlayer2, long, int, int);
+ public static abstract class MediaPlayer2.MediaPlayer2EventCallback {
+ ctor public MediaPlayer2.MediaPlayer2EventCallback();
+ method public void onCallComplete(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+ method public void onCommandLabelReached(android.media.MediaPlayer2, java.lang.Object);
+ method public void onError(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+ method public void onInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+ method public void onMediaTimeChanged(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaTimestamp);
+ method public void onTimedMetaDataAvailable(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.TimedMetaData);
+ method public void onVideoSizeChanged(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
}
public static final class MediaPlayer2.MetricsConstants {
@@ -24215,7 +24468,7 @@
}
public static abstract interface MediaPlayer2.OnDrmConfigHelper {
- method public abstract void onDrmConfig(android.media.MediaPlayer2, long);
+ method public abstract void onDrmConfig(android.media.MediaPlayer2, android.media.DataSourceDesc);
}
public static abstract class MediaPlayer2.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
@@ -24239,6 +24492,61 @@
field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
}
+ public abstract class MediaPlayerBase implements java.lang.AutoCloseable {
+ ctor public MediaPlayerBase();
+ method public abstract android.media.AudioAttributes getAudioAttributes();
+ method public long getBufferedPosition();
+ method public abstract int getBufferingState();
+ method public abstract android.media.DataSourceDesc getCurrentDataSource();
+ method public long getCurrentPosition();
+ method public long getDuration();
+ method public float getMaxPlayerVolume();
+ method public float getPlaybackSpeed();
+ method public abstract int getPlayerState();
+ method public abstract float getPlayerVolume();
+ method public boolean isReversePlaybackSupported();
+ method public abstract void loopCurrent(boolean);
+ method public abstract void pause();
+ method public abstract void play();
+ method public abstract void prepare();
+ method public abstract void registerPlayerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayerBase.PlayerEventCallback);
+ method public abstract void seekTo(long);
+ method public abstract void setAudioAttributes(android.media.AudioAttributes);
+ method public abstract void setDataSource(android.media.DataSourceDesc);
+ method public abstract void setNextDataSource(android.media.DataSourceDesc);
+ method public abstract void setNextDataSources(java.util.List<android.media.DataSourceDesc>);
+ method public abstract void setPlaybackSpeed(float);
+ method public abstract void setPlayerVolume(float);
+ method public abstract void skipToNext();
+ method public abstract void unregisterPlayerEventCallback(android.media.MediaPlayerBase.PlayerEventCallback);
+ field public static final int BUFFERING_STATE_BUFFERING_AND_PLAYABLE = 1; // 0x1
+ field public static final int BUFFERING_STATE_BUFFERING_AND_STARVED = 2; // 0x2
+ field public static final int BUFFERING_STATE_BUFFERING_COMPLETE = 3; // 0x3
+ field public static final int BUFFERING_STATE_UNKNOWN = 0; // 0x0
+ field public static final int PLAYER_STATE_ERROR = 3; // 0x3
+ field public static final int PLAYER_STATE_IDLE = 0; // 0x0
+ field public static final int PLAYER_STATE_PAUSED = 1; // 0x1
+ field public static final int PLAYER_STATE_PLAYING = 2; // 0x2
+ field public static final long UNKNOWN_TIME = -1L; // 0xffffffffffffffffL
+ }
+
+ public static abstract class MediaPlayerBase.PlayerEventCallback {
+ ctor public MediaPlayerBase.PlayerEventCallback();
+ method public void onBufferingStateChanged(android.media.MediaPlayerBase, android.media.DataSourceDesc, int);
+ method public void onCurrentDataSourceChanged(android.media.MediaPlayerBase, android.media.DataSourceDesc);
+ method public void onMediaPrepared(android.media.MediaPlayerBase, android.media.DataSourceDesc);
+ method public void onPlayerStateChanged(android.media.MediaPlayerBase, int);
+ }
+
+ public abstract interface MediaPlaylistController {
+ method public abstract void addPlaylistItem(int, android.media.MediaItem2);
+ method public abstract android.media.MediaItem2 getCurrentPlaylistItem();
+ method public abstract java.util.List<android.media.MediaItem2> getPlaylist();
+ method public abstract void removePlaylistItem(android.media.MediaItem2);
+ method public abstract void replacePlaylistItem(int, android.media.MediaItem2);
+ method public abstract void skipToPlaylistItem(android.media.MediaItem2);
+ }
+
public class MediaRecorder implements android.media.AudioRouting {
ctor public MediaRecorder();
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
@@ -24515,6 +24823,179 @@
method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
}
+ public class MediaSession2 implements java.lang.AutoCloseable android.media.MediaPlaylistController {
+ method public void addPlaylistItem(int, android.media.MediaItem2);
+ method public void close();
+ method public void fastForward();
+ method public java.util.List<android.media.MediaSession2.ControllerInfo> getConnectedControllers();
+ method public android.media.MediaItem2 getCurrentPlaylistItem();
+ method public android.media.MediaPlaylistController getMediaPlaylistController();
+ method public float getPlaybackSpeed();
+ method public android.media.MediaPlayerBase getPlayer();
+ method public java.util.List<android.media.MediaItem2> getPlaylist();
+ method public android.media.MediaSession2.PlaylistParams getPlaylistParams();
+ method public android.media.SessionToken2 getToken();
+ method public android.media.VolumeProvider2 getVolumeProvider();
+ method public void notifyError(int, android.os.Bundle);
+ method public void pause();
+ method public void play();
+ method public void prepare();
+ method public void removePlaylistItem(android.media.MediaItem2);
+ method public void replacePlaylistItem(int, android.media.MediaItem2);
+ method public void rewind();
+ method public void seekTo(long);
+ method public void sendCustomCommand(android.media.MediaSession2.Command, android.os.Bundle);
+ method public void sendCustomCommand(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
+ method public void setAllowedCommands(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.CommandGroup);
+ method public void setAudioFocusRequest(android.media.AudioFocusRequest);
+ method public void setCustomLayout(android.media.MediaSession2.ControllerInfo, java.util.List<android.media.MediaSession2.CommandButton>);
+ method public void setPlaybackSpeed(float);
+ method public void setPlaylist(java.util.List<android.media.MediaItem2>);
+ method public void setPlaylistParams(android.media.MediaSession2.PlaylistParams);
+ method public void skipToNext();
+ method public void skipToPlaylistItem(android.media.MediaItem2);
+ method public void skipToPrevious();
+ method public void stop();
+ method public void updatePlayer(android.media.MediaPlayerBase, android.media.MediaPlaylistController, android.media.VolumeProvider2);
+ field public static final int COMMAND_CODE_BROWSER = 22; // 0x16
+ field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
+ field public static final int COMMAND_CODE_PLAYBACK_FAST_FORWARD = 7; // 0x7
+ field public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2; // 0x2
+ field public static final int COMMAND_CODE_PLAYBACK_PLAY = 1; // 0x1
+ field public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6; // 0x6
+ field public static final int COMMAND_CODE_PLAYBACK_REWIND = 8; // 0x8
+ field public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9; // 0x9
+ field public static final int COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS = 11; // 0xb
+ field public static final int COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM = 4; // 0x4
+ field public static final int COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM = 5; // 0x5
+ field public static final int COMMAND_CODE_PLAYBACK_SKIP_TO_PLAYLIST_ITEM = 10; // 0xa
+ field public static final int COMMAND_CODE_PLAYBACK_STOP = 3; // 0x3
+ field public static final int COMMAND_CODE_PLAYLIST_ADD = 12; // 0xc
+ field public static final int COMMAND_CODE_PLAYLIST_GET = 14; // 0xe
+ field public static final int COMMAND_CODE_PLAYLIST_REMOVE = 13; // 0xd
+ field public static final int COMMAND_CODE_PLAY_FROM_MEDIA_ID = 16; // 0x10
+ field public static final int COMMAND_CODE_PLAY_FROM_SEARCH = 18; // 0x12
+ field public static final int COMMAND_CODE_PLAY_FROM_URI = 17; // 0x11
+ field public static final int COMMAND_CODE_PREPARE_FROM_MEDIA_ID = 19; // 0x13
+ field public static final int COMMAND_CODE_PREPARE_FROM_SEARCH = 21; // 0x15
+ field public static final int COMMAND_CODE_PREPARE_FROM_URI = 20; // 0x14
+ field public static final int COMMAND_CODE_SET_VOLUME = 15; // 0xf
+ field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+ field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+ field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+ field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+ field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+ field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+ field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+ field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+ field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+ field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+ field public static final int ERROR_CODE_SETUP_REQUIRED = 12; // 0xc
+ field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+ field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ public static final class MediaSession2.Builder {
+ ctor public MediaSession2.Builder(android.content.Context);
+ method public android.media.MediaSession2 build();
+ method public android.media.MediaSession2.Builder setId(java.lang.String);
+ method public android.media.MediaSession2.Builder setPlayer(android.media.MediaPlayerBase);
+ method public android.media.MediaSession2.Builder setPlaylistController(android.media.MediaPlaylistController);
+ method public android.media.MediaSession2.Builder setSessionActivity(android.app.PendingIntent);
+ method public android.media.MediaSession2.Builder setSessionCallback(java.util.concurrent.Executor, android.media.MediaSession2.SessionCallback);
+ method public android.media.MediaSession2.Builder setVolumeProvider(android.media.VolumeProvider2);
+ }
+
+ public static final class MediaSession2.Command {
+ ctor public MediaSession2.Command(android.content.Context, int);
+ ctor public MediaSession2.Command(android.content.Context, java.lang.String, android.os.Bundle);
+ method public int getCommandCode();
+ method public java.lang.String getCustomCommand();
+ method public android.os.Bundle getExtras();
+ }
+
+ public static final class MediaSession2.CommandButton {
+ method public android.media.MediaSession2.Command getCommand();
+ method public java.lang.String getDisplayName();
+ method public android.os.Bundle getExtras();
+ method public int getIconResId();
+ method public boolean isEnabled();
+ }
+
+ public static final class MediaSession2.CommandButton.Builder {
+ ctor public MediaSession2.CommandButton.Builder(android.content.Context);
+ method public android.media.MediaSession2.CommandButton build();
+ method public android.media.MediaSession2.CommandButton.Builder setCommand(android.media.MediaSession2.Command);
+ method public android.media.MediaSession2.CommandButton.Builder setDisplayName(java.lang.String);
+ method public android.media.MediaSession2.CommandButton.Builder setEnabled(boolean);
+ method public android.media.MediaSession2.CommandButton.Builder setExtras(android.os.Bundle);
+ method public android.media.MediaSession2.CommandButton.Builder setIconResId(int);
+ }
+
+ public static final class MediaSession2.CommandGroup {
+ ctor public MediaSession2.CommandGroup(android.content.Context);
+ ctor public MediaSession2.CommandGroup(android.content.Context, android.media.MediaSession2.CommandGroup);
+ method public void addAllPredefinedCommands();
+ method public void addCommand(android.media.MediaSession2.Command);
+ method public java.util.List<android.media.MediaSession2.Command> getCommands();
+ method public boolean hasCommand(android.media.MediaSession2.Command);
+ method public boolean hasCommand(int);
+ method public void removeCommand(android.media.MediaSession2.Command);
+ }
+
+ public static final class MediaSession2.ControllerInfo {
+ method public java.lang.String getPackageName();
+ method public int getUid();
+ method public boolean isTrusted();
+ }
+
+ public static final class MediaSession2.PlaylistParams {
+ ctor public MediaSession2.PlaylistParams(android.content.Context, int, int, android.media.MediaMetadata2);
+ method public static android.media.MediaSession2.PlaylistParams fromBundle(android.content.Context, android.os.Bundle);
+ method public android.media.MediaMetadata2 getPlaylistMetadata();
+ method public int getRepeatMode();
+ method public int getShuffleMode();
+ method public android.os.Bundle toBundle();
+ field public static final int REPEAT_MODE_ALL = 2; // 0x2
+ field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+ field public static final int REPEAT_MODE_NONE = 0; // 0x0
+ field public static final int REPEAT_MODE_ONE = 1; // 0x1
+ field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+ field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+ field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+ }
+
+ public static abstract class MediaSession2.SessionCallback {
+ ctor public MediaSession2.SessionCallback(android.content.Context);
+ method public boolean onCommandRequest(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command);
+ method public android.media.MediaSession2.CommandGroup onConnect(android.media.MediaSession2.ControllerInfo);
+ method public void onCustomCommand(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
+ method public void onDisconnected(android.media.MediaSession2.ControllerInfo);
+ method public void onPlayFromMediaId(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPlayFromSearch(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
+ method public void onPrepareFromMediaId(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPrepareFromSearch(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPrepareFromUri(android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
+ method public void onSetRating(android.media.MediaSession2.ControllerInfo, java.lang.String, android.media.Rating2);
+ }
+
+ public abstract class MediaSessionService2 extends android.app.Service {
+ ctor public MediaSessionService2();
+ method public final android.media.MediaSession2 getSession();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.media.MediaSession2 onCreateSession(java.lang.String);
+ method public android.media.MediaSessionService2.MediaNotification onUpdateNotification();
+ field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaSessionService2";
+ field public static final java.lang.String SERVICE_META_DATA = "android.media.session";
+ }
+
+ public static class MediaSessionService2.MediaNotification {
+ ctor public MediaSessionService2.MediaNotification(android.content.Context, int, android.app.Notification);
+ method public android.app.Notification getNotification();
+ method public int getNotificationId();
+ }
+
public final class MediaSync {
ctor public MediaSync();
method public android.view.Surface createInputSurface();
@@ -24645,6 +25126,29 @@
field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
}
+ public final class Rating2 {
+ method public static android.media.Rating2 fromBundle(android.content.Context, android.os.Bundle);
+ method public float getPercentRating();
+ method public int getRatingStyle();
+ method public float getStarRating();
+ method public boolean hasHeart();
+ method public boolean isRated();
+ method public boolean isThumbUp();
+ method public static android.media.Rating2 newHeartRating(android.content.Context, boolean);
+ method public static android.media.Rating2 newPercentageRating(android.content.Context, float);
+ method public static android.media.Rating2 newStarRating(android.content.Context, int, float);
+ method public static android.media.Rating2 newThumbRating(android.content.Context, boolean);
+ method public static android.media.Rating2 newUnratedRating(android.content.Context, int);
+ method public android.os.Bundle toBundle();
+ field public static final int RATING_3_STARS = 3; // 0x3
+ field public static final int RATING_4_STARS = 4; // 0x4
+ field public static final int RATING_5_STARS = 5; // 0x5
+ field public static final int RATING_HEART = 1; // 0x1
+ field public static final int RATING_NONE = 0; // 0x0
+ field public static final int RATING_PERCENTAGE = 6; // 0x6
+ field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+ }
+
public deprecated class RemoteControlClient {
ctor public RemoteControlClient(android.app.PendingIntent);
ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
@@ -24734,10 +25238,14 @@
method public android.media.AudioAttributes getAudioAttributes();
method public deprecated int getStreamType();
method public java.lang.String getTitle(android.content.Context);
+ method public float getVolume();
+ method public boolean isLooping();
method public boolean isPlaying();
method public void play();
method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+ method public void setLooping(boolean);
method public deprecated void setStreamType(int);
+ method public void setVolume(float);
method public void stop();
}
@@ -24780,6 +25288,22 @@
field public static final int URI_COLUMN_INDEX = 2; // 0x2
}
+ public final class SessionToken2 {
+ ctor public SessionToken2(android.content.Context, java.lang.String, java.lang.String);
+ method public static android.media.SessionToken2 fromBundle(android.content.Context, android.os.Bundle);
+ method public java.lang.String getId();
+ method public java.lang.String getPackageName();
+ method public int getType();
+ method public int getUid();
+ method public android.os.Bundle toBundle();
+ field public static final int TYPE_LIBRARY_SERVICE = 2; // 0x2
+ field public static final int TYPE_SESSION = 0; // 0x0
+ field public static final int TYPE_SESSION_SERVICE = 1; // 0x1
+ }
+
+ public static abstract class SessionToken2.TokenType implements java.lang.annotation.Annotation {
+ }
+
public class SoundPool {
ctor public deprecated SoundPool(int, int, int);
method public final void autoPause();
@@ -24983,6 +25507,19 @@
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
+ public abstract class VolumeProvider2 {
+ ctor public VolumeProvider2(android.content.Context, int, int, int);
+ method public final int getControlType();
+ method public final int getCurrentVolume();
+ method public final int getMaxVolume();
+ method public void onAdjustVolume(int);
+ method public void onSetVolumeTo(int);
+ method public final void setCurrentVolume(int);
+ field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+ field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+ field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+ }
+
public final class VolumeShaper implements java.lang.AutoCloseable {
method public void apply(android.media.VolumeShaper.Operation);
method public void close();
@@ -25064,6 +25601,7 @@
field public static final java.util.UUID EFFECT_TYPE_AEC;
field public static final java.util.UUID EFFECT_TYPE_AGC;
field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
+ field public static final java.util.UUID EFFECT_TYPE_DYNAMICS_PROCESSING;
field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB;
field public static final java.util.UUID EFFECT_TYPE_EQUALIZER;
field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER;
@@ -25127,6 +25665,201 @@
field public short strength;
}
+ public final class DynamicsProcessing extends android.media.audiofx.AudioEffect {
+ ctor public DynamicsProcessing(int);
+ ctor public DynamicsProcessing(int, int, android.media.audiofx.DynamicsProcessing.Config);
+ method public android.media.audiofx.DynamicsProcessing.Channel getChannelByChannelIndex(int);
+ method public int getChannelCount();
+ method public android.media.audiofx.DynamicsProcessing.Config getConfig();
+ method public float getInputGainByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.Limiter getLimiterByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.MbcBand getMbcBandByChannelIndex(int, int);
+ method public android.media.audiofx.DynamicsProcessing.Mbc getMbcByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.EqBand getPostEqBandByChannelIndex(int, int);
+ method public android.media.audiofx.DynamicsProcessing.Eq getPostEqByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.EqBand getPreEqBandByChannelIndex(int, int);
+ method public android.media.audiofx.DynamicsProcessing.Eq getPreEqByChannelIndex(int);
+ method public void setAllChannelsTo(android.media.audiofx.DynamicsProcessing.Channel);
+ method public void setChannelTo(int, android.media.audiofx.DynamicsProcessing.Channel);
+ method public void setInputGainAllChannelsTo(float);
+ method public void setInputGainbyChannel(int, float);
+ method public void setLimiterAllChannelsTo(android.media.audiofx.DynamicsProcessing.Limiter);
+ method public void setLimiterByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Limiter);
+ method public void setMbcAllChannelsTo(android.media.audiofx.DynamicsProcessing.Mbc);
+ method public void setMbcBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.MbcBand);
+ method public void setMbcBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.MbcBand);
+ method public void setMbcByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Mbc);
+ method public void setPostEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPostEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPostEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPostEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPreEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPreEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPreEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPreEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq);
+ field public static final int VARIANT_FAVOR_FREQUENCY_RESOLUTION = 0; // 0x0
+ field public static final int VARIANT_FAVOR_TIME_RESOLUTION = 1; // 0x1
+ }
+
+ public static class DynamicsProcessing.BandBase {
+ ctor public DynamicsProcessing.BandBase(boolean, float);
+ method public float getCutoffFrequency();
+ method public boolean isEnabled();
+ method public void setCutoffFrequency(float);
+ method public void setEnabled(boolean);
+ }
+
+ public static class DynamicsProcessing.BandStage extends android.media.audiofx.DynamicsProcessing.Stage {
+ ctor public DynamicsProcessing.BandStage(boolean, boolean, int);
+ method public int getBandCount();
+ }
+
+ public static final class DynamicsProcessing.Channel {
+ ctor public DynamicsProcessing.Channel(float, boolean, int, boolean, int, boolean, int, boolean);
+ ctor public DynamicsProcessing.Channel(android.media.audiofx.DynamicsProcessing.Channel);
+ method public float getInputGain();
+ method public android.media.audiofx.DynamicsProcessing.Limiter getLimiter();
+ method public android.media.audiofx.DynamicsProcessing.Mbc getMbc();
+ method public android.media.audiofx.DynamicsProcessing.MbcBand getMbcBand(int);
+ method public android.media.audiofx.DynamicsProcessing.Eq getPostEq();
+ method public android.media.audiofx.DynamicsProcessing.EqBand getPostEqBand(int);
+ method public android.media.audiofx.DynamicsProcessing.Eq getPreEq();
+ method public android.media.audiofx.DynamicsProcessing.EqBand getPreEqBand(int);
+ method public void setInputGain(float);
+ method public void setLimiter(android.media.audiofx.DynamicsProcessing.Limiter);
+ method public void setMbc(android.media.audiofx.DynamicsProcessing.Mbc);
+ method public void setMbcBand(int, android.media.audiofx.DynamicsProcessing.MbcBand);
+ method public void setPostEq(android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPostEqBand(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPreEq(android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPreEqBand(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ }
+
+ public static final class DynamicsProcessing.Config {
+ method public android.media.audiofx.DynamicsProcessing.Channel getChannelByChannelIndex(int);
+ method public float getInputGainByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.Limiter getLimiterByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.MbcBand getMbcBandByChannelIndex(int, int);
+ method public int getMbcBandCount();
+ method public android.media.audiofx.DynamicsProcessing.Mbc getMbcByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.EqBand getPostEqBandByChannelIndex(int, int);
+ method public int getPostEqBandCount();
+ method public android.media.audiofx.DynamicsProcessing.Eq getPostEqByChannelIndex(int);
+ method public android.media.audiofx.DynamicsProcessing.EqBand getPreEqBandByChannelIndex(int, int);
+ method public int getPreEqBandCount();
+ method public android.media.audiofx.DynamicsProcessing.Eq getPreEqByChannelIndex(int);
+ method public float getPreferredFrameDuration();
+ method public int getVariant();
+ method public boolean isLimiterInUse();
+ method public boolean isMbcInUse();
+ method public boolean isPostEqInUse();
+ method public boolean isPreEqInUse();
+ method public void setAllChannelsTo(android.media.audiofx.DynamicsProcessing.Channel);
+ method public void setChannelTo(int, android.media.audiofx.DynamicsProcessing.Channel);
+ method public void setInputGainAllChannelsTo(float);
+ method public void setInputGainByChannelIndex(int, float);
+ method public void setLimiterAllChannelsTo(android.media.audiofx.DynamicsProcessing.Limiter);
+ method public void setLimiterByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Limiter);
+ method public void setMbcAllChannelsTo(android.media.audiofx.DynamicsProcessing.Mbc);
+ method public void setMbcBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.MbcBand);
+ method public void setMbcBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.MbcBand);
+ method public void setMbcByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Mbc);
+ method public void setPostEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPostEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPostEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPostEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPreEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq);
+ method public void setPreEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPreEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand);
+ method public void setPreEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq);
+ }
+
+ public static final class DynamicsProcessing.Config.Builder {
+ ctor public DynamicsProcessing.Config.Builder(int, int, boolean, int, boolean, int, boolean, int, boolean);
+ method public android.media.audiofx.DynamicsProcessing.Config build();
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setAllChannelsTo(android.media.audiofx.DynamicsProcessing.Channel);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setChannelTo(int, android.media.audiofx.DynamicsProcessing.Channel);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setInputGainAllChannelsTo(float);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setInputGainByChannelIndex(int, float);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setLimiterAllChannelsTo(android.media.audiofx.DynamicsProcessing.Limiter);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setLimiterByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Limiter);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setMbcAllChannelsTo(android.media.audiofx.DynamicsProcessing.Mbc);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setMbcByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Mbc);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setPostEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setPostEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setPreEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setPreEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq);
+ method public android.media.audiofx.DynamicsProcessing.Config.Builder setPreferredFrameDuration(float);
+ }
+
+ public static final class DynamicsProcessing.Eq extends android.media.audiofx.DynamicsProcessing.BandStage {
+ ctor public DynamicsProcessing.Eq(boolean, boolean, int);
+ ctor public DynamicsProcessing.Eq(android.media.audiofx.DynamicsProcessing.Eq);
+ method public android.media.audiofx.DynamicsProcessing.EqBand getBand(int);
+ method public void setBand(int, android.media.audiofx.DynamicsProcessing.EqBand);
+ }
+
+ public static final class DynamicsProcessing.EqBand extends android.media.audiofx.DynamicsProcessing.BandBase {
+ ctor public DynamicsProcessing.EqBand(boolean, float, float);
+ ctor public DynamicsProcessing.EqBand(android.media.audiofx.DynamicsProcessing.EqBand);
+ method public float getGain();
+ method public void setGain(float);
+ }
+
+ public static final class DynamicsProcessing.Limiter extends android.media.audiofx.DynamicsProcessing.Stage {
+ ctor public DynamicsProcessing.Limiter(boolean, boolean, int, float, float, float, float, float);
+ ctor public DynamicsProcessing.Limiter(android.media.audiofx.DynamicsProcessing.Limiter);
+ method public float getAttackTime();
+ method public int getLinkGroup();
+ method public float getPostGain();
+ method public float getRatio();
+ method public float getReleaseTime();
+ method public float getThreshold();
+ method public void setAttackTime(float);
+ method public void setLinkGroup(int);
+ method public void setPostGain(float);
+ method public void setRatio(float);
+ method public void setReleaseTime(float);
+ method public void setThreshold(float);
+ }
+
+ public static final class DynamicsProcessing.Mbc extends android.media.audiofx.DynamicsProcessing.BandStage {
+ ctor public DynamicsProcessing.Mbc(boolean, boolean, int);
+ ctor public DynamicsProcessing.Mbc(android.media.audiofx.DynamicsProcessing.Mbc);
+ method public android.media.audiofx.DynamicsProcessing.MbcBand getBand(int);
+ method public void setBand(int, android.media.audiofx.DynamicsProcessing.MbcBand);
+ }
+
+ public static final class DynamicsProcessing.MbcBand extends android.media.audiofx.DynamicsProcessing.BandBase {
+ ctor public DynamicsProcessing.MbcBand(boolean, float, float, float, float, float, float, float, float, float, float);
+ ctor public DynamicsProcessing.MbcBand(android.media.audiofx.DynamicsProcessing.MbcBand);
+ method public float getAttackTime();
+ method public float getExpanderRatio();
+ method public float getKneeWidth();
+ method public float getNoiseGateThreshold();
+ method public float getPostGain();
+ method public float getPreGain();
+ method public float getRatio();
+ method public float getReleaseTime();
+ method public float getThreshold();
+ method public void setAttackTime(float);
+ method public void setExpanderRatio(float);
+ method public void setKneeWidth(float);
+ method public void setNoiseGateThreshold(float);
+ method public void setPostGain(float);
+ method public void setPreGain(float);
+ method public void setRatio(float);
+ method public void setReleaseTime(float);
+ method public void setThreshold(float);
+ }
+
+ public static class DynamicsProcessing.Stage {
+ ctor public DynamicsProcessing.Stage(boolean, boolean);
+ method public boolean isEnabled();
+ method public boolean isInUse();
+ method public void setEnabled(boolean);
+ }
+
public class EnvironmentalReverb extends android.media.audiofx.AudioEffect {
ctor public EnvironmentalReverb(int, int) throws java.lang.IllegalArgumentException, java.lang.RuntimeException, java.lang.UnsupportedOperationException;
method public short getDecayHFRatio() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
@@ -25729,14 +26462,23 @@
public final class MediaSessionManager {
method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName);
method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler);
+ method public void addOnSessionTokensChangedListener(java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnSessionTokensChangedListener);
+ method public java.util.List<android.media.SessionToken2> getActiveSessionTokens();
method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
+ method public java.util.List<android.media.SessionToken2> getAllSessionTokens();
+ method public java.util.List<android.media.SessionToken2> getSessionServiceTokens();
method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
+ method public void removeOnSessionTokensChangedListener(android.media.session.MediaSessionManager.OnSessionTokensChangedListener);
}
public static abstract interface MediaSessionManager.OnActiveSessionsChangedListener {
method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
}
+ public static abstract interface MediaSessionManager.OnSessionTokensChangedListener {
+ method public abstract void onSessionTokensChanged(java.util.List<android.media.SessionToken2>);
+ }
+
public final class PlaybackState implements android.os.Parcelable {
method public int describeContents();
method public long getActions();
@@ -33165,6 +33907,17 @@
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
+ field public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; // 0x4
+ field public static final int USER_OPERATION_ERROR_LOW_STORAGE = 5; // 0x5
+ field public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; // 0x2
+ field public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; // 0x3
+ field public static final int USER_OPERATION_ERROR_MAX_USERS = 6; // 0x6
+ field public static final int USER_OPERATION_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int USER_OPERATION_SUCCESS = 0; // 0x0
+ }
+
+ public static class UserManager.UserOperationException extends java.lang.RuntimeException {
+ method public int getUserOperationResult();
}
public abstract class VibrationEffect implements android.os.Parcelable {
@@ -34639,7 +35392,7 @@
field public static final java.lang.String FEATURES = "features";
field public static final int FEATURES_HD_CALL = 4; // 0x4
field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
- field public static final int FEATURES_RTT = 16; // 0x10
+ field public static final int FEATURES_RTT = 32; // 0x20
field public static final int FEATURES_VIDEO = 1; // 0x1
field public static final int FEATURES_WIFI = 8; // 0x8
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
@@ -52594,6 +53347,20 @@
method public void update();
}
+ public class MediaControlView2 extends android.view.ViewGroup {
+ ctor public MediaControlView2(android.content.Context);
+ ctor public MediaControlView2(android.content.Context, android.util.AttributeSet);
+ ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int);
+ ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int, int);
+ method public void requestPlayButtonFocus();
+ method public void setMediaSessionToken(android.media.SessionToken2);
+ method public void setOnFullScreenListener(android.widget.MediaControlView2.OnFullScreenListener);
+ }
+
+ public static abstract interface MediaControlView2.OnFullScreenListener {
+ method public abstract void onFullScreen(android.view.View, boolean);
+ }
+
public class MediaController extends android.widget.FrameLayout {
ctor public MediaController(android.content.Context, android.util.AttributeSet);
ctor public MediaController(android.content.Context, boolean);
@@ -53984,6 +54751,27 @@
method public void suspend();
}
+ public class VideoView2 extends android.view.ViewGroup {
+ ctor public VideoView2(android.content.Context);
+ ctor public VideoView2(android.content.Context, android.util.AttributeSet);
+ ctor public VideoView2(android.content.Context, android.util.AttributeSet, int);
+ ctor public VideoView2(android.content.Context, android.util.AttributeSet, int, int);
+ method public android.widget.MediaControlView2 getMediaControlView2();
+ method public android.media.SessionToken2 getMediaSessionToken();
+ method public int getViewType();
+ method public boolean isSubtitleEnabled();
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
+ method public void setDataSource(android.media.DataSourceDesc);
+ method public void setMediaControlView2(android.widget.MediaControlView2, long);
+ method public void setMediaItem(android.media.MediaItem2);
+ method public void setSpeed(float);
+ method public void setSubtitleEnabled(boolean);
+ method public void setViewType(int);
+ field public static final int VIEW_TYPE_SURFACEVIEW = 1; // 0x1
+ field public static final int VIEW_TYPE_TEXTUREVIEW = 2; // 0x2
+ }
+
public class ViewAnimator extends android.widget.FrameLayout {
ctor public ViewAnimator(android.content.Context);
ctor public ViewAnimator(android.content.Context, android.util.AttributeSet);
diff --git a/api/system-current.txt b/api/system-current.txt
index a581bab..0555263 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -617,6 +617,7 @@
method public java.lang.String transportDirName();
field public static final int AGENT_ERROR = -1003; // 0xfffffc15
field public static final int AGENT_UNKNOWN = -1004; // 0xfffffc14
+ field public static final java.lang.String EXTRA_TRANSPORT_REGISTRATION = "android.app.backup.extra.TRANSPORT_REGISTRATION";
field public static final int FLAG_INCREMENTAL = 2; // 0x2
field public static final int FLAG_NON_INCREMENTAL = 4; // 0x4
field public static final int FLAG_USER_INITIATED = 1; // 0x1
@@ -1591,7 +1592,7 @@
method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
}
- public deprecated class ContextHubMessage {
+ public deprecated class ContextHubMessage implements android.os.Parcelable {
ctor public ContextHubMessage(int, int, byte[]);
method public int describeContents();
method public byte[] getData();
@@ -1722,7 +1723,7 @@
field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
}
- public deprecated class NanoApp {
+ public deprecated class NanoApp implements android.os.Parcelable {
ctor public NanoApp();
ctor public deprecated NanoApp(int, byte[]);
ctor public NanoApp(long, byte[]);
@@ -1770,7 +1771,7 @@
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppBinary> CREATOR;
}
- public deprecated class NanoAppFilter {
+ public deprecated class NanoAppFilter implements android.os.Parcelable {
ctor public NanoAppFilter(long, int, int, long);
method public int describeContents();
method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
@@ -1785,7 +1786,7 @@
field public static final int VENDOR_ANY = -1; // 0xffffffff
}
- public deprecated class NanoAppInstanceInfo {
+ public deprecated class NanoAppInstanceInfo implements android.os.Parcelable {
ctor public NanoAppInstanceInfo();
method public int describeContents();
method public long getAppId();
@@ -2648,8 +2649,10 @@
}
public class AudioPolicy {
+ method public int attachMixes(java.util.List<android.media.audiopolicy.AudioMix>);
method public android.media.AudioRecord createAudioRecordSink(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
+ method public int detachMixes(java.util.List<android.media.audiopolicy.AudioMix>);
method public int getFocusDuckingBehavior();
method public int getStatus();
method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -4180,6 +4183,7 @@
field public static final java.lang.String CARRIER_APP_NAMES = "carrier_app_names";
field public static final java.lang.String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
+ field public static final java.lang.String EUICC_PROVISIONED = "euicc_provisioned";
field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
@@ -4275,6 +4279,7 @@
method public byte[] getServerParams();
method public int getSnapshotVersion();
method public java.security.cert.CertPath getTrustedHardwareCertPath();
+ method public deprecated byte[] getTrustedHardwarePublicKey();
method public java.util.List<android.security.keystore.recovery.WrappedApplicationKey> getWrappedApplicationKeys();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainSnapshot> CREATOR;
@@ -4297,16 +4302,22 @@
public class RecoveryController {
method public android.security.keystore.recovery.RecoverySession createRecoverySession();
method public byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+ method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
method public java.security.Key generateKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+ method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
method public int[] getPendingRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
method public void setRecoveryStatus(java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public void setServerParams(byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public void setSnapshotCreatedPendingIntent(android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException;
@@ -4318,6 +4329,7 @@
public class RecoverySession implements java.lang.AutoCloseable {
method public void close();
method public java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+ method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
}
@@ -4327,6 +4339,7 @@
public final class WrappedApplicationKey implements android.os.Parcelable {
method public int describeContents();
+ method public deprecated byte[] getAccount();
method public java.lang.String getAlias();
method public byte[] getEncryptedKeyMaterial();
method public void writeToParcel(android.os.Parcel, int);
@@ -4336,6 +4349,7 @@
public static class WrappedApplicationKey.Builder {
ctor public WrappedApplicationKey.Builder();
method public android.security.keystore.recovery.WrappedApplicationKey build();
+ method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(java.lang.String);
method public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(byte[]);
}
@@ -5384,6 +5398,7 @@
field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2
field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1
field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4
+ field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
field public static final int RESULT_OK = 0; // 0x0
field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
}
@@ -5983,7 +5998,6 @@
method public void setUiTtyMode(int, android.os.Message);
method public int shouldProcessCall(java.lang.String[]);
field public static final int PROCESS_CALL_CSFB = 1; // 0x1
- field public static final int PROCESS_CALL_EMERGENCY_CSFB = 2; // 0x2
field public static final int PROCESS_CALL_IMS = 0; // 0x0
}
@@ -6130,7 +6144,9 @@
method public final void onSmsReceived(int, java.lang.String, byte[]) throws java.lang.RuntimeException;
method public final void onSmsStatusReportReceived(int, int, java.lang.String, byte[]) throws java.lang.RuntimeException;
method public void sendSms(int, int, java.lang.String, java.lang.String, boolean, byte[]);
- field public static final int DELIVER_STATUS_ERROR = 2; // 0x2
+ field public static final int DELIVER_STATUS_ERROR_GENERIC = 2; // 0x2
+ field public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; // 0x3
+ field public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; // 0x4
field public static final int DELIVER_STATUS_OK = 1; // 0x1
field public static final int SEND_STATUS_ERROR = 2; // 0x2
field public static final int SEND_STATUS_ERROR_FALLBACK = 4; // 0x4
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 58652a2..48f43e0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -91,34 +91,6 @@
}
-package android.security.keystore.recovery {
-
- public final class KeyChainSnapshot implements android.os.Parcelable {
- method public deprecated byte[] getTrustedHardwarePublicKey();
- }
-
- public class RecoveryController {
- method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
- }
-
- public class RecoverySession implements java.lang.AutoCloseable {
- method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
- }
-
- public final class WrappedApplicationKey implements android.os.Parcelable {
- method public deprecated byte[] getAccount();
- }
-
- public static class WrappedApplicationKey.Builder {
- method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
- }
-
-}
-
package android.service.notification {
public abstract class NotificationListenerService extends android.app.Service {
diff --git a/api/test-current.txt b/api/test-current.txt
index d5b4311..2559d24 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12,6 +12,7 @@
public class ActivityManager {
method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method public int getPackageImportance(java.lang.String);
+ method public long getTotalRam();
method public int getUidImportance(int);
method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
@@ -47,7 +48,10 @@
public class AppOpsManager {
method public static java.lang.String[] getOpStrs();
+ method public boolean isOperationActive(int, int, java.lang.String);
method public void setMode(int, int, java.lang.String, int);
+ method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener);
+ method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener);
field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
@@ -89,6 +93,12 @@
field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
+ field public static final int OP_RECORD_AUDIO = 27; // 0x1b
+ field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
+ }
+
+ public static abstract interface AppOpsManager.OnOpActiveChangedListener {
+ method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
}
public final class NotificationChannelGroup implements android.os.Parcelable {
@@ -351,6 +361,7 @@
public final class DisplayManager {
method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
+ method public android.graphics.Point getStableDisplaySize();
method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
}
@@ -446,6 +457,10 @@
package android.os {
+ public static class Build.VERSION {
+ field public static final int RESOURCES_SDK_INT;
+ }
+
public class IncidentManager {
method public void reportIncident(android.os.IncidentReportArgs);
method public void reportIncident(java.lang.String, byte[]);
@@ -546,6 +561,7 @@
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages";
+ field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final java.lang.String LOW_POWER_MODE = "low_power";
field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index e87a78e..84a04e5 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -297,6 +297,10 @@
super.backupFinished(status);
System.out.println("Backup finished with result: "
+ convertBackupStatusToString(status));
+ if (status == BackupManager.ERROR_BACKUP_CANCELLED) {
+ System.out.println("Backups can be cancelled if a backup is already running, check "
+ + "backup dumpsys");
+ }
}
}
@@ -318,7 +322,7 @@
case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
return "Size quota exceeded";
case BackupManager.ERROR_BACKUP_CANCELLED:
- return "Backup Cancelled";
+ return "Backup cancelled";
default:
return "Unknown error";
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 54785ca..8ffe5bf 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -29,11 +29,11 @@
#include <signal.h>
#include <time.h>
+#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <androidfw/AssetManager.h>
#include <binder/IPCThreadState.h>
-#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 6bdd9be..3a47fe1 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -15,7 +15,8 @@
LOCAL_PATH:= $(call my-dir)
# proto files used in incidentd to generate cppstream proto headers.
-PROTO_FILES:= frameworks/base/core/proto/android/util/log.proto
+PROTO_FILES:= frameworks/base/core/proto/android/util/log.proto \
+ frameworks/base/core/proto/android/os/data.proto
# ========= #
# incidentd #
@@ -131,7 +132,7 @@
LOCAL_MODULE_CLASS := NATIVE_TESTS
gen_src_dir := $(local-generated-sources-dir)
# generate cppstream proto for testing
-GEN_PROTO := $(gen_src_dir)/log.proto.timestamp
+GEN_PROTO := $(gen_src_dir)/test.proto.timestamp
$(GEN_PROTO): $(HOST_OUT_EXECUTABLES)/aprotoc $(HOST_OUT_EXECUTABLES)/protoc-gen-cppstream $(PROTO_FILES)
$(GEN_PROTO): PRIVATE_GEN_SRC_DIR := $(gen_src_dir)
$(GEN_PROTO): PRIVATE_CUSTOM_TOOL = \
diff --git a/cmds/incidentd/incidentd.rc b/cmds/incidentd/incidentd.rc
index 1bd1468..6dd8114 100644
--- a/cmds/incidentd/incidentd.rc
+++ b/cmds/incidentd/incidentd.rc
@@ -15,7 +15,7 @@
service incidentd /system/bin/incidentd
class main
user incidentd
- group incidentd log
+ group incidentd log readproc
on post-fs-data
# Create directory for incidentd
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index db60794..64da677 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -76,6 +76,7 @@
return -errno;
}
} else if (amt == 0) {
+ VLOG("Reached EOF of fd=%d", fd);
break;
}
mBuffer.wp()->move(amt);
@@ -156,10 +157,10 @@
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
VLOG("Fail to read fd %d: %s", fd, strerror(errno));
return -errno;
- } // otherwise just continue
- } else if (amt == 0) { // reach EOF so don't have to poll pfds[0].
- ::close(pfds[0].fd);
- pfds[0].fd = -1;
+ } // otherwise just continue
+ } else if (amt == 0) {
+ VLOG("Reached EOF of input file %d", fd);
+ pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0].
} else {
rpos += amt;
cirSize += amt;
@@ -187,6 +188,7 @@
// if buffer is empty and fd is closed, close write fd.
if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) {
+ VLOG("Close write pipe %d", toFd);
::close(pfds[1].fd);
pfds[1].fd = -1;
}
@@ -207,6 +209,7 @@
return -errno;
} // otherwise just continue
} else if (amt == 0) {
+ VLOG("Reached EOF of fromFd %d", fromFd);
break;
} else {
mBuffer.wp()->move(amt);
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 5bfa093..66a3de1 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -26,7 +26,7 @@
using namespace std;
/**
- * Reads a file into a buffer, and then writes that data to an FdSet.
+ * Reads data from fd into a buffer, fd must be closed explicitly.
*/
class FdBuffer {
public:
@@ -83,6 +83,11 @@
*/
EncodedBuffer::iterator data() const;
+ /**
+ * Return the internal buffer, don't call unless you are familiar with EncodedBuffer.
+ */
+ EncodedBuffer* getInternalBuffer() { return &mBuffer; }
+
private:
EncodedBuffer mBuffer;
int64_t mStartTime;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 64eae3a..334d77c 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -18,12 +18,8 @@
#include "Section.h"
-#include <errno.h>
-#include <sys/prctl.h>
-#include <unistd.h>
#include <wait.h>
-#include <memory>
#include <mutex>
#include <android-base/file.h>
@@ -37,6 +33,7 @@
#include "FdBuffer.h"
#include "Privacy.h"
#include "PrivacyBuffer.h"
+#include "frameworks/base/core/proto/android/os/data.proto.h"
#include "frameworks/base/core/proto/android/util/log.proto.h"
#include "incidentd_util.h"
@@ -52,31 +49,11 @@
const int WAIT_MAX = 5;
const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
const char INCIDENT_HELPER[] = "/system/bin/incident_helper";
+const char GZIP[] = "/system/bin/gzip";
-static pid_t fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe,
- Fpipe& c2pPipe) {
+static pid_t fork_execute_incident_helper(const int id, Fpipe* p2cPipe, Fpipe* c2pPipe) {
const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
- // fork used in multithreaded environment, avoid adding unnecessary code in child process
- pid_t pid = fork();
- if (pid == 0) {
- if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0 || !p2cPipe.close() ||
- TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1 || !c2pPipe.close()) {
- ALOGW("%s can't setup stdin and stdout for incident helper", name);
- _exit(EXIT_FAILURE);
- }
-
- /* make sure the child dies when incidentd dies */
- prctl(PR_SET_PDEATHSIG, SIGKILL);
-
- execv(INCIDENT_HELPER, const_cast<char**>(ihArgs));
-
- ALOGW("%s failed in incident helper process: %s", name, strerror(errno));
- _exit(EXIT_FAILURE); // always exits with failure if any
- }
- // close the fds used in incident helper
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
- return pid;
+ return fork_execute_cmd(INCIDENT_HELPER, const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
}
// ================================================================================
@@ -254,10 +231,12 @@
return NO_ERROR;
}
// ================================================================================
+static inline bool isSysfs(const char* filename) { return strncmp(filename, "/sys/", 5) == 0; }
+
FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
: Section(id, timeoutMs), mFilename(filename) {
name = filename;
- mIsSysfs = strncmp(filename, "/sys/", 5) == 0;
+ mIsSysfs = isSysfs(filename);
}
FileSection::~FileSection() {}
@@ -280,7 +259,7 @@
return -errno;
}
- pid_t pid = fork_execute_incident_helper(this->id, this->name.string(), p2cPipe, c2pPipe);
+ pid_t pid = fork_execute_incident_helper(this->id, &p2cPipe, &c2pPipe);
if (pid == -1) {
ALOGW("FileSection '%s' failed to fork", this->name.string());
return -errno;
@@ -289,6 +268,8 @@
// parent process
status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
this->timeoutMs, mIsSysfs);
+ close(fd); // close the fd anyway.
+
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
@@ -313,7 +294,99 @@
return NO_ERROR;
}
+// ================================================================================
+GZipSection::GZipSection(int id, const char* filename, ...) : Section(id) {
+ name = "gzip ";
+ name += filename;
+ va_list args;
+ va_start(args, filename);
+ mFilenames = varargs(filename, args);
+ va_end(args);
+}
+GZipSection::~GZipSection() {}
+
+status_t GZipSection::Execute(ReportRequestSet* requests) const {
+ // Reads the files in order, use the first available one.
+ int index = 0;
+ int fd = -1;
+ while (mFilenames[index] != NULL) {
+ fd = open(mFilenames[index], O_RDONLY | O_CLOEXEC);
+ if (fd != -1) {
+ break;
+ }
+ ALOGW("GZipSection failed to open file %s", mFilenames[index]);
+ index++; // look at the next file.
+ }
+ VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd);
+ if (fd == -1) return -1;
+
+ FdBuffer buffer;
+ Fpipe p2cPipe;
+ Fpipe c2pPipe;
+ // initiate pipes to pass data to/from gzip
+ if (!p2cPipe.init() || !c2pPipe.init()) {
+ ALOGW("GZipSection '%s' failed to setup pipes", this->name.string());
+ return -errno;
+ }
+
+ const char* gzipArgs[]{GZIP, NULL};
+ pid_t pid = fork_execute_cmd(GZIP, const_cast<char**>(gzipArgs), &p2cPipe, &c2pPipe);
+ if (pid == -1) {
+ ALOGW("GZipSection '%s' failed to fork", this->name.string());
+ return -errno;
+ }
+ // parent process
+
+ // construct Fdbuffer to output GZippedfileProto, the reason to do this instead of using
+ // ProtoOutputStream is to avoid allocation of another buffer inside ProtoOutputStream.
+ EncodedBuffer* internalBuffer = buffer.getInternalBuffer();
+ internalBuffer->writeHeader((uint32_t)GZippedFileProto::FILENAME, WIRE_TYPE_LENGTH_DELIMITED);
+ String8 usedFile(mFilenames[index]);
+ internalBuffer->writeRawVarint32(usedFile.size());
+ for (size_t i = 0; i < usedFile.size(); i++) {
+ internalBuffer->writeRawByte(mFilenames[index][i]);
+ }
+ internalBuffer->writeHeader((uint32_t)GZippedFileProto::GZIPPED_DATA,
+ WIRE_TYPE_LENGTH_DELIMITED);
+ size_t editPos = internalBuffer->wp()->pos();
+ internalBuffer->wp()->move(8); // reserve 8 bytes for the varint of the data size.
+ size_t dataBeginAt = internalBuffer->wp()->pos();
+ VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos,
+ dataBeginAt);
+
+ status_t readStatus = buffer.readProcessedDataInStream(
+ fd, p2cPipe.writeFd(), c2pPipe.readFd(), this->timeoutMs, isSysfs(mFilenames[index]));
+ close(fd); // close the fd anyway.
+
+ if (readStatus != NO_ERROR || buffer.timedOut()) {
+ ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s",
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ kill_child(pid);
+ return readStatus;
+ }
+
+ status_t gzipStatus = wait_child(pid);
+ if (gzipStatus != NO_ERROR) {
+ ALOGW("GZipSection '%s' abnormal child process: %s", this->name.string(),
+ strerror(-gzipStatus));
+ return gzipStatus;
+ }
+ // Revisit the actual size from gzip result and edit the internal buffer accordingly.
+ size_t dataSize = buffer.size() - dataBeginAt;
+ internalBuffer->wp()->rewind()->move(editPos);
+ internalBuffer->writeRawVarint32(dataSize);
+ internalBuffer->copy(dataBeginAt, dataSize);
+ VLOG("GZipSection '%s' wrote %zd bytes in %d ms, dataSize=%zd", this->name.string(),
+ buffer.size(), (int)buffer.durationMs(), dataSize);
+ status_t err = write_report_requests(this->id, buffer, requests);
+ if (err != NO_ERROR) {
+ ALOGW("GZipSection '%s' failed writing: %s", this->name.string(), strerror(-err));
+ return err;
+ }
+
+ return NO_ERROR;
+}
// ================================================================================
struct WorkerThreadData : public virtual RefBase {
const WorkerThreadSection* section;
@@ -457,42 +530,20 @@
}
// ================================================================================
-void CommandSection::init(const char* command, va_list args) {
- va_list copied_args;
- int numOfArgs = 0;
-
- va_copy(copied_args, args);
- while (va_arg(copied_args, const char*) != NULL) {
- numOfArgs++;
- }
- va_end(copied_args);
-
- // allocate extra 1 for command and 1 for NULL terminator
- mCommand = (const char**)malloc(sizeof(const char*) * (numOfArgs + 2));
-
- mCommand[0] = command;
- name = command;
- for (int i = 0; i < numOfArgs; i++) {
- const char* arg = va_arg(args, const char*);
- mCommand[i + 1] = arg;
- name += " ";
- name += arg;
- }
- mCommand[numOfArgs + 1] = NULL;
-}
-
CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...)
: Section(id, timeoutMs) {
+ name = command;
va_list args;
va_start(args, command);
- init(command, args);
+ mCommand = varargs(command, args);
va_end(args);
}
CommandSection::CommandSection(int id, const char* command, ...) : Section(id) {
+ name = command;
va_list args;
va_start(args, command);
- init(command, args);
+ mCommand = varargs(command, args);
va_end(args);
}
@@ -527,7 +578,7 @@
strerror(errno));
_exit(err); // exit with command error code
}
- pid_t ihPid = fork_execute_incident_helper(this->id, this->name.string(), cmdPipe, ihPipe);
+ pid_t ihPid = fork_execute_incident_helper(this->id, &cmdPipe, &ihPipe);
if (ihPid == -1) {
ALOGW("CommandSection '%s' failed to fork", this->name.string());
return -errno;
@@ -544,8 +595,7 @@
}
// TODO: wait for command here has one trade-off: the failed status of command won't be detected
- // until
- // buffer timeout, but it has advatage on starting the data stream earlier.
+ // until buffer timeout, but it has advatage on starting the data stream earlier.
status_t cmdStatus = wait_child(cmdPid);
status_t ihStatus = wait_child(ihPid);
if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index d644681..8294be1 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -84,6 +84,21 @@
};
/**
+ * Section that reads in a file and gzips the content.
+ */
+class GZipSection : public Section {
+public:
+ GZipSection(int id, const char* filename, ...);
+ virtual ~GZipSection();
+
+ virtual status_t Execute(ReportRequestSet* requests) const;
+
+private:
+ // It looks up the content from multiple files and stops when the first one is available.
+ const char** mFilenames;
+};
+
+/**
* Base class for sections that call a command that might need a timeout.
*/
class WorkerThreadSection : public Section {
@@ -111,8 +126,6 @@
private:
const char** mCommand;
-
- void init(const char* command, va_list args);
};
/**
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index 2415860..c095f2b 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -13,8 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
+#include "Log.h"
+
#include "incidentd_util.h"
+#include <sys/prctl.h>
+
#include "section_list.h"
const Privacy* get_privacy_of_section(int id) {
@@ -50,4 +55,49 @@
int Fpipe::readFd() const { return mRead.get(); }
-int Fpipe::writeFd() const { return mWrite.get(); }
\ No newline at end of file
+int Fpipe::writeFd() const { return mWrite.get(); }
+
+pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output) {
+ // fork used in multithreaded environment, avoid adding unnecessary code in child process
+ pid_t pid = fork();
+ if (pid == 0) {
+ if (TEMP_FAILURE_RETRY(dup2(input->readFd(), STDIN_FILENO)) < 0 || !input->close() ||
+ TEMP_FAILURE_RETRY(dup2(output->writeFd(), STDOUT_FILENO)) < 0 || !output->close()) {
+ ALOGW("Can't setup stdin and stdout for command %s", cmd);
+ _exit(EXIT_FAILURE);
+ }
+
+ /* make sure the child dies when incidentd dies */
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+
+ execv(cmd, argv);
+
+ ALOGW("%s failed in the child process: %s", cmd, strerror(errno));
+ _exit(EXIT_FAILURE); // always exits with failure if any
+ }
+ // close the fds used in child process.
+ close(input->readFd());
+ close(output->writeFd());
+ return pid;
+}
+// ================================================================================
+const char** varargs(const char* first, va_list rest) {
+ va_list copied_rest;
+ int numOfArgs = 1; // first is already count.
+
+ va_copy(copied_rest, rest);
+ while (va_arg(copied_rest, const char*) != NULL) {
+ numOfArgs++;
+ }
+ va_end(copied_rest);
+
+ // allocate extra 1 for NULL terminator
+ const char** ret = (const char**)malloc(sizeof(const char*) * (numOfArgs + 1));
+ ret[0] = first;
+ for (int i = 1; i < numOfArgs; i++) {
+ const char* arg = va_arg(rest, const char*);
+ ret[i] = arg;
+ }
+ ret[numOfArgs] = NULL;
+ return ret;
+}
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index 09aa040..db7ec82 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -20,12 +20,20 @@
#include <android-base/unique_fd.h>
+#include <stdarg.h>
+
#include "Privacy.h"
using namespace android::base;
+/**
+ * Looks up Privacy of a section in the auto-gen PRIVACY_POLICY_LIST;
+ */
const Privacy* get_privacy_of_section(int id);
+/**
+ * This class wraps android::base::Pipe.
+ */
class Fpipe {
public:
Fpipe();
@@ -41,4 +49,15 @@
unique_fd mWrite;
};
+/**
+ * Forks and exec a command with two pipes, one connects stdin for input,
+ * one connects stdout for output. It returns the pid of the child.
+ */
+pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output);
+
+/**
+ * Grabs varargs from stack and stores them in heap with NULL-terminated array.
+ */
+const char** varargs(const char* first, va_list rest);
+
#endif // INCIDENTD_UTIL_H
\ No newline at end of file
diff --git a/cmds/incidentd/testdata/kmsg.txt b/cmds/incidentd/testdata/kmsg.txt
new file mode 100644
index 0000000..a8e3c02
--- /dev/null
+++ b/cmds/incidentd/testdata/kmsg.txt
@@ -0,0 +1,47 @@
+[0] bldr_log_init: bldr_log_base=0x83600000, bldr_log_size=458752
+B - 626409 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device
+B - 729255 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device
+B - 729285 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 9:0
+D - 104829 - APPSBL Image Loaded, Delta - (2498816 Bytes)
+B - 729468 - SBL1, End
+D - 643611 - SBL1, Delta
+S - Flash Throughput, 129000 KB/s (4729638 Bytes, 36613 us)
+S - DDR Frequency, 1017 MHz
+0x400, 0x400
+B - 482296 - Basic DDR tests done
+B - 544638 - clock_init, Start
+D - 244 - clock_init, Delta
+B - 544913 - HTC RPM DATARAM UPDATE info: Done
+B - 545004 - Image Load, Start
+B - 548359 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 5:0
+D - 3386 - QSEE Dev Config Image Loaded, Delta - (46232 Bytes)
+B - 548725 - Image Load, Start
+B - 550860 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 512:0
+D - 2166 - APDP Image Loaded, Delta - (7696 Bytes)
+B - 550891 - Image Load, Start
+B - 601612 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 7:0
+D - 50782 - QSEE Image Loaded, Delta - (1648640 Bytes)
+B - 601704 - Image Load, Start
+D - 244 - SEC Image Loaded, Delta - (4096 Bytes)
+B - 602344 - 0x1310 = 0x24
+B - 602375 - is_above_vbat_weak = 1, pon_reasons (with usb_in checked) = 0x31
+B - 602466 - sbl1_efs_handle_cookies, Start
+D - 91 - sbl1_efs_handle_cookies, Delta
+B - 602558 - Image Load, Start
+B - 613446 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 21:0
+D - 11010 - QHEE Image Loaded, Delta - (258280 Bytes)
+B - 613568 - Image Load, Start
+B - 624274 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 10:0
+D - 10736 - RPM Image Loaded, Delta - (224104 Bytes)
+B - 624335 - Image Load, Start
+D - 0 - STI Image Loaded, Delta - (0 Bytes)
+B - 624548 - Image Load, Start
+m_driver_init, Delta
+B - 471804 - pm_sbl_chg
+ ******************** [ START SECOND] ********************
+^@B - 736605 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device
+B - 839451 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device
+B - 839482 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 9:0
+D - 104828 - APPSBL Image Loaded, Delta - (2498816 Bytes)
+B - 839665 - SBL1, End
+D - 753838 - SBL1, Delta
diff --git a/cmds/incidentd/testdata/kmsg.txt.gz b/cmds/incidentd/testdata/kmsg.txt.gz
new file mode 100644
index 0000000..fba449f
--- /dev/null
+++ b/cmds/incidentd/testdata/kmsg.txt.gz
Binary files differ
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 026bf74..1528224 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -39,10 +39,22 @@
using namespace android::os;
using namespace std;
using ::testing::StrEq;
+using ::testing::Test;
using ::testing::internal::CaptureStdout;
using ::testing::internal::GetCapturedStdout;
// NOTICE: this test requires /system/bin/incident_helper is installed.
+class SectionTest : public Test {
+public:
+ virtual void SetUp() override { ASSERT_NE(tf.fd, -1); }
+
+protected:
+ TemporaryFile tf;
+ ReportRequestSet requests;
+
+ const std::string kTestPath = GetExecutableDirectory();
+ const std::string kTestDataPath = kTestPath + "/testdata/";
+};
class SimpleListener : public IIncidentReportStatusListener {
public:
@@ -58,10 +70,8 @@
virtual IBinder* onAsBinder() override { return nullptr; };
};
-TEST(SectionTest, HeaderSection) {
- TemporaryFile output2;
+TEST_F(SectionTest, HeaderSection) {
HeaderSection hs;
- ReportRequestSet requests;
IncidentReportArgs args1, args2;
args1.addSection(1);
@@ -77,7 +87,7 @@
args2.addHeader(head2);
requests.add(new ReportRequest(args1, new SimpleListener(), -1));
- requests.add(new ReportRequest(args2, new SimpleListener(), output2.fd));
+ requests.add(new ReportRequest(args2, new SimpleListener(), tf.fd));
requests.setMainFd(STDOUT_FILENO);
string content;
@@ -87,28 +97,25 @@
"\x12\x3"
"axe\n\x05\x12\x03pup"));
- EXPECT_TRUE(ReadFileToString(output2.path, &content));
+ EXPECT_TRUE(ReadFileToString(tf.path, &content));
EXPECT_THAT(content, StrEq("\n\x05\x12\x03pup"));
}
-TEST(SectionTest, MetadataSection) {
+TEST_F(SectionTest, MetadataSection) {
MetadataSection ms;
- ReportRequestSet requests;
requests.setMainFd(STDOUT_FILENO);
requests.sectionStats(1)->set_success(true);
CaptureStdout();
ASSERT_EQ(NO_ERROR, ms.Execute(&requests));
- EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b\x18\x1\"\x4\b\x1\x10\x1"));
+ EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b(\x1"
+ "2\x4\b\x1\x10\x1"));
}
-TEST(SectionTest, FileSection) {
- TemporaryFile tf;
+TEST_F(SectionTest, FileSection) {
FileSection fs(REVERSE_PARSER, tf.path);
- ReportRequestSet requests;
- ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(WriteStringToFile("iamtestdata", tf.path));
requests.setMainFd(STDOUT_FILENO);
@@ -120,66 +127,79 @@
EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\vatadtsetmai"));
}
-TEST(SectionTest, FileSectionTimeout) {
- TemporaryFile tf;
- // id -1 is timeout parser
+TEST_F(SectionTest, FileSectionTimeout) {
FileSection fs(TIMEOUT_PARSER, tf.path, QUICK_TIMEOUT_MS);
- ReportRequestSet requests;
ASSERT_EQ(NO_ERROR, fs.Execute(&requests));
}
-TEST(SectionTest, CommandSectionConstructor) {
+TEST_F(SectionTest, GZipSection) {
+ const std::string testFile = kTestDataPath + "kmsg.txt";
+ const std::string testGzFile = testFile + ".gz";
+ GZipSection gs(NOOP_PARSER, "/tmp/nonexist", testFile.c_str(), NULL);
+
+ requests.setMainFd(tf.fd);
+ requests.setMainDest(android::os::DEST_LOCAL);
+
+ ASSERT_EQ(NO_ERROR, gs.Execute(&requests));
+ std::string expect, gzFile, actual;
+ ASSERT_TRUE(ReadFileToString(testGzFile, &gzFile));
+ ASSERT_TRUE(ReadFileToString(tf.path, &actual));
+ expect = "\x2\xC6\x6\n\"" + testFile + "\x12\x9F\x6" + gzFile;
+ EXPECT_THAT(actual, StrEq(expect));
+}
+
+TEST_F(SectionTest, GZipSectionNoFileFound) {
+ GZipSection gs(NOOP_PARSER, "/tmp/nonexist1", "/tmp/nonexist2", NULL);
+ requests.setMainFd(STDOUT_FILENO);
+ ASSERT_EQ(-1, gs.Execute(&requests));
+}
+
+TEST_F(SectionTest, CommandSectionConstructor) {
CommandSection cs1(1, "echo", "\"this is a test\"", "ooo", NULL);
CommandSection cs2(2, "single_command", NULL);
CommandSection cs3(1, 3123, "echo", "\"this is a test\"", "ooo", NULL);
CommandSection cs4(2, 43214, "single_command", NULL);
- EXPECT_THAT(cs1.name.string(), StrEq("echo \"this is a test\" ooo"));
+ EXPECT_THAT(cs1.name.string(), StrEq("echo"));
EXPECT_THAT(cs2.name.string(), StrEq("single_command"));
EXPECT_EQ(3123, cs3.timeoutMs);
EXPECT_EQ(43214, cs4.timeoutMs);
- EXPECT_THAT(cs3.name.string(), StrEq("echo \"this is a test\" ooo"));
+ EXPECT_THAT(cs3.name.string(), StrEq("echo"));
EXPECT_THAT(cs4.name.string(), StrEq("single_command"));
}
-TEST(SectionTest, CommandSectionEcho) {
+TEST_F(SectionTest, CommandSectionEcho) {
CommandSection cs(REVERSE_PARSER, "/system/bin/echo", "about", NULL);
- ReportRequestSet requests;
requests.setMainFd(STDOUT_FILENO);
CaptureStdout();
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\x06\ntuoba"));
}
-TEST(SectionTest, CommandSectionCommandTimeout) {
+TEST_F(SectionTest, CommandSectionCommandTimeout) {
CommandSection cs(NOOP_PARSER, QUICK_TIMEOUT_MS, "/system/bin/yes", NULL);
- ReportRequestSet requests;
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
}
-TEST(SectionTest, CommandSectionIncidentHelperTimeout) {
+TEST_F(SectionTest, CommandSectionIncidentHelperTimeout) {
CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "/system/bin/echo", "about", NULL);
- ReportRequestSet requests;
requests.setMainFd(STDOUT_FILENO);
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
}
-TEST(SectionTest, CommandSectionBadCommand) {
+TEST_F(SectionTest, CommandSectionBadCommand) {
CommandSection cs(NOOP_PARSER, "echoo", "about", NULL);
- ReportRequestSet requests;
ASSERT_EQ(NAME_NOT_FOUND, cs.Execute(&requests));
}
-TEST(SectionTest, CommandSectionBadCommandAndTimeout) {
+TEST_F(SectionTest, CommandSectionBadCommandAndTimeout) {
CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "nonexistcommand", "-opt", NULL);
- ReportRequestSet requests;
// timeout will return first
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
}
-TEST(SectionTest, LogSectionBinary) {
+TEST_F(SectionTest, LogSectionBinary) {
LogSection ls(1, LOG_ID_EVENTS);
- ReportRequestSet requests;
requests.setMainFd(STDOUT_FILENO);
CaptureStdout();
ASSERT_EQ(NO_ERROR, ls.Execute(&requests));
@@ -187,9 +207,8 @@
EXPECT_FALSE(results.empty());
}
-TEST(SectionTest, LogSectionSystem) {
+TEST_F(SectionTest, LogSectionSystem) {
LogSection ls(1, LOG_ID_SYSTEM);
- ReportRequestSet requests;
requests.setMainFd(STDOUT_FILENO);
CaptureStdout();
ASSERT_EQ(NO_ERROR, ls.Execute(&requests));
@@ -197,12 +216,9 @@
EXPECT_FALSE(results.empty());
}
-TEST(SectionTest, TestFilterPiiTaggedFields) {
- TemporaryFile tf;
+TEST_F(SectionTest, TestFilterPiiTaggedFields) {
FileSection fs(NOOP_PARSER, tf.path);
- ReportRequestSet requests;
- ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
requests.setMainFd(STDOUT_FILENO);
@@ -212,11 +228,9 @@
EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2));
}
-TEST(SectionTest, TestBadFdRequest) {
- TemporaryFile input;
- FileSection fs(NOOP_PARSER, input.path);
- ReportRequestSet requests;
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
+TEST_F(SectionTest, TestBadFdRequest) {
+ FileSection fs(NOOP_PARSER, tf.path);
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
IncidentReportArgs args;
args.setAll(true);
@@ -231,11 +245,9 @@
EXPECT_EQ(badFdRequest->err, -EBADF);
}
-TEST(SectionTest, TestBadRequests) {
- TemporaryFile input;
- FileSection fs(NOOP_PARSER, input.path);
- ReportRequestSet requests;
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
+TEST_F(SectionTest, TestBadRequests) {
+ FileSection fs(NOOP_PARSER, tf.path);
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
IncidentReportArgs args;
args.setAll(true);
@@ -244,16 +256,14 @@
EXPECT_EQ(fs.Execute(&requests), -EBADF);
}
-TEST(SectionTest, TestMultipleRequests) {
- TemporaryFile input, output1, output2, output3;
- FileSection fs(NOOP_PARSER, input.path);
- ReportRequestSet requests;
+TEST_F(SectionTest, TestMultipleRequests) {
+ TemporaryFile output1, output2, output3;
+ FileSection fs(NOOP_PARSER, tf.path);
- ASSERT_TRUE(input.fd != -1);
ASSERT_TRUE(output1.fd != -1);
ASSERT_TRUE(output2.fd != -1);
ASSERT_TRUE(output3.fd != -1);
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
IncidentReportArgs args1, args2, args3;
args1.setAll(true);
@@ -286,17 +296,15 @@
EXPECT_THAT(content, StrEq(""));
}
-TEST(SectionTest, TestMultipleRequestsBySpec) {
- TemporaryFile input, output1, output2, output3;
- FileSection fs(NOOP_PARSER, input.path);
- ReportRequestSet requests;
+TEST_F(SectionTest, TestMultipleRequestsBySpec) {
+ TemporaryFile output1, output2, output3;
+ FileSection fs(NOOP_PARSER, tf.path);
- ASSERT_TRUE(input.fd != -1);
ASSERT_TRUE(output1.fd != -1);
ASSERT_TRUE(output2.fd != -1);
ASSERT_TRUE(output3.fd != -1);
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
IncidentReportArgs args1, args2, args3;
args1.setAll(true);
@@ -328,4 +336,4 @@
c = (char)STRING_FIELD_2.size();
EXPECT_TRUE(ReadFileToString(output3.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2));
-}
\ No newline at end of file
+}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 87825f1..7f76ab1 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -21,9 +21,11 @@
src/statsd_config.proto \
src/FieldValue.cpp \
src/stats_log_util.cpp \
- src/anomaly/AnomalyMonitor.cpp \
+ src/anomaly/AlarmMonitor.cpp \
+ src/anomaly/AlarmTracker.cpp \
src/anomaly/AnomalyTracker.cpp \
src/anomaly/DurationAnomalyTracker.cpp \
+ src/anomaly/subscriber_util.cpp \
src/condition/CombinationConditionTracker.cpp \
src/condition/condition_util.cpp \
src/condition/SimpleConditionTracker.cpp \
@@ -36,6 +38,7 @@
src/external/StatsCompanionServicePuller.cpp \
src/external/SubsystemSleepStatePuller.cpp \
src/external/ResourceHealthManagerPuller.cpp \
+ src/external/ResourceThermalManagerPuller.cpp \
src/external/CpuTimePerUidPuller.cpp \
src/external/CpuTimePerUidFreqPuller.cpp \
src/external/KernelUidCpuActiveTimeReader.cpp \
@@ -99,6 +102,7 @@
android.hardware.health@2.0 \
android.hardware.power@1.0 \
android.hardware.power@1.1 \
+ android.hardware.thermal@1.0 \
libmemunreachable
# =========
@@ -170,7 +174,8 @@
src/atom_field_options.proto \
src/atoms.proto \
src/stats_log.proto \
- tests/AnomalyMonitor_test.cpp \
+ tests/AlarmMonitor_test.cpp \
+ tests/anomaly/AlarmTracker_test.cpp \
tests/anomaly/AnomalyTracker_test.cpp \
tests/ConfigManager_test.cpp \
tests/external/puller_util_test.cpp \
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 21f30e2..b0e2c43 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -217,6 +217,14 @@
const Field mMatcher;
const int32_t mMask;
+ inline const Field& getMatcher() const {
+ return mMatcher;
+ }
+
+ inline int32_t getMask() const {
+ return mMask;
+ }
+
bool hasAnyPositionMatcher(int* prefix) const {
if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) {
(*prefix) = mMatcher.getPrefix(2);
@@ -224,6 +232,10 @@
}
return false;
}
+
+ inline bool operator!=(const Matcher& that) const {
+ return mMatcher != that.getMatcher() || mMask != that.getMask();
+ };
};
/**
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 1502a00..cc706313 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -166,10 +166,11 @@
}
}
-void getDimensionForCondition(const LogEvent& event, Metric2Condition links,
+void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
+ const Metric2Condition& links,
vector<HashableDimensionKey>* conditionDimension) {
// Get the dimension first by using dimension from what.
- filterValues(links.metricFields, event.getValues(), conditionDimension);
+ filterValues(links.metricFields, eventValues, conditionDimension);
// Then replace the field with the dimension from condition.
for (auto& dim : *conditionDimension) {
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 89fe317..57bdf68 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -40,7 +40,7 @@
mValues = values;
}
- HashableDimensionKey(){};
+ HashableDimensionKey() {};
HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};
@@ -144,7 +144,8 @@
void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
std::vector<FieldValue>* output);
-void getDimensionForCondition(const LogEvent& event, Metric2Condition links,
+void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
+ const Metric2Condition& links,
std::vector<HashableDimensionKey>* conditionDimension);
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 87dec5d..9b58a14 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -66,13 +66,16 @@
#define STATS_DATA_DIR "/data/misc/stats-data"
StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
- const sp<AnomalyMonitor>& anomalyMonitor,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor,
const long timeBaseSec,
const std::function<void(const ConfigKey&)>& sendBroadcast)
: mUidMap(uidMap),
- mAnomalyMonitor(anomalyMonitor),
+ mAnomalyAlarmMonitor(anomalyAlarmMonitor),
+ mPeriodicAlarmMonitor(periodicAlarmMonitor),
mSendBroadcast(sendBroadcast),
- mTimeBaseSec(timeBaseSec) {
+ mTimeBaseSec(timeBaseSec),
+ mLastLogTimestamp(0) {
StatsPullerManager statsPullerManager;
statsPullerManager.SetTimeBaseSec(mTimeBaseSec);
}
@@ -82,10 +85,19 @@
void StatsLogProcessor::onAnomalyAlarmFired(
const uint64_t timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet) {
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
for (const auto& itr : mMetricsManagers) {
- itr.second->onAnomalyAlarmFired(timestampNs, anomalySet);
+ itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
+ }
+}
+void StatsLogProcessor::onPeriodicAlarmFired(
+ const uint64_t timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
+
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ for (const auto& itr : mMetricsManagers) {
+ itr.second->onPeriodicAlarmFired(timestampNs, alarmSet);
}
}
@@ -133,9 +145,12 @@
}
}
-// TODO: what if statsd service restarts? How do we know what logs are already processed before?
void StatsLogProcessor::OnLogEvent(LogEvent* event) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
+ if (event->GetElapsedTimestampNs() < mLastLogTimestamp) {
+ return;
+ }
+ mLastLogTimestamp = event->GetElapsedTimestampNs();
StatsdStats::getInstance().noteAtomLogged(
event->GetTagId(), event->GetElapsedTimestampNs() / NS_PER_SEC);
@@ -170,7 +185,9 @@
void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
VLOG("Updated configuration for key %s", key.ToString().c_str());
- sp<MetricsManager> newMetricsManager = new MetricsManager(key, config, mTimeBaseSec, mUidMap);
+ sp<MetricsManager> newMetricsManager =
+ new MetricsManager(key, config, mTimeBaseSec, mUidMap,
+ mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
ALOGE("Can't accept more configs!");
@@ -179,7 +196,6 @@
if (newMetricsManager->isConfigValid()) {
mUidMap->OnConfigUpdated(key);
- newMetricsManager->setAnomalyMonitor(mAnomalyMonitor);
if (newMetricsManager->shouldAddUidMapListener()) {
// We have to add listener after the MetricsManager is constructed because it's
// not safe to create wp or sp from this pointer inside its constructor.
@@ -316,7 +332,7 @@
StatsdStats::kMaxMetricsBytesPerConfig) { // Too late. We need to start clearing data.
// TODO(b/70571383): By 12/15/2017 add API to drop data directly
ProtoOutputStream proto;
- metricsManager.onDumpReport(time(nullptr) * NS_PER_SEC, &proto);
+ metricsManager.onDumpReport(timestampNs, &proto);
StatsdStats::getInstance().noteDataDropped(key);
VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
} else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
@@ -340,7 +356,7 @@
for (auto& pair : mMetricsManagers) {
const ConfigKey& key = pair.first;
vector<uint8_t> data;
- onDumpReportLocked(key, time(nullptr) * NS_PER_SEC, &data);
+ onDumpReportLocked(key, getElapsedRealtimeNs(), &data);
// TODO: Add a guardrail to prevent accumulation of file on disk.
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 1444306..7a6aa1e 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -34,7 +34,8 @@
class StatsLogProcessor : public ConfigListener {
public:
- StatsLogProcessor(const sp<UidMap>& uidMap, const sp<AnomalyMonitor>& anomalyMonitor,
+ StatsLogProcessor(const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
const long timeBaseSec,
const std::function<void(const ConfigKey&)>& sendBroadcast);
virtual ~StatsLogProcessor();
@@ -48,10 +49,15 @@
void onDumpReport(const ConfigKey& key, const uint64_t dumpTimeNs, vector<uint8_t>* outData);
- /* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
+ /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
void onAnomalyAlarmFired(
const uint64_t timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet);
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
+
+ /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */
+ void onPeriodicAlarmFired(
+ const uint64_t timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
/* Flushes data to disk. Data on memory will be gone after written to disk. */
void WriteDataToDisk();
@@ -76,7 +82,9 @@
StatsPullerManager mStatsPullerManager;
- sp<AnomalyMonitor> mAnomalyMonitor;
+ sp<AlarmMonitor> mAnomalyAlarmMonitor;
+
+ sp<AlarmMonitor> mPeriodicAlarmMonitor;
void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs,
vector<uint8_t>* outData);
@@ -98,6 +106,8 @@
const long mTimeBaseSec;
+ int64_t mLastLogTimestamp;
+
long mLastPullerCacheClearTimeSec = 0;
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 26db3af..ee4f434 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -50,49 +50,73 @@
constexpr const char* kPermissionDump = "android.permission.DUMP";
#define STATS_SERVICE_DIR "/data/misc/stats-service"
-// ======================================================================
/**
* Watches for the death of the stats companion (system process).
*/
class CompanionDeathRecipient : public IBinder::DeathRecipient {
public:
- CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor);
+ CompanionDeathRecipient(const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor) :
+ mAnomalyAlarmMonitor(anomalyAlarmMonitor),
+ mPeriodicAlarmMonitor(periodicAlarmMonitor) {}
virtual void binderDied(const wp<IBinder>& who);
private:
- const sp<AnomalyMonitor> mAnomalyMonitor;
+ sp<AlarmMonitor> mAnomalyAlarmMonitor;
+ sp<AlarmMonitor> mPeriodicAlarmMonitor;
};
-CompanionDeathRecipient::CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor)
- : mAnomalyMonitor(anomalyMonitor) {
-}
-
void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
ALOGW("statscompanion service died");
- mAnomalyMonitor->setStatsCompanionService(nullptr);
+ mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
+ mPeriodicAlarmMonitor->setStatsCompanionService(nullptr);
SubscriberReporter::getInstance().setStatsCompanionService(nullptr);
}
-// ======================================================================
StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS))
-{
+ : mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+ [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+ if (sc != nullptr) {
+ sc->setAnomalyAlarm(timeMillis);
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+ }
+ },
+ [](const sp<IStatsCompanionService>& sc) {
+ if (sc != nullptr) {
+ sc->cancelAnomalyAlarm();
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+ }
+ })),
+ mPeriodicAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+ [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+ if (sc != nullptr) {
+ sc->setAlarmForSubscriberTriggering(timeMillis);
+ StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+ }
+ },
+ [](const sp<IStatsCompanionService>& sc) {
+ if (sc != nullptr) {
+ sc->cancelAlarmForSubscriberTriggering();
+ StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+ }
+
+ })) {
mUidMap = new UidMap();
StatsPuller::SetUidMap(mUidMap);
mConfigManager = new ConfigManager();
- mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, getElapsedRealtimeSec(),
- [this](const ConfigKey& key) {
- sp<IStatsCompanionService> sc = getStatsCompanionService();
- auto receiver = mConfigManager->GetConfigReceiver(key);
- if (sc == nullptr) {
- VLOG("Could not find StatsCompanionService");
- } else if (receiver == nullptr) {
- VLOG("Statscompanion could not find a broadcast receiver for %s",
- key.ToString().c_str());
- } else {
- sc->sendDataBroadcast(receiver);
- }
+ mProcessor = new StatsLogProcessor(mUidMap, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
+ getElapsedRealtimeSec(), [this](const ConfigKey& key) {
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ auto receiver = mConfigManager->GetConfigReceiver(key);
+ if (sc == nullptr) {
+ VLOG("Could not find StatsCompanionService");
+ } else if (receiver == nullptr) {
+ VLOG("Statscompanion could not find a broadcast receiver for %s",
+ key.ToString().c_str());
+ } else {
+ sc->sendDataBroadcast(receiver);
}
+ }
);
mConfigManager->AddListener(mProcessor);
@@ -423,6 +447,13 @@
}
if (args[1] == "update") {
+ char* endp;
+ int64_t configID = strtoll(name.c_str(), &endp, 10);
+ if (endp == name.c_str() || *endp != '\0') {
+ fprintf(err, "Error parsing config ID.\n");
+ return UNKNOWN_ERROR;
+ }
+
// Read stream into buffer.
string buffer;
if (!android::base::ReadFdToString(fileno(in), &buffer)) {
@@ -438,7 +469,7 @@
}
// Add / update the config.
- mConfigManager->UpdateConfig(ConfigKey(uid, StrToInt64(name)), config);
+ mConfigManager->UpdateConfig(ConfigKey(uid, configID), config);
} else {
if (argCount == 2) {
cmd_remove_all_configs(out);
@@ -493,7 +524,7 @@
}
if (good) {
vector<uint8_t> data;
- mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), time(nullptr) * NS_PER_SEC,
+ mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
&data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
if (proto) {
@@ -615,7 +646,8 @@
status_t StatsService::cmd_clear_puller_cache(FILE* out) {
IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
+ VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
+ ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
int cleared = mStatsPullerManager.ForceClearPullerCache();
fprintf(out, "Puller removed %d cached data!\n", cleared);
@@ -670,18 +702,40 @@
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informAnomalyAlarmFired");
}
+
uint64_t currentTimeSec = getElapsedRealtimeSec();
- std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet =
- mAnomalyMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
- if (anomalySet.size() > 0) {
+ std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
+ mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ if (alarmSet.size() > 0) {
VLOG("Found an anomaly alarm that fired.");
- mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet);
+ mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
} else {
VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled.");
}
return Status::ok();
}
+Status StatsService::informAlarmForSubscriberTriggeringFired() {
+ VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
+ "Only system uid can call informAlarmForSubscriberTriggeringFired");
+ }
+
+ uint64_t currentTimeSec = time(nullptr);
+ std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
+ mPeriodicAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ if (alarmSet.size() > 0) {
+ VLOG("Found periodic alarm fired.");
+ mProcessor->onPeriodicAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
+ } else {
+ ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
+ }
+ return Status::ok();
+}
+
Status StatsService::informPollAlarmFired() {
VLOG("StatsService::informPollAlarmFired was called");
@@ -766,10 +820,11 @@
"statscompanion unavailable despite it contacting statsd!");
}
VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
- IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor));
- mAnomalyMonitor->setStatsCompanionService(statsCompanion);
+ IInterface::asBinder(statsCompanion)->linkToDeath(
+ new CompanionDeathRecipient(mAnomalyAlarmMonitor, mPeriodicAlarmMonitor));
+ mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion);
+ mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion);
SubscriberReporter::getInstance().setStatsCompanionService(statsCompanion);
-
return Status::ok();
}
@@ -786,7 +841,7 @@
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
ConfigKey configKey(ipc->getCallingUid(), key);
- mProcessor->onDumpReport(configKey, time(nullptr) * NS_PER_SEC, output);
+ mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), output);
return Status::ok();
} else {
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 9690de7..e0a1299 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -18,7 +18,7 @@
#define STATS_SERVICE_H
#include "StatsLogProcessor.h"
-#include "anomaly/AnomalyMonitor.h"
+#include "anomaly/AlarmMonitor.h"
#include "config/ConfigManager.h"
#include "external/StatsPullerManager.h"
#include "packages/UidMap.h"
@@ -58,6 +58,8 @@
virtual Status statsCompanionReady();
virtual Status informAnomalyAlarmFired();
virtual Status informPollAlarmFired();
+ virtual Status informAlarmForSubscriberTriggeringFired();
+
virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app);
virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version);
@@ -244,9 +246,14 @@
sp<StatsLogProcessor> mProcessor;
/**
- * The anomaly detector.
+ * The alarm monitor for anomaly detection.
*/
- const sp<AnomalyMonitor> mAnomalyMonitor;
+ const sp<AlarmMonitor> mAnomalyAlarmMonitor;
+
+ /**
+ * The alarm monitor for alarms to directly trigger subscriber.
+ */
+ const sp<AlarmMonitor> mPeriodicAlarmMonitor;
/**
* Whether this is an eng build.
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
similarity index 74%
rename from cmds/statsd/src/anomaly/AnomalyMonitor.cpp
rename to cmds/statsd/src/anomaly/AlarmMonitor.cpp
index ca34dc6..78f0c2b 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
@@ -17,21 +17,24 @@
#define DEBUG false
#include "Log.h"
-#include "anomaly/AnomalyMonitor.h"
+#include "anomaly/AlarmMonitor.h"
#include "guardrail/StatsdStats.h"
namespace android {
namespace os {
namespace statsd {
-AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
- : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) {
-}
+AlarmMonitor::AlarmMonitor(
+ uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
+ const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
+ const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm)
+ : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec),
+ mUpdateAlarm(updateAlarm),
+ mCancelAlarm(cancelAlarm) {}
-AnomalyMonitor::~AnomalyMonitor() {
-}
+AlarmMonitor::~AlarmMonitor() {}
-void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
+void AlarmMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
std::lock_guard<std::mutex> lock(mLock);
sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
@@ -40,13 +43,13 @@
return;
}
VLOG("Creating link to statsCompanionService");
- const sp<const AnomalyAlarm> top = mPq.top();
+ const sp<const InternalAlarm> top = mPq.top();
if (top != nullptr) {
updateRegisteredAlarmTime_l(top->timestampSec);
}
}
-void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
+void AlarmMonitor::add(sp<const InternalAlarm> alarm) {
std::lock_guard<std::mutex> lock(mLock);
if (alarm == nullptr) {
ALOGW("Asked to add a null alarm.");
@@ -66,7 +69,7 @@
}
}
-void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
+void AlarmMonitor::remove(sp<const InternalAlarm> alarm) {
std::lock_guard<std::mutex> lock(mLock);
if (alarm == nullptr) {
ALOGW("Asked to remove a null alarm.");
@@ -89,13 +92,13 @@
// More efficient than repeatedly calling remove(mPq.top()) since it batches the
// updates to the registered alarm.
-unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
+unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> AlarmMonitor::popSoonerThan(
uint32_t timestampSec) {
VLOG("Removing alarms with time <= %u", timestampSec);
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> oldAlarms;
std::lock_guard<std::mutex> lock(mLock);
- for (sp<const AnomalyAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
+ for (sp<const InternalAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
t = mPq.top()) {
oldAlarms.insert(t);
mPq.pop(); // remove t
@@ -113,25 +116,19 @@
return oldAlarms;
}
-void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
+void AlarmMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
VLOG("Updating reg alarm time to %u", timestampSec);
mRegisteredAlarmTimeSec = timestampSec;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
+ mUpdateAlarm(mStatsCompanionService, secToMs(mRegisteredAlarmTimeSec));
}
-void AnomalyMonitor::cancelRegisteredAlarmTime_l() {
+void AlarmMonitor::cancelRegisteredAlarmTime_l() {
VLOG("Cancelling reg alarm.");
mRegisteredAlarmTimeSec = 0;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelAnomalyAlarm();
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
+ mCancelAlarm(mStatsCompanionService);
}
-int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
+int64_t AlarmMonitor::secToMs(uint32_t timeSec) {
return ((int64_t)timeSec) * 1000;
}
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h
similarity index 77%
rename from cmds/statsd/src/anomaly/AnomalyMonitor.h
rename to cmds/statsd/src/anomaly/AlarmMonitor.h
index 7acc7904..3badb1f 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.h
@@ -41,33 +41,34 @@
* threshold.
* Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
*/
-struct AnomalyAlarm : public RefBase {
- AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
+struct InternalAlarm : public RefBase {
+ InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
}
const uint32_t timestampSec;
- /** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
+ /** InternalAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
struct SmallerTimestamp {
- bool operator()(sp<const AnomalyAlarm> a, sp<const AnomalyAlarm> b) const {
+ bool operator()(sp<const InternalAlarm> a, sp<const InternalAlarm> b) const {
return (a->timestampSec < b->timestampSec);
}
};
};
-// TODO: Rename this file to AnomalyAlarmMonitor.
/**
- * Manages alarms for Anomaly Detection.
+ * Manages internal alarms that may get registered with the AlarmManager.
*/
-class AnomalyMonitor : public RefBase {
+class AlarmMonitor : public RefBase {
public:
/**
* @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
* from the registered alarm by more than this amount, update the registered
* alarm.
*/
- AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
- ~AnomalyMonitor();
+ AlarmMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
+ const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
+ const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm);
+ ~AlarmMonitor();
/**
* Tells AnomalyMonitor what IStatsCompanionService to use and, if
@@ -80,20 +81,20 @@
/**
* Adds the given alarm (reference) to the queue.
*/
- void add(sp<const AnomalyAlarm> alarm);
+ void add(sp<const InternalAlarm> alarm);
/**
* Removes the given alarm (reference) from the queue.
* Note that alarm comparison is reference-based; if another alarm exists
* with the same timestampSec, that alarm will still remain in the queue.
*/
- void remove(sp<const AnomalyAlarm> alarm);
+ void remove(sp<const InternalAlarm> alarm);
/**
* Returns and removes all alarms whose timestamp <= the given timestampSec.
* Always updates the registered alarm if return is non-empty.
*/
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> popSoonerThan(
uint32_t timestampSec);
/**
@@ -119,7 +120,7 @@
/**
* Priority queue of alarms, prioritized by soonest alarm.timestampSec.
*/
- indexed_priority_queue<AnomalyAlarm, AnomalyAlarm::SmallerTimestamp> mPq;
+ indexed_priority_queue<InternalAlarm, InternalAlarm::SmallerTimestamp> mPq;
/**
* Binder interface for communicating with StatsCompanionService.
@@ -146,6 +147,13 @@
/** Converts uint32 timestamp in seconds to a Java long in msec. */
int64_t secToMs(uint32_t timeSec);
+
+ // Callback function to update the alarm via StatsCompanionService.
+ std::function<void(const sp<IStatsCompanionService>, int64_t)> mUpdateAlarm;
+
+ // Callback function to cancel the alarm via StatsCompanionService.
+ std::function<void(const sp<IStatsCompanionService>)> mCancelAlarm;
+
};
} // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
new file mode 100644
index 0000000..eb28383
--- /dev/null
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "anomaly/AlarmTracker.h"
+#include "anomaly/subscriber_util.h"
+#include "HashableDimensionKey.h"
+#include "stats_util.h"
+#include "storage/StorageManager.h"
+
+#include <statslog.h>
+#include <time.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+AlarmTracker::AlarmTracker(uint64_t startMillis,
+ const Alarm& alarm, const ConfigKey& configKey,
+ const sp<AlarmMonitor>& alarmMonitor)
+ : mAlarmConfig(alarm),
+ mConfigKey(configKey),
+ mAlarmMonitor(alarmMonitor) {
+ VLOG("AlarmTracker() called");
+ mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC;
+ mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
+ mAlarmMonitor->add(mInternalAlarm);
+}
+
+AlarmTracker::~AlarmTracker() {
+ VLOG("~AlarmTracker() called");
+ if (mInternalAlarm != nullptr) {
+ mAlarmMonitor->remove(mInternalAlarm);
+ }
+}
+
+void AlarmTracker::addSubscription(const Subscription& subscription) {
+ mSubscriptions.push_back(subscription);
+}
+
+uint64_t AlarmTracker::findNextAlarmSec(uint64_t currentTimeSec) {
+ int periodsForward = (currentTimeSec - mAlarmSec) * MS_PER_SEC / mAlarmConfig.period_millis();
+ return mAlarmSec + (periodsForward + 1) * mAlarmConfig.period_millis() / MS_PER_SEC;
+}
+
+void AlarmTracker::informAlarmsFired(
+ const uint64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
+ if (firedAlarms.empty() || firedAlarms.find(mInternalAlarm) == firedAlarms.end()) {
+ return;
+ }
+ if (!mSubscriptions.empty()) {
+ triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey,
+ mSubscriptions);
+ }
+ firedAlarms.erase(mInternalAlarm);
+ mAlarmSec = findNextAlarmSec(timestampNs / NS_PER_SEC);
+ mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
+ mAlarmMonitor->add(mInternalAlarm);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h
new file mode 100644
index 0000000..d59dacaa
--- /dev/null
+++ b/cmds/statsd/src/anomaly/AlarmTracker.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <gtest/gtest_prod.h>
+
+#include "AlarmMonitor.h"
+#include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alarm
+
+#include <android/os/IStatsCompanionService.h>
+#include <stdlib.h>
+#include <utils/RefBase.h>
+
+using android::os::IStatsCompanionService;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class AlarmTracker : public virtual RefBase {
+public:
+ AlarmTracker(uint64_t startMillis,
+ const Alarm& alarm, const ConfigKey& configKey,
+ const sp<AlarmMonitor>& subscriberAlarmMonitor);
+
+ virtual ~AlarmTracker();
+
+ void onAlarmFired();
+
+ void addSubscription(const Subscription& subscription);
+
+ void informAlarmsFired(const uint64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms);
+
+protected:
+ uint64_t findNextAlarmSec(uint64_t currentTimeMillis);
+
+ // statsd_config.proto Alarm message that defines this tracker.
+ const Alarm mAlarmConfig;
+
+ // A reference to the Alarm's config key.
+ const ConfigKey& mConfigKey;
+
+ // The subscriptions that depend on this alarm.
+ std::vector<Subscription> mSubscriptions;
+
+ // Alarm monitor.
+ sp<AlarmMonitor> mAlarmMonitor;
+
+ // The current expected alarm time in seconds.
+ uint64_t mAlarmSec;
+
+ // The current alarm.
+ sp<const InternalAlarm> mInternalAlarm;
+
+ FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index c40eb81..642604e 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "AnomalyTracker.h"
+#include "subscriber_util.h"
#include "external/Perfetto.h"
#include "guardrail/StatsdStats.h"
#include "subscriber/IncidentdReporter.h"
@@ -231,40 +232,7 @@
}
void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
- VLOG("informSubscribers called.");
- if (mSubscriptions.empty()) {
- // The config just wanted to log the anomaly. That's fine.
- VLOG("No Subscriptions were associated with the alert.");
- return;
- }
-
- for (const Subscription& subscription : mSubscriptions) {
- if (subscription.probability_of_informing() < 1
- && ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) {
- // Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always.
- // The config writer was advised to use -0.1 and 1.1 for never/always.
- ALOGI("Fate decided that a subscriber would not be informed.");
- continue;
- }
- switch (subscription.subscriber_information_case()) {
- case Subscription::SubscriberInformationCase::kIncidentdDetails:
- if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) {
- ALOGW("Failed to generate incident report.");
- }
- break;
- case Subscription::SubscriberInformationCase::kPerfettoDetails:
- if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
- ALOGW("Failed to generate prefetto traces.");
- }
- break;
- case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
- SubscriberReporter::getInstance().alertBroadcastSubscriber(mConfigKey, subscription,
- key);
- break;
- default:
- break;
- }
- }
+ triggerSubscribers(mAlert.id(), key, mConfigKey, mSubscriptions);
}
} // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 3be959d..e3f493c 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -23,7 +23,7 @@
#include <gtest/gtest_prod.h>
#include <utils/RefBase.h>
-#include "AnomalyMonitor.h"
+#include "AlarmMonitor.h"
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
#include "stats_util.h" // HashableDimensionKey and DimToValMap
@@ -64,9 +64,9 @@
void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
const MetricDimensionKey& key, const int64_t& currentBucketValue);
- // Init the AnomalyMonitor which is shared across anomaly trackers.
- virtual void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
- return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
+ // Init the AlarmMonitor which is shared across anomaly trackers.
+ virtual void setAlarmMonitor(const sp<AlarmMonitor>& alarmMonitor) {
+ return; // Base AnomalyTracker class has no need for the AlarmMonitor.
}
// Helper function to return the sum value of past buckets at given dimension.
@@ -92,11 +92,10 @@
}
// Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
- // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
- virtual void informAlarmsFired(
- const uint64_t& timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
- return; // The base AnomalyTracker class doesn't have alarms.
+ // and removes it from firedAlarms. Does NOT remove the alarm from the AlarmMonitor.
+ virtual void informAlarmsFired(const uint64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
+ return; // The base AnomalyTracker class doesn't have alarms.
}
protected:
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index 3ba943c..31d50be 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -24,8 +24,9 @@
namespace os {
namespace statsd {
-DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey)
- : AnomalyTracker(alert, configKey) {
+DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
+ const sp<AlarmMonitor>& alarmMonitor)
+ : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
}
DurationAnomalyTracker::~DurationAnomalyTracker() {
@@ -59,10 +60,10 @@
VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period");
timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1;
}
- sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
+ sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec};
mAlarms.insert({dimensionKey, alarm});
- if (mAnomalyMonitor != nullptr) {
- mAnomalyMonitor->add(alarm);
+ if (mAlarmMonitor != nullptr) {
+ mAlarmMonitor->add(alarm);
}
}
@@ -70,8 +71,8 @@
auto itr = mAlarms.find(dimensionKey);
if (itr != mAlarms.end()) {
mAlarms.erase(dimensionKey);
- if (mAnomalyMonitor != nullptr) {
- mAnomalyMonitor->remove(itr->second);
+ if (mAlarmMonitor != nullptr) {
+ mAlarmMonitor->remove(itr->second);
}
}
}
@@ -86,16 +87,16 @@
}
}
-void DurationAnomalyTracker::informAlarmsFired(
- const uint64_t& timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
+void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
+
if (firedAlarms.empty() || mAlarms.empty()) return;
// Find the intersection of firedAlarms and mAlarms.
// The for loop is inefficient, since it loops over all keys, but that's okay since it is very
- // seldomly called. The alternative would be having AnomalyAlarms store information about the
+ // seldomly called. The alternative would be having InternalAlarms store information about the
// DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
// is rarely ever called.
- unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
+ unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms;
for (const auto& kv : mAlarms) {
if (firedAlarms.count(kv.second) > 0) {
matchedAlarms.insert({kv.first, kv.second});
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 15aef29..51186df 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -16,7 +16,7 @@
#pragma once
-#include "AnomalyMonitor.h"
+#include "AlarmMonitor.h"
#include "AnomalyTracker.h"
namespace android {
@@ -27,7 +27,8 @@
class DurationAnomalyTracker : public virtual AnomalyTracker {
public:
- DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey);
+ DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
+ const sp<AlarmMonitor>& alarmMonitor);
virtual ~DurationAnomalyTracker();
@@ -40,11 +41,6 @@
// Stop all the alarms owned by this tracker.
void stopAllAlarms();
- // Init the AnomalyMonitor which is shared across anomaly trackers.
- void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) override {
- mAnomalyMonitor = anomalyMonitor;
- }
-
// Declares the anomaly when the alarm expired given the current timestamp.
void declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey,
const uint64_t& timestampNs);
@@ -53,17 +49,16 @@
// and removes it from firedAlarms.
// Note that this will generally be called from a different thread from the other functions;
// the caller is responsible for thread safety.
- void informAlarmsFired(
- const uint64_t& timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) override;
+ void informAlarmsFired(const uint64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) override;
protected:
// The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
// are still active.
- std::unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> mAlarms;
+ std::unordered_map<MetricDimensionKey, sp<const InternalAlarm>> mAlarms;
// Anomaly alarm monitor.
- sp<AnomalyMonitor> mAnomalyMonitor;
+ sp<AlarmMonitor> mAlarmMonitor;
// Resets all bucket data. For use when all the data gets stale.
void resetStorage() override;
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
new file mode 100644
index 0000000..e796d19
--- /dev/null
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IServiceManager.h>
+
+#include "external/Perfetto.h"
+#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+#include "subscriber/IncidentdReporter.h"
+#include "subscriber/SubscriberReporter.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void triggerSubscribers(const int64_t rule_id,
+ const MetricDimensionKey& dimensionKey,
+ const ConfigKey& configKey,
+ const std::vector<Subscription>& subscriptions) {
+ VLOG("informSubscribers called.");
+ if (subscriptions.empty()) {
+ VLOG("No Subscriptions were associated.");
+ return;
+ }
+
+ for (const Subscription& subscription : subscriptions) {
+ if (subscription.probability_of_informing() < 1
+ && ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) {
+ // Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always.
+ // The config writer was advised to use -0.1 and 1.1 for never/always.
+ ALOGI("Fate decided that a subscriber would not be informed.");
+ continue;
+ }
+ switch (subscription.subscriber_information_case()) {
+ case Subscription::SubscriberInformationCase::kIncidentdDetails:
+ if (!GenerateIncidentReport(subscription.incidentd_details(), rule_id, configKey)) {
+ ALOGW("Failed to generate incident report.");
+ }
+ break;
+ case Subscription::SubscriberInformationCase::kPerfettoDetails:
+ if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
+ ALOGW("Failed to generate prefetto traces.");
+ }
+ break;
+ case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
+ SubscriberReporter::getInstance().alertBroadcastSubscriber(configKey, subscription,
+ dimensionKey);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/anomaly/subscriber_util.h b/cmds/statsd/src/anomaly/subscriber_util.h
new file mode 100644
index 0000000..dba8981
--- /dev/null
+++ b/cmds/statsd/src/anomaly/subscriber_util.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "HashableDimensionKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void triggerSubscribers(const int64_t rule_id,
+ const MetricDimensionKey& dimensionKey,
+ const ConfigKey& configKey,
+ const std::vector<Subscription>& subscriptions);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 04ebfcd..8e06504 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -72,7 +72,7 @@
BatteryLevelChanged battery_level_changed = 30;
ChargingStateChanged charging_state_changed = 31;
PluggedStateChanged plugged_state_changed = 32;
- DeviceTemperatureReported device_temperature_reported = 33;
+ // TODO: 33 is blank, but is available for use.
DeviceOnStatusChanged device_on_status_changed = 34;
WakeupAlarmOccurred wakeup_alarm_occurred = 35;
KernelWakeupReported kernel_wakeup_reported = 36;
@@ -101,11 +101,15 @@
OverlayStateChanged overlay_state_changed = 59;
ForegroundServiceStateChanged foreground_service_state_changed = 60;
CallStateChanged call_state_changed = 61;
+ KeyguardStateChanged keyguard_state_changed = 62;
+ KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63;
+ KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64;
+ AppDied app_died=65;
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
// Pulled events will start at field 10000.
- // Next: 10021
+ // Next: 10022
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000;
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -128,7 +132,11 @@
DiskSpace disk_space = 10018;
RemainingBatteryCapacity remaining_battery_capacity = 10019;
FullBatteryCapacity full_battery_capacity = 10020;
+ Temperature temperature = 10021;
}
+
+ // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
+ // 100,000 are reserved for non-AOSP (e.g. OEMs) to use.
}
/**
@@ -536,17 +544,6 @@
optional android.os.BatteryPluggedStateEnum state = 1;
}
-/**
- * Logs the temperature of the device, in tenths of a degree Celsius.
- *
- * Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message DeviceTemperatureReported {
- // Temperature in tenths of a degree C.
- optional int32 temperature = 1;
-}
-
// TODO: Define this more precisely.
// TODO: Log the ON state somewhere. It isn't currently logged anywhere.
/**
@@ -757,14 +754,74 @@
}
/**
+ * Logs keyguard state. The keyguard is the lock screen.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+ */
+message KeyguardStateChanged {
+ enum State {
+ UNKNOWN = 0;
+ // The keyguard is hidden when the phone is unlocked.
+ HIDDEN = 1;
+ // The keyguard is shown when the phone is locked (screen turns off).
+ SHOWN= 2;
+ // The keyguard is occluded when something is overlaying the keyguard.
+ // Eg. Opening the camera while on the lock screen.
+ OCCLUDED = 3;
+ }
+ optional State state = 1;
+}
+
+/**
+ * Logs keyguard bouncer state. The bouncer is a part of the keyguard, and
+ * prompts the user to enter a password (pattern, pin, etc).
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+ */
+
+message KeyguardBouncerStateChanged {
+ enum State {
+ UNKNOWN = 0;
+ // Bouncer is hidden, either as a result of successfully entering the
+ // password, screen timing out, or user going back to lock screen.
+ HIDDEN = 1;
+ // This is when the user is being prompted to enter the password.
+ SHOWN = 2;
+ }
+ optional State state = 1;
+}
+
+/**
+ * Logs the result of entering a password into the keyguard bouncer.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+ */
+message KeyguardBouncerPasswordEntered {
+ enum BouncerResult {
+ UNKNOWN = 0;
+ // The password entered was incorrect.
+ FAILURE = 1;
+ // The password entered was correct.
+ SUCCESS = 2;
+ }
+ optional BouncerResult result = 1;
+}
+
+/**
* Logs the duration of a davey (jank of >=700ms) when it occurs
*
* Logged from:
* frameworks/base/libs/hwui/JankTracker.cpp
*/
message DaveyOccurred {
+ // The UID that logged this atom.
+ optional int32 uid = 1;
+
// Amount of time it took to render the frame. Should be >=700ms.
- optional int64 jank_duration_millis = 1;
+ optional int64 jank_duration_millis = 2;
}
/**
@@ -1179,6 +1236,17 @@
optional int64 swap_in_bytes = 8;
}
+/*
+ * Logs when the ActivityManagerService detects that an app died.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message AppDied {
+ // timestamp(elapsedRealtime) of record creation
+ optional uint64 timestamp_millis = 1;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
@@ -1508,7 +1576,8 @@
/**
* Pulls battery coulomb counter, which is the remaining battery charge in uAh.
- * Logged from: frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+ * Pulled from:
+ * frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
*/
message RemainingBatteryCapacity {
optional int32 charge_uAh = 1;
@@ -1516,8 +1585,26 @@
/**
* Pulls battery capacity, which is the battery capacity when full in uAh.
- * Logged from: frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+ * Pulled from:
+ * frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
*/
message FullBatteryCapacity {
optional int32 capacity_uAh = 1;
-}
\ No newline at end of file
+}
+
+/**
+ * Pulls the temperature of various parts of the device, in Celsius.
+ *
+ * Pulled from:
+ * frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
+ */
+message Temperature {
+ // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY.
+ optional android.os.TemperatureTypeEnum sensor_location = 1;
+
+ // The name of the temperature source. Eg. CPU0
+ optional string sensor_name = 2;
+
+ // Temperature in degrees C.
+ optional float temperature_C = 3;
+}
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
index e2e0253..2a5679c 100644
--- a/cmds/statsd/src/external/Perfetto.h
+++ b/cmds/statsd/src/external/Perfetto.h
@@ -16,6 +16,8 @@
#pragma once
+#include <android/os/StatsLogEventWrapper.h>
+
using android::os::StatsLogEventWrapper;
namespace android {
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index 261cb43..3741202 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define DEBUG true // STOPSHIP if true
+#define DEBUG false // STOPSHIP if true
#include "Log.h"
#include <android/hardware/health/2.0/IHealth.h>
@@ -47,7 +47,6 @@
bool getHealthHal() {
if (gHealthHal == nullptr) {
gHealthHal = get_health_service();
-
}
return gHealthHal != nullptr;
}
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
new file mode 100644
index 0000000..b3acdfc
--- /dev/null
+++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include <android/hardware/thermal/1.0/IThermal.h>
+#include "external/ResourceThermalManagerPuller.h"
+#include "external/StatsPuller.h"
+
+#include "ResourceThermalManagerPuller.h"
+#include "logd/LogEvent.h"
+#include "statslog.h"
+#include "stats_log_util.h"
+
+#include <chrono>
+
+using android::hardware::hidl_death_recipient;
+using android::hardware::hidl_vec;
+using android::hidl::base::V1_0::IBase;
+using android::hardware::thermal::V1_0::IThermal;
+using android::hardware::thermal::V1_0::Temperature;
+using android::hardware::thermal::V1_0::ThermalStatus;
+using android::hardware::thermal::V1_0::ThermalStatusCode;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using std::chrono::duration_cast;
+using std::chrono::nanoseconds;
+using std::chrono::system_clock;
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool getThermalHalLocked();
+sp<android::hardware::thermal::V1_0::IThermal> gThermalHal = nullptr;
+std::mutex gThermalHalMutex;
+
+struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
+ std::lock_guard<std::mutex> lock(gThermalHalMutex);
+ ALOGE("ThermalHAL just died");
+ gThermalHal = nullptr;
+ getThermalHalLocked();
+ }
+};
+
+sp<ThermalHalDeathRecipient> gThermalHalDeathRecipient = nullptr;
+
+// The caller must be holding gThermalHalMutex.
+bool getThermalHalLocked() {
+ if (gThermalHal == nullptr) {
+ gThermalHal = IThermal::getService();
+ if (gThermalHal == nullptr) {
+ ALOGE("Unable to get Thermal service.");
+ } else {
+ if (gThermalHalDeathRecipient == nullptr) {
+ gThermalHalDeathRecipient = new ThermalHalDeathRecipient();
+ }
+ hardware::Return<bool> linked = gThermalHal->linkToDeath(
+ gThermalHalDeathRecipient, 0x451F /* cookie */);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to ThermalHAL death: %s",
+ linked.description().c_str());
+ gThermalHal = nullptr;
+ } else if (!linked) {
+ ALOGW("Unable to link to ThermalHal death notifications");
+ gThermalHal = nullptr;
+ } else {
+ ALOGD("Link to death notification successful");
+ }
+ }
+ }
+ return gThermalHal != nullptr;
+}
+
+ResourceThermalManagerPuller::ResourceThermalManagerPuller() :
+ StatsPuller(android::util::TEMPERATURE) {
+}
+
+bool ResourceThermalManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ std::lock_guard<std::mutex> lock(gThermalHalMutex);
+ if (!getThermalHalLocked()) {
+ ALOGE("Thermal Hal not loaded");
+ return false;
+ }
+
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+
+ data->clear();
+ bool resultSuccess = true;
+
+ Return<void> ret = gThermalHal->getTemperatures(
+ [&](ThermalStatus status, const hidl_vec<Temperature>& temps) {
+ if (status.code != ThermalStatusCode::SUCCESS) {
+ ALOGE("Failed to get temperatures from ThermalHAL. Status: %d", status.code);
+ resultSuccess = false;
+ return;
+ }
+ if (mTagId == android::util::TEMPERATURE) {
+ for (size_t i = 0; i < temps.size(); ++i) {
+ auto ptr = make_shared<LogEvent>(android::util::TEMPERATURE,
+ wallClockTimestampNs, elapsedTimestampNs);
+ ptr->write((static_cast<int>(temps[i].type)));
+ ptr->write(temps[i].name);
+ ptr->write(temps[i].currentValue);
+ ptr->init();
+ data->push_back(ptr);
+ }
+ } else {
+ ALOGE("Unsupported tag in ResourceThermalManagerPuller: %d", mTagId);
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("getThermalHalLocked() failed: thermal HAL service not available. Description: %s",
+ ret.description().c_str());
+ if (ret.isDeadObject()) {
+ gThermalHal = nullptr;
+ }
+ return false;
+ }
+ return resultSuccess;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.h b/cmds/statsd/src/external/ResourceThermalManagerPuller.h
new file mode 100644
index 0000000..13c675a
--- /dev/null
+++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Reads IThermal.hal
+ */
+class ResourceThermalManagerPuller : public StatsPuller {
+public:
+ ResourceThermalManagerPuller();
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index bee9939..880dfd1 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -23,10 +23,10 @@
#include <climits>
#include "CpuTimePerUidFreqPuller.h"
#include "CpuTimePerUidPuller.h"
-#include "ResourceHealthManagerPuller.h"
#include "KernelUidCpuActiveTimeReader.h"
#include "KernelUidCpuClusterTimeReader.h"
-#include "SubsystemSleepStatePuller.h"
+#include "ResourceHealthManagerPuller.h"
+#include "ResourceThermalManagerPuller.h"
#include "StatsCompanionServicePuller.h"
#include "StatsPullerManagerImpl.h"
#include "StatsService.h"
@@ -118,7 +118,9 @@
{{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}};
+ {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
+ // temperature
+ {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}};
StatsPullerManagerImpl::StatsPullerManagerImpl()
: mCurrentPullingInterval(LONG_MAX) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 66cb1d0..0881d44 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -47,11 +47,13 @@
const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
// const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp
const int FIELD_ID_LOGGER_ERROR_STATS = 11;
+const int FIELD_ID_SUBSCRIBER_ALARM_STATS = 12;
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
+const int FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED = 1;
const int FIELD_ID_LOGGER_STATS_TIME = 1;
const int FIELD_ID_LOGGER_STATS_ERROR_CODE = 2;
@@ -248,6 +250,11 @@
mAnomalyAlarmRegisteredStats++;
}
+void StatsdStats::noteRegisteredPeriodicAlarmChanged() {
+ lock_guard<std::mutex> lock(mLock);
+ mPeriodicAlarmRegisteredStats++;
+}
+
void StatsdStats::updateMinPullIntervalSec(int pullAtomId, long intervalSec) {
lock_guard<std::mutex> lock(mLock);
mPulledAtomStats[pullAtomId].minPullIntervalSec = intervalSec;
@@ -297,6 +304,7 @@
std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
mAlertStats.clear();
mAnomalyAlarmRegisteredStats = 0;
+ mPeriodicAlarmRegisteredStats = 0;
mMatcherStats.clear();
mLoggerErrors.clear();
for (auto& config : mConfigStats) {
@@ -367,7 +375,7 @@
fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
for (const auto& configStats : mIceBox) {
fprintf(out,
- "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+ "Config {%d_%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
"#matcher=%d, #alert=%d, valid=%d\n",
configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
configStats.deletion_time_sec(), configStats.metric_count(),
@@ -462,6 +470,11 @@
fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
}
+ if (mPeriodicAlarmRegisteredStats > 0) {
+ fprintf(out, "********SubscriberAlarmStats stats***********\n");
+ fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
+ }
+
fprintf(out,
"UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
"lost=%d\n",
@@ -531,6 +544,13 @@
proto.end(token);
}
+ if (mPeriodicAlarmRegisteredStats > 0) {
+ long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_SUBSCRIBER_ALARM_STATS);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED,
+ mPeriodicAlarmRegisteredStats);
+ proto.end(token);
+ }
+
const int numBytes = mUidMapStats.ByteSize();
vector<char> buffer(numBytes);
mUidMapStats.SerializeToArray(&buffer[0], numBytes);
@@ -566,4 +586,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 8c16e4e..24ac688 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -170,6 +170,11 @@
void noteRegisteredAnomalyAlarmChanged();
/**
+ * Report that statsd modified the periodic alarm registered with StatsCompanionService.
+ */
+ void noteRegisteredPeriodicAlarmChanged();
+
+ /**
* Records the number of snapshot and delta entries that are being dropped from the uid map.
*/
void noteUidMapDropped(int snapshots, int deltas);
@@ -264,6 +269,9 @@
// StatsCompanionService.
int mAnomalyAlarmRegisteredStats = 0;
+ // Stores the number of times statsd registers the periodic alarm changes
+ int mPeriodicAlarmRegisteredStats = 0;
+
// Stores the number of times an anomaly detection alert has been declared
// (per config, per alert name). The map size is capped by kMaxConfigCount.
std::map<const ConfigKey, std::map<const int64_t, int>> mAlertStats;
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 4612009..5d5e64e 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -87,6 +87,10 @@
const string& str_match) {
if (isAttributionUidField(field, value)) {
int uid = value.int_value;
+ auto aidIt = UidMap::sAidToUidMapping.find(str_match);
+ if (aidIt != UidMap::sAidToUidMapping.end()) {
+ return ((int)aidIt->second) == uid;
+ }
std::set<string> packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/);
return packageNames.find(str_match) != packageNames.end();
} else if (value.getType() == STRING) {
@@ -207,6 +211,9 @@
}
return false;
}
+ // Finally, we get to the point of real value matching.
+ // If the field matcher ends with ANY, then we have [start, end) range > 1.
+ // In the following, we should return true, when ANY of the values matches.
case FieldValueMatcher::ValueMatcherCase::kEqBool: {
for (int i = start; i < end; i++) {
if ((values[i].mValue.getType() == INT &&
@@ -225,9 +232,36 @@
return true;
}
}
- }
return false;
- case FieldValueMatcher::ValueMatcherCase::kEqInt:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kNeqAllString: {
+ const auto& str_list = matcher.neq_all_string();
+ for (int i = start; i < end; i++) {
+ bool notEqAll = true;
+ for (const auto& str : str_list.str_value()) {
+ if (tryMatchString(uidMap, values[i].mField, values[i].mValue, str)) {
+ notEqAll = false;
+ break;
+ }
+ }
+ if (notEqAll) {
+ return true;
+ }
+ }
+ return false;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqAnyString: {
+ const auto& str_list = matcher.eq_any_string();
+ for (int i = start; i < end; i++) {
+ for (const auto& str : str_list.str_value()) {
+ if (tryMatchString(uidMap, values[i].mField, values[i].mValue, str)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(matcher.eq_int() == values[i].mValue.int_value)) {
@@ -240,7 +274,8 @@
}
}
return false;
- case FieldValueMatcher::ValueMatcherCase::kLtInt:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLtInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value < matcher.lt_int())) {
@@ -253,7 +288,8 @@
}
}
return false;
- case FieldValueMatcher::ValueMatcherCase::kGtInt:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGtInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value > matcher.gt_int())) {
@@ -266,7 +302,8 @@
}
}
return false;
- case FieldValueMatcher::ValueMatcherCase::kLtFloat:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == FLOAT &&
(values[i].mValue.float_value < matcher.lt_float())) {
@@ -274,7 +311,8 @@
}
}
return false;
- case FieldValueMatcher::ValueMatcherCase::kGtFloat:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == FLOAT &&
(values[i].mValue.float_value > matcher.gt_float())) {
@@ -282,7 +320,8 @@
}
}
return false;
- case FieldValueMatcher::ValueMatcherCase::kLteInt:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLteInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value <= matcher.lte_int())) {
@@ -295,7 +334,8 @@
}
}
return false;
- case FieldValueMatcher::ValueMatcherCase::kGteInt:
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGteInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value >= matcher.gte_int())) {
@@ -308,6 +348,7 @@
}
}
return false;
+ }
default:
return false;
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 9c65371..80329c3 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -101,6 +101,18 @@
}
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
+ if (mDimensionsInWhat.size() == mInternalDimensions.size()) {
+ bool mUseWhatDimensionAsInternalDimension = true;
+ for (size_t i = 0; mUseWhatDimensionAsInternalDimension &&
+ i < mDimensionsInWhat.size(); ++i) {
+ if (mDimensionsInWhat[i] != mInternalDimensions[i]) {
+ mUseWhatDimensionAsInternalDimension = false;
+ }
+ }
+ } else {
+ mUseWhatDimensionAsInternalDimension = false;
+ }
+
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -109,9 +121,11 @@
VLOG("~DurationMetric() called");
}
-sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
+sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
+ const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
std::lock_guard<std::mutex> lock(mMutex);
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey);
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
if (anomalyTracker != nullptr) {
mAnomalyTrackers.push_back(anomalyTracker);
}
@@ -139,29 +153,56 @@
flushIfNeededLocked(eventTime);
// Now for each of the on-going event, check if the condition has changed for them.
- for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- pair.second->onSlicedConditionMayChange(eventTime);
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ for (auto& pair : whatIt.second) {
+ pair.second->onSlicedConditionMayChange(eventTime);
+ }
}
-
- std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
- mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
- &conditionDimensionsKeySet);
-
- for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- conditionDimensionsKeySet.erase(pair.first.getDimensionKeyInCondition());
+ if (mDimensionsInCondition.empty()) {
+ return;
}
- std::unordered_set<MetricDimensionKey> newKeys;
- for (const auto& conditionDimensionsKey : conditionDimensionsKeySet) {
- for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- auto newKey =
- MetricDimensionKey(pair.first.getDimensionKeyInWhat(), conditionDimensionsKey);
- if (newKeys.find(newKey) == newKeys.end()) {
- mCurrentSlicedDurationTrackerMap[newKey] = pair.second->clone(eventTime);
- mCurrentSlicedDurationTrackerMap[newKey]->setEventKey(newKey);
- mCurrentSlicedDurationTrackerMap[newKey]->onSlicedConditionMayChange(eventTime);
+
+ if (mMetric2ConditionLinks.empty()) {
+ std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
+ mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
+ &conditionDimensionsKeySet);
+ for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ for (const auto& pair : whatIt.second) {
+ conditionDimensionsKeySet.erase(pair.first);
}
- newKeys.insert(newKey);
+ }
+ for (const auto& conditionDimension : conditionDimensionsKeySet) {
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ if (!whatIt.second.empty()) {
+ unique_ptr<DurationTracker> newTracker =
+ whatIt.second.begin()->second->clone(eventTime);
+ newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension));
+ newTracker->onSlicedConditionMayChange(eventTime);
+ whatIt.second[conditionDimension] = std::move(newTracker);
+ }
+ }
+ }
+ } else {
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ ConditionKey conditionKey;
+ for (const auto& link : mMetric2ConditionLinks) {
+ getDimensionForCondition(whatIt.first.getValues(), link,
+ &conditionKey[link.conditionId]);
+ }
+ std::unordered_set<HashableDimensionKey> conditionDimensionsKeys;
+ mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
+ &conditionDimensionsKeys);
+
+ for (const auto& conditionDimension : conditionDimensionsKeys) {
+ if (!whatIt.second.empty() &&
+ whatIt.second.find(conditionDimension) == whatIt.second.end()) {
+ auto newTracker = whatIt.second.begin()->second->clone(eventTime);
+ newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension));
+ newTracker->onSlicedConditionMayChange(eventTime);
+ whatIt.second[conditionDimension] = std::move(newTracker);
+ }
+ }
}
}
}
@@ -173,8 +214,10 @@
flushIfNeededLocked(eventTime);
// TODO: need to populate the condition change time from the event which triggers the condition
// change, instead of using current time.
- for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- pair.second->onConditionChanged(conditionMet, eventTime);
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ for (auto& pair : whatIt.second) {
+ pair.second->onConditionChanged(conditionMet, eventTime);
+ }
}
}
@@ -239,13 +282,20 @@
return;
}
VLOG("flushing...........");
- for (auto it = mCurrentSlicedDurationTrackerMap.begin();
- it != mCurrentSlicedDurationTrackerMap.end();) {
- if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s", it->first.c_str());
- it = mCurrentSlicedDurationTrackerMap.erase(it);
+ for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
+ whatIt != mCurrentSlicedDurationTrackerMap.end();) {
+ for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
+ if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
+ VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str());
+ it = whatIt->second.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ if (whatIt->second.empty()) {
+ whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
} else {
- ++it;
+ whatIt++;
}
}
@@ -255,13 +305,20 @@
}
void DurationMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
- for (auto it = mCurrentSlicedDurationTrackerMap.begin();
- it != mCurrentSlicedDurationTrackerMap.end();) {
- if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s", it->first.c_str());
- it = mCurrentSlicedDurationTrackerMap.erase(it);
+ for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
+ whatIt != mCurrentSlicedDurationTrackerMap.end();) {
+ for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
+ if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
+ VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str());
+ it = whatIt->second.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ if (whatIt->second.empty()) {
+ whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
} else {
- ++it;
+ whatIt++;
}
}
}
@@ -274,18 +331,16 @@
fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId,
(unsigned long)mCurrentSlicedDurationTrackerMap.size());
if (verbose) {
- for (const auto& slice : mCurrentSlicedDurationTrackerMap) {
- fprintf(out, "\t%s\n", slice.first.c_str());
- slice.second->dumpStates(out, verbose);
+ for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ for (const auto& slice : whatIt.second) {
+ fprintf(out, "\t%s\t%s\n", whatIt.first.c_str(), slice.first.c_str());
+ slice.second->dumpStates(out, verbose);
+ }
}
}
}
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
- // the key is not new, we are good.
- if (mCurrentSlicedDurationTrackerMap.find(newKey) != mCurrentSlicedDurationTrackerMap.end()) {
- return false;
- }
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
@@ -300,49 +355,162 @@
return false;
}
-void DurationMetricProducer::onMatchedLogEventInternalLocked(
- const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKeys, bool condition,
- const LogEvent& event) {
- flushIfNeededLocked(event.GetElapsedTimestampNs());
+void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
+ const ConditionKey& conditionKeys,
+ bool condition, const LogEvent& event) {
+ const auto& whatKey = eventKey.getDimensionKeyInWhat();
+ const auto& condKey = eventKey.getDimensionKeyInCondition();
- if (matcherIndex == mStopAllIndex) {
- for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- pair.second->noteStopAll(event.GetElapsedTimestampNs());
- }
- return;
- }
-
- if (mCurrentSlicedDurationTrackerMap.find(eventKey) == mCurrentSlicedDurationTrackerMap.end()) {
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
+ if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDurationTrackerMap[eventKey] = createDurationTracker(eventKey);
+ mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
+ } else {
+ if (whatIt->second.find(condKey) == whatIt->second.end()) {
+ if (hitGuardRailLocked(eventKey)) {
+ return;
+ }
+ mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
+ }
}
- auto it = mCurrentSlicedDurationTrackerMap.find(eventKey);
+ auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(condKey);
+ if (mUseWhatDimensionAsInternalDimension) {
+ it->second->noteStart(whatKey, condition,
+ event.GetElapsedTimestampNs(), conditionKeys);
+ return;
+ }
std::vector<HashableDimensionKey> values;
filterValues(mInternalDimensions, event.getValues(), &values);
if (values.empty()) {
- if (matcherIndex == mStartIndex) {
- it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
- event.GetElapsedTimestampNs(), conditionKeys);
- } else if (matcherIndex == mStopIndex) {
- it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetElapsedTimestampNs(), false);
- }
+ it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
+ event.GetElapsedTimestampNs(), conditionKeys);
} else {
for (const auto& value : values) {
- if (matcherIndex == mStartIndex) {
- it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
- } else if (matcherIndex == mStopIndex) {
- it->second->noteStop(value, event.GetElapsedTimestampNs(), false);
- }
+ it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
}
}
}
+void DurationMetricProducer::onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const MetricDimensionKey& eventKey,
+ const ConditionKey& conditionKeys, bool condition,
+ const LogEvent& event) {
+ ALOGW("Not used in duration tracker.");
+}
+
+void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
+ const LogEvent& event) {
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
+ if (eventTimeNs < mStartTimeNs) {
+ return;
+ }
+
+ flushIfNeededLocked(event.GetElapsedTimestampNs());
+
+ // Handles Stopall events.
+ if (matcherIndex == mStopAllIndex) {
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ for (auto& pair : whatIt.second) {
+ pair.second->noteStopAll(event.GetElapsedTimestampNs());
+ }
+ }
+ return;
+ }
+
+ vector<HashableDimensionKey> dimensionInWhatValues;
+ if (!mDimensionsInWhat.empty()) {
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
+ } else {
+ dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
+ }
+
+ // Handles Stop events.
+ if (matcherIndex == mStopIndex) {
+ if (mUseWhatDimensionAsInternalDimension) {
+ for (const HashableDimensionKey& whatKey : dimensionInWhatValues) {
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ condIt.second->noteStop(whatKey, event.GetElapsedTimestampNs(), false);
+ }
+ }
+ }
+ return;
+ }
+
+ std::vector<HashableDimensionKey> internalDimensionKeys;
+ filterValues(mInternalDimensions, event.getValues(), &internalDimensionKeys);
+ if (internalDimensionKeys.empty()) {
+ internalDimensionKeys.push_back(DEFAULT_DIMENSION_KEY);
+ }
+ for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) {
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ for (const auto& internalDimensionKey : internalDimensionKeys) {
+ condIt.second->noteStop(
+ internalDimensionKey, event.GetElapsedTimestampNs(), false);
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ bool condition;
+ ConditionKey conditionKey;
+ std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
+ if (mConditionSliced) {
+ for (const auto& link : mMetric2ConditionLinks) {
+ getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
+ }
+
+ auto conditionState =
+ mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
+ &dimensionKeysInCondition);
+ condition = (conditionState == ConditionState::kTrue);
+ if (mDimensionsInCondition.empty() && condition) {
+ dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
+ }
+ } else {
+ condition = mCondition;
+ if (condition) {
+ dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
+ }
+ }
+
+ for (const auto& whatDimension : dimensionInWhatValues) {
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
+ // If the what dimension is already there, we should update all the trackers even
+ // the condition is false.
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ const bool cond = dimensionKeysInCondition.find(condIt.first) !=
+ dimensionKeysInCondition.end();
+ handleStartEvent(MetricDimensionKey(whatDimension, condIt.first),
+ conditionKey, cond, event);
+ }
+ } else {
+ // If it is a new what dimension key, we need to handle the start events for all current
+ // condition dimensions.
+ for (const auto& conditionDimension : dimensionKeysInCondition) {
+ handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension),
+ conditionKey, condition, event);
+ }
+ }
+ if (dimensionKeysInCondition.empty()) {
+ handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
+ }
+ }
+}
+
+
size_t DurationMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 5f29281..73d074f 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -46,15 +46,20 @@
virtual ~DurationMetricProducer();
- sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) override;
+ sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor) override;
protected:
+ void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKeys, bool condition,
const LogEvent& event) override;
private:
+ void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys,
+ bool condition, const LogEvent& event);
+
void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) override;
@@ -91,12 +96,16 @@
// The dimension from the atom predicate. e.g., uid, wakelock name.
vector<Matcher> mInternalDimensions;
+ // This boolean is true iff When mInternalDimensions == mDimensionsInWhat
+ bool mUseWhatDimensionAsInternalDimension;
+
// Save the past buckets and we can clear when the StatsLogReport is dumped.
// TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
- // The current bucket.
- std::unordered_map<MetricDimensionKey, std::unique_ptr<DurationTracker>>
+ // The duration trackers in the current bucket.
+ std::unordered_map<HashableDimensionKey,
+ std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>>
mCurrentSlicedDurationTrackerMap;
// Helper function to create a duration tracker given the metric aggregation type.
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index f3307dc..18694a1 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -37,7 +37,7 @@
std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
if (mConditionSliced) {
for (const auto& link : mMetric2ConditionLinks) {
- getDimensionForCondition(event, link, &conditionKey[link.conditionId]);
+ getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
}
auto conditionState =
@@ -48,37 +48,30 @@
condition = mCondition;
}
- vector<HashableDimensionKey> dimensionInWhatValues;
- if (mDimensionsInWhat.size() > 0) {
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
+ if (mDimensionsInCondition.empty() && condition) {
+ dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
- if (dimensionInWhatValues.empty() && dimensionKeysInCondition.empty()) {
- onMatchedLogEventInternalLocked(
- matcherIndex, DEFAULT_METRIC_DIMENSION_KEY, conditionKey, condition, event);
- } else if (dimensionKeysInCondition.empty()) {
- for (const HashableDimensionKey& whatValue : dimensionInWhatValues) {
- onMatchedLogEventInternalLocked(matcherIndex,
- MetricDimensionKey(whatValue, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
- }
- } else if (dimensionInWhatValues.empty()) {
+ vector<HashableDimensionKey> dimensionInWhatValues;
+ if (!mDimensionsInWhat.empty()) {
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
+ } else {
+ dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
+ }
+
+ for (const auto& whatDimension : dimensionInWhatValues) {
for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
onMatchedLogEventInternalLocked(
- matcherIndex,
- MetricDimensionKey(DEFAULT_DIMENSION_KEY, conditionDimensionKey),
- conditionKey, condition, event);
+ matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey),
+ conditionKey, condition, event);
}
- } else {
- for (const auto& whatValue : dimensionInWhatValues) {
- for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
- onMatchedLogEventInternalLocked(
- matcherIndex, MetricDimensionKey(whatValue, conditionDimensionKey),
- conditionKey, condition, event);
- }
+ if (dimensionKeysInCondition.empty()) {
+ onMatchedLogEventInternalLocked(
+ matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
}
}
-}
+ }
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 8663e5e..2bf6241 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -124,7 +124,8 @@
}
/* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
- virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) {
+ virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor) {
std::lock_guard<std::mutex> lock(mMutex);
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
if (anomalyTracker != nullptr) {
@@ -232,7 +233,7 @@
const LogEvent& event) = 0;
// Consume the parsed stats log entry that already matched the "what" of the metric.
- void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
+ virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
mutable std::mutex mMutex;
};
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index e75b710..4c8a7d8 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -49,13 +49,17 @@
const int FIELD_ID_METRICS = 1;
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
- const long timeBaseSec, sp<UidMap> uidMap)
+ const long timeBaseSec,
+ const sp<UidMap> &uidMap,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor)
: mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) {
mConfigValid =
- initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers,
- mAllConditionTrackers,
- mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
- mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
+ initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, mTagIds, mAllAtomMatchers,
+ mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
+ mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
+ mTrackerToConditionMap, mNoReportMetricIds);
if (config.allowed_log_source_size() == 0) {
// TODO(b/70794411): uncomment the following line and remove the hard coded log source
@@ -198,31 +202,59 @@
// Uid is 3rd from last field and must match the caller's uid,
// unless that caller is statsd itself (statsd is allowed to spoof uids).
long appHookUid = event.GetLong(event.size()-2, &err);
+ if (err != NO_ERROR ) {
+ VLOG("APP_BREADCRUMB_REPORTED had error when parsing the uid");
+ return;
+ }
int32_t loggerUid = event.GetUid();
- if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != AID_STATSD)) {
- VLOG("AppHook has invalid uid: claimed %ld but caller is %d", appHookUid, loggerUid);
+ if (loggerUid != appHookUid && loggerUid != AID_STATSD) {
+ VLOG("APP_BREADCRUMB_REPORTED has invalid uid: claimed %ld but caller is %d",
+ appHookUid, loggerUid);
return;
}
// Label is 2nd from last field and must be from [0, 15].
long appHookLabel = event.GetLong(event.size()-1, &err);
- if (err != NO_ERROR || appHookLabel < 0 || appHookLabel > 15) {
- VLOG("AppHook does not have valid label %ld", appHookLabel);
+ if (err != NO_ERROR ) {
+ VLOG("APP_BREADCRUMB_REPORTED had error when parsing the label field");
+ return;
+ } else if (appHookLabel < 0 || appHookLabel > 15) {
+ VLOG("APP_BREADCRUMB_REPORTED does not have valid label %ld", appHookLabel);
return;
}
// The state must be from 0,3. This part of code must be manually updated.
long appHookState = event.GetLong(event.size(), &err);
- if (err != NO_ERROR || appHookState < 0 || appHookState > 3) {
- VLOG("AppHook does not have valid state %ld", appHookState);
+ if (err != NO_ERROR ) {
+ VLOG("APP_BREADCRUMB_REPORTED had error when parsing the state field");
+ return;
+ } else if (appHookState < 0 || appHookState > 3) {
+ VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
return;
}
} else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
// Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
// Check that the davey duration is reasonable. Max length check is for privacy.
status_t err = NO_ERROR;
+
+ // Uid is the first field provided.
+ long jankUid = event.GetLong(1, &err);
+ if (err != NO_ERROR ) {
+ VLOG("Davey occurred had error when parsing the uid");
+ return;
+ }
+ int32_t loggerUid = event.GetUid();
+ if (loggerUid != jankUid && loggerUid != AID_STATSD) {
+ VLOG("DAVEY_OCCURRED has invalid uid: claimed %ld but caller is %d", jankUid,
+ loggerUid);
+ return;
+ }
+
long duration = event.GetLong(event.size(), &err);
- if (err != NO_ERROR || duration > 100000) {
+ if (err != NO_ERROR ) {
+ VLOG("Davey occurred had error when parsing the duration");
+ return;
+ } else if (duration > 100000) {
VLOG("Davey duration is unreasonably long: %ld", duration);
return;
}
@@ -312,16 +344,19 @@
}
}
-void MetricsManager::onAnomalyAlarmFired(const uint64_t timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet) {
+void MetricsManager::onAnomalyAlarmFired(
+ const uint64_t timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
for (const auto& itr : mAllAnomalyTrackers) {
- itr->informAlarmsFired(timestampNs, anomalySet);
+ itr->informAlarmsFired(timestampNs, alarmSet);
}
}
-void MetricsManager::setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
- for (auto& itr : mAllAnomalyTrackers) {
- itr->setAnomalyMonitor(anomalyMonitor);
+void MetricsManager::onPeriodicAlarmFired(
+ const uint64_t timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
+ for (const auto& itr : mAllPeriodicAlarmTrackers) {
+ itr->informAlarmsFired(timestampNs, alarmSet);
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d4f844f..b50ef4a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -16,7 +16,8 @@
#pragma once
-#include "anomaly/AnomalyMonitor.h"
+#include "anomaly/AlarmMonitor.h"
+#include "anomaly/AlarmTracker.h"
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionTracker.h"
#include "config/ConfigKey.h"
@@ -36,7 +37,8 @@
class MetricsManager : public PackageInfoListener {
public:
MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec,
- sp<UidMap> uidMap);
+ const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor);
virtual ~MetricsManager();
@@ -47,9 +49,11 @@
void onAnomalyAlarmFired(
const uint64_t timestampNs,
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& anomalySet);
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
- void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
+ void onPeriodicAlarmFired(
+ const uint64_t timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
const int64_t version) override;
@@ -120,6 +124,9 @@
// Hold all alert trackers.
std::vector<sp<AnomalyTracker>> mAllAnomalyTrackers;
+ // Hold all periodic alarm trackers.
+ std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers;
+
// To make the log processing more efficient, we want to do as much filtering as possible
// before we go into individual trackers and conditions to match.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 71e5c33..9912afa 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -17,16 +17,19 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
+#include "metrics_manager_util.h"
+
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
-#include "CountMetricProducer.h"
-#include "DurationMetricProducer.h"
-#include "EventMetricProducer.h"
-#include "GaugeMetricProducer.h"
-#include "ValueMetricProducer.h"
+#include "../metrics/CountMetricProducer.h"
+#include "../metrics/DurationMetricProducer.h"
+#include "../metrics/EventMetricProducer.h"
+#include "../metrics/GaugeMetricProducer.h"
+#include "../metrics/ValueMetricProducer.h"
+
#include "stats_util.h"
using std::set;
@@ -494,6 +497,7 @@
bool initAlerts(const StatsdConfig& config,
const unordered_map<int64_t, int>& metricProducerMap,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
unordered_map<int64_t, int> anomalyTrackerMap;
@@ -512,7 +516,7 @@
}
const int metricIndex = itr->second;
sp<MetricProducer> metric = allMetricProducers[metricIndex];
- sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
if (anomalyTracker == nullptr) {
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
return false;
@@ -522,6 +526,9 @@
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
+ if (subscription.rule_type() != Subscription::ALERT) {
+ continue;
+ }
if (subscription.subscriber_information_case() ==
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
ALOGW("subscription \"%lld\" has no subscriber info.\"",
@@ -540,13 +547,60 @@
return true;
}
+bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
+ const sp<AlarmMonitor>& periodicAlarmMonitor,
+ const long timeBaseSec,
+ vector<sp<AlarmTracker>>& allAlarmTrackers) {
+ unordered_map<int64_t, int> alarmTrackerMap;
+ uint64_t startMillis = (uint64_t)timeBaseSec * MS_PER_SEC;
+ for (int i = 0; i < config.alarm_size(); i++) {
+ const Alarm& alarm = config.alarm(i);
+ if (alarm.offset_millis() <= 0) {
+ ALOGW("Alarm offset_millis should be larger than 0.");
+ return false;
+ }
+ if (alarm.period_millis() <= 0) {
+ ALOGW("Alarm period_millis should be larger than 0.");
+ return false;
+ }
+ alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
+ allAlarmTrackers.push_back(
+ new AlarmTracker(startMillis, alarm, key, periodicAlarmMonitor));
+ }
+ for (int i = 0; i < config.subscription_size(); ++i) {
+ const Subscription& subscription = config.subscription(i);
+ if (subscription.rule_type() != Subscription::ALARM) {
+ continue;
+ }
+ if (subscription.subscriber_information_case() ==
+ Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
+ ALOGW("subscription \"%lld\" has no subscriber info.\"",
+ (long long)subscription.id());
+ return false;
+ }
+ const auto& itr = alarmTrackerMap.find(subscription.rule_id());
+ if (itr == alarmTrackerMap.end()) {
+ ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
+ (long long)subscription.id(), (long long)subscription.rule_id());
+ return false;
+ }
+ const int trackerIndex = itr->second;
+ allAlarmTrackers[trackerIndex]->addSubscription(subscription);
+ }
+ return true;
+}
+
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
const UidMap& uidMap,
- const long timeBaseSec, set<int>& allTagIds,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor,
+ const long timeBaseSec,
+ set<int>& allTagIds,
vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
+ vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
unordered_map<int, std::vector<int>>& trackerToConditionMap,
@@ -573,10 +627,16 @@
ALOGE("initMetricProducers failed");
return false;
}
- if (!initAlerts(config, metricProducerMap, allMetricProducers, allAnomalyTrackers)) {
+ if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
+ allAnomalyTrackers)) {
ALOGE("initAlerts failed");
return false;
}
+ if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseSec, allPeriodicAlarmTrackers)) {
+ ALOGE("initAlarms failed");
+ return false;
+ }
+
return true;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 4f19ada..edda53d 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -13,16 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef METRIC_UTIL_H
-#define METRIC_UTIL_H
+
+#pragma once
+
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
+#include "../anomaly/AlarmTracker.h"
#include "../condition/ConditionTracker.h"
#include "../external/StatsPullerManagerImpl.h"
#include "../matchers/LogMatchingTracker.h"
+#include "../metrics/MetricProducer.h"
namespace android {
namespace os {
@@ -93,11 +96,15 @@
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
const UidMap& uidMap,
- const long timeBaseSec, std::set<int>& allTagIds,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor,
+ const long timeBaseSec,
+ std::set<int>& allTagIds,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
+ vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
@@ -106,4 +113,3 @@
} // namespace statsd
} // namespace os
} // namespace android
-#endif // METRIC_UTIL_H
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 272e90b..269f25b 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -164,4 +164,4 @@
optional ConfigKey config_key = 1;
repeated ConfigMetricsReport reports = 2;
-}
\ No newline at end of file
+}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index a313854..1e8aa12 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -74,6 +74,9 @@
int64 gte_int = 11;
MessageMatcher matches_tuple = 12;
+
+ StringListMatcher eq_any_string = 13;
+ StringListMatcher neq_all_string = 14;
}
}
@@ -81,6 +84,10 @@
repeated FieldValueMatcher field_value_matcher = 1;
}
+message StringListMatcher {
+ repeated string str_value = 1;
+}
+
enum LogicalOperation {
LOGICAL_OPERATION_UNSPECIFIED = 0;
AND = 1;
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 6a1db72..781eced 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -195,6 +195,20 @@
}
}
+bool StorageManager::readFileToString(const char* file, string* content) {
+ int fd = open(file, O_RDONLY | O_CLOEXEC);
+ bool res = false;
+ if (fd != -1) {
+ if (android::base::ReadFdToString(fd, content)) {
+ res = true;
+ } else {
+ VLOG("Failed to read file %s\n", file);
+ }
+ close(fd);
+ }
+ return res;
+}
+
void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap) {
unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
if (dir == NULL) {
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index d319674..6c8ed0a 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -37,6 +37,11 @@
static void writeFile(const char* file, const void* buffer, int numBytes);
/**
+ * Reads the file content to the buffer.
+ */
+ static bool readFileToString(const char* file, string* content);
+
+ /**
* Deletes a single file given a file name.
*/
static void deleteFile(const char* file);
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index d9a8fc8..1c18f67 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -28,10 +28,10 @@
namespace os {
namespace statsd {
-bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
const ConfigKey& configKey) {
if (config.section_size() == 0) {
- VLOG("The alert %lld contains zero section in config(%d,%lld)", alert.id(),
+ VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
configKey.GetUid(), (long long) configKey.GetId());
return false;
}
@@ -39,7 +39,7 @@
IncidentReportArgs incidentReport;
android::os::IncidentHeaderProto header;
- header.set_alert_id(alert.id());
+ header.set_alert_id(rule_id);
header.mutable_config_key()->set_uid(configKey.GetUid());
header.mutable_config_key()->set_id(configKey.GetId());
incidentReport.addHeader(header);
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h
index 229ed77..1b83fe2 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.h
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.h
@@ -26,7 +26,7 @@
/**
* Calls incidentd to trigger an incident report and put in dropbox for uploading.
*/
-bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
const ConfigKey& configKey);
} // namespace statsd
diff --git a/cmds/statsd/tests/AnomalyMonitor_test.cpp b/cmds/statsd/tests/AlarmMonitor_test.cpp
similarity index 70%
rename from cmds/statsd/tests/AnomalyMonitor_test.cpp
rename to cmds/statsd/tests/AlarmMonitor_test.cpp
index 920ca08..1fccb35 100644
--- a/cmds/statsd/tests/AnomalyMonitor_test.cpp
+++ b/cmds/statsd/tests/AlarmMonitor_test.cpp
@@ -12,28 +12,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "anomaly/AnomalyMonitor.h"
+#include "anomaly/AlarmMonitor.h"
#include <gtest/gtest.h>
using namespace android::os::statsd;
#ifdef __ANDROID__
-TEST(AnomalyMonitor, popSoonerThan) {
+TEST(AlarmMonitor, popSoonerThan) {
std::string emptyMetricId;
std::string emptyDimensionId;
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> set;
- AnomalyMonitor am(2);
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> set;
+ AlarmMonitor am(2, [](const sp<IStatsCompanionService>&, int64_t){},
+ [](const sp<IStatsCompanionService>&){});
set = am.popSoonerThan(5);
EXPECT_TRUE(set.empty());
- sp<const AnomalyAlarm> a = new AnomalyAlarm{10};
- sp<const AnomalyAlarm> b = new AnomalyAlarm{20};
- sp<const AnomalyAlarm> c = new AnomalyAlarm{20};
- sp<const AnomalyAlarm> d = new AnomalyAlarm{30};
- sp<const AnomalyAlarm> e = new AnomalyAlarm{40};
- sp<const AnomalyAlarm> f = new AnomalyAlarm{50};
+ sp<const InternalAlarm> a = new InternalAlarm{10};
+ sp<const InternalAlarm> b = new InternalAlarm{20};
+ sp<const InternalAlarm> c = new InternalAlarm{20};
+ sp<const InternalAlarm> d = new InternalAlarm{30};
+ sp<const InternalAlarm> e = new InternalAlarm{40};
+ sp<const InternalAlarm> f = new InternalAlarm{50};
am.add(a);
am.add(b);
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 62bdba4..90c3a2f 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -65,8 +65,12 @@
const int64_t testConfigId = 12345;
TEST(ConfigManagerTest, TestFakeConfig) {
- auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, testConfigId),
- build_fake_config(), 1000, new UidMap());
+ auto metricsManager = std::make_unique<MetricsManager>(
+ ConfigKey(0, testConfigId), build_fake_config(), 1000, new UidMap(),
+ new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
+ [](const sp<IStatsCompanionService>&){}),
+ new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
+ [](const sp<IStatsCompanionService>&){}));
EXPECT_TRUE(metricsManager->isConfigValid());
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 2320a9d..36c6e0c 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -294,6 +294,159 @@
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
}
+TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
+ UidMap uidMap;
+ uidMap.updateMap(
+ {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
+
+ AttributionNodeInternal attribution_node1;
+ attribution_node1.set_uid(1111);
+ attribution_node1.set_tag("location1");
+
+ AttributionNodeInternal attribution_node2;
+ attribution_node2.set_uid(2222);
+ attribution_node2.set_tag("location2");
+
+ AttributionNodeInternal attribution_node3;
+ attribution_node3.set_uid(3333);
+ attribution_node3.set_tag("location3");
+
+ AttributionNodeInternal attribution_node4;
+ attribution_node4.set_uid(1066);
+ attribution_node4.set_tag("location3");
+ std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
+ attribution_node3, attribution_node4};
+
+ // Set up the event
+ LogEvent event(TAG_ID, 0);
+ event.write(attribution_nodes);
+ event.write("some value");
+ // Convert to a LogEvent
+ event.init();
+
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ // Match first node.
+ auto attributionMatcher = simpleMatcher->add_field_value_matcher();
+ attributionMatcher->set_field(FIELD_ID_1);
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
+ ATTRIBUTION_UID_FIELD_ID);
+ auto neqStringList = attributionMatcher->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_neq_all_string();
+ neqStringList->add_str_value("pkg2");
+ neqStringList->add_str_value("pkg3");
+
+ auto fieldMatcher = simpleMatcher->add_field_value_matcher();
+ fieldMatcher->set_field(FIELD_ID_2);
+ fieldMatcher->set_eq_string("some value");
+
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ neqStringList->Clear();
+ neqStringList->add_str_value("pkg1");
+ neqStringList->add_str_value("pkg3");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::ANY);
+ neqStringList->Clear();
+ neqStringList->add_str_value("maps.com");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ neqStringList->Clear();
+ neqStringList->add_str_value("PkG3");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::LAST);
+ neqStringList->Clear();
+ neqStringList->add_str_value("AID_STATSD");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
+TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
+ UidMap uidMap;
+ uidMap.updateMap(
+ {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
+
+ AttributionNodeInternal attribution_node1;
+ attribution_node1.set_uid(1067);
+ attribution_node1.set_tag("location1");
+
+ AttributionNodeInternal attribution_node2;
+ attribution_node2.set_uid(2222);
+ attribution_node2.set_tag("location2");
+
+ AttributionNodeInternal attribution_node3;
+ attribution_node3.set_uid(3333);
+ attribution_node3.set_tag("location3");
+
+ AttributionNodeInternal attribution_node4;
+ attribution_node4.set_uid(1066);
+ attribution_node4.set_tag("location3");
+ std::vector<AttributionNodeInternal> attribution_nodes = {attribution_node1, attribution_node2,
+ attribution_node3, attribution_node4};
+
+ // Set up the event
+ LogEvent event(TAG_ID, 0);
+ event.write(attribution_nodes);
+ event.write("some value");
+ // Convert to a LogEvent
+ event.init();
+
+ // Set up the matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+
+ // Match first node.
+ auto attributionMatcher = simpleMatcher->add_field_value_matcher();
+ attributionMatcher->set_field(FIELD_ID_1);
+ attributionMatcher->set_position(Position::FIRST);
+ attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
+ ATTRIBUTION_UID_FIELD_ID);
+ auto eqStringList = attributionMatcher->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_eq_any_string();
+ eqStringList->add_str_value("AID_ROOT");
+ eqStringList->add_str_value("AID_INCIDENTD");
+
+ auto fieldMatcher = simpleMatcher->add_field_value_matcher();
+ fieldMatcher->set_field(FIELD_ID_2);
+ fieldMatcher->set_eq_string("some value");
+
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ attributionMatcher->set_position(Position::ANY);
+ eqStringList->Clear();
+ eqStringList->add_str_value("AID_STATSD");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ eqStringList->Clear();
+ eqStringList->add_str_value("pkg1");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ auto normalStringField = fieldMatcher->mutable_eq_any_string();
+ normalStringField->add_str_value("some value123");
+ normalStringField->add_str_value("some value");
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ normalStringField->Clear();
+ normalStringField->add_str_value("AID_STATSD");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ eqStringList->Clear();
+ eqStringList->add_str_value("maps.com");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
TEST(AtomMatcherTest, TestBoolMatcher) {
UidMap uidMap;
// Set up the matcher
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index f90ca40..5d8c3f7 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -271,19 +271,25 @@
TEST(MetricsManagerTest, TestGoodConfig) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildGoodConfig();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
EXPECT_EQ(1u, allMetricProducers.size());
@@ -293,112 +299,148 @@
TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildDimensionMetricsWithMultiTags();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildCircleMatchers();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildMissingMatchers();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildMissingPredicate();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildCirclePredicates();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
UidMap uidMap;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
StatsdConfig config = buildAlertWithUnknownMetric();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
+ EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
+ anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
noReportMetricIds));
}
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index cb72697..3238b74 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -41,7 +41,13 @@
*/
class MockMetricsManager : public MetricsManager {
public:
- MockMetricsManager() : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, new UidMap()) {
+ MockMetricsManager() : MetricsManager(
+ ConfigKey(1, 12345), StatsdConfig(), 1000,
+ new UidMap(),
+ new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
+ [](const sp<IStatsCompanionService>&){}),
+ new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
+ [](const sp<IStatsCompanionService>&){})) {
}
MOCK_METHOD0(byteSize, size_t());
@@ -50,9 +56,11 @@
TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
sp<UidMap> m = new UidMap();
- sp<AnomalyMonitor> anomalyMonitor;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
// Construct the processor with a dummy sendBroadcast function that does nothing.
- StatsLogProcessor p(m, anomalyMonitor, 0, [](const ConfigKey& key) {});
+ StatsLogProcessor p(m, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
+ [](const ConfigKey& key) {});
MockMetricsManager mockMetricsManager;
@@ -67,11 +75,11 @@
TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
sp<UidMap> m = new UidMap();
- sp<AnomalyMonitor> anomalyMonitor;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
- StatsLogProcessor p(m, anomalyMonitor, 0, [&broadcastCount](const ConfigKey& key) {
- broadcastCount++;
- });
+ StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
+ [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
MockMetricsManager mockMetricsManager;
@@ -93,9 +101,10 @@
TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
sp<UidMap> m = new UidMap();
- sp<AnomalyMonitor> anomalyMonitor;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
- StatsLogProcessor p(m, anomalyMonitor, 0,
+ StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
[&broadcastCount](const ConfigKey& key) { broadcastCount++; });
MockMetricsManager mockMetricsManager;
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index f26c10d..ca656ed 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -36,9 +36,11 @@
TEST(UidMapTest, TestIsolatedUID) {
sp<UidMap> m = new UidMap();
- sp<AnomalyMonitor> anomalyMonitor;
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
// Construct the processor with a dummy sendBroadcast function that does nothing.
- StatsLogProcessor p(m, anomalyMonitor, 0, [](const ConfigKey& key) {});
+ StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
+ [](const ConfigKey& key) {});
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
addEvent.write(100); // parent UID
addEvent.write(101); // isolated UID
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
new file mode 100644
index 0000000..3330ee9
--- /dev/null
+++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
@@ -0,0 +1,68 @@
+// Copyright (C) 2018 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.
+
+#include "src/anomaly/AlarmTracker.h"
+
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const ConfigKey kConfigKey(0, 12345);
+
+TEST(AlarmTrackerTest, TestTriggerTimestamp) {
+ sp<AlarmMonitor> subscriberAlarmMonitor =
+ new AlarmMonitor(100, [](const sp<IStatsCompanionService>&, int64_t){},
+ [](const sp<IStatsCompanionService>&){});
+ Alarm alarm;
+ alarm.set_offset_millis(15 * MS_PER_SEC);
+ alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr
+ uint64_t startMillis = 100000000 * MS_PER_SEC;
+ AlarmTracker tracker(startMillis, alarm, kConfigKey,
+ subscriberAlarmMonitor);
+
+ EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
+
+ uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
+ std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
+ subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ EXPECT_TRUE(firedAlarmSet.empty());
+ tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
+ EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
+
+ currentTimeSec = startMillis / MS_PER_SEC + 7000;
+ firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ EXPECT_EQ(firedAlarmSet.size(), 1u);
+ tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
+ EXPECT_TRUE(firedAlarmSet.empty());
+ EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15 + 2 * 60 * 60);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 20ddbe9..9a0de0d 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -201,6 +201,7 @@
}
TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
@@ -222,7 +223,7 @@
bucketStartTimeNs);
countProducer.setBucketSize(60 * NS_PER_SEC);
- sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
// Bucket is flushed yet.
@@ -315,6 +316,7 @@
}
TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
+ sp<AlarmMonitor> alarmMonitor;
Alert alert;
alert.set_id(11);
alert.set_metric_id(1);
@@ -337,7 +339,7 @@
bucketStartTimeNs);
countProducer.setBucketSize(60 * NS_PER_SEC);
- sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
int tagId = 1;
LogEvent event1(tagId, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 7969596..1b22d75 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -239,6 +239,7 @@
}
TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
@@ -263,7 +264,7 @@
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
durationProducer.setBucketSize(60 * NS_PER_SEC);
- sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
LogEvent start_event(tagId, startTimeNs);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 0eb8ce2..77b3ace 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -129,6 +129,7 @@
}
TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
GaugeMetric metric;
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
@@ -145,8 +146,9 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /* -1 means no pulling */, bucketStartTimeNs,
pullerManager);
+
gaugeProducer.setBucketSize(60 * NS_PER_SEC);
- sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -339,6 +341,7 @@
}
TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
+ sp<AlarmMonitor> alarmMonitor;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
shared_ptr<MockStatsPullerManager> pullerManager =
@@ -363,7 +366,7 @@
alert.set_num_buckets(2);
const int32_t refPeriodSec = 60;
alert.set_refractory_period_secs(refPeriodSec);
- sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
int tagId = 1;
std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index a164c12..83b1cbf 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -276,13 +276,15 @@
alert.set_num_buckets(2);
const int32_t refPeriodSec = 45;
alert.set_refractory_period_secs(refPeriodSec);
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ sp<AlarmMonitor> alarmMonitor;
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
true, {anomalyTracker});
tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
- sp<const AnomalyAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
+ sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(53ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
// Remove the anomaly alarm when the duration is no longer fully met.
@@ -336,7 +338,9 @@
alert.set_num_buckets(2);
const int32_t refPeriodSec = 45;
alert.set_refractory_period_secs(refPeriodSec);
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ sp<AlarmMonitor> alarmMonitor;
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
true, {anomalyTracker});
@@ -390,7 +394,9 @@
alert.set_num_buckets(2);
const int32_t refPeriodSec = 45;
alert.set_refractory_period_secs(refPeriodSec);
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ sp<AlarmMonitor> alarmMonitor;
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
true, {anomalyTracker});
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index cb731c5..aa41038 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -334,7 +334,9 @@
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ sp<AlarmMonitor> alarmMonitor;
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, {anomalyTracker});
@@ -403,7 +405,9 @@
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ sp<AlarmMonitor> alarmMonitor;
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, false, {anomalyTracker});
@@ -453,14 +457,16 @@
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
+ sp<AlarmMonitor> alarmMonitor;
+ sp<DurationAnomalyTracker> anomalyTracker =
+ new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs,
bucketSizeNs, false, {anomalyTracker});
tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
- sp<const AnomalyAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
+ sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
EXPECT_EQ((long long)(55ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
@@ -487,7 +493,7 @@
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
// Now, at 60s, which is 38s after key1 started again, we have reached 40s of 'on' time.
- std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> firedAlarms({alarm});
+ std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarms({alarm});
anomalyTracker->informAlarmsFired(62 * NS_PER_SEC, firedAlarms);
EXPECT_EQ(0u, anomalyTracker->mAlarms.size());
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index ce4fa32..a0addcc 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -346,6 +346,7 @@
}
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
+ sp<AlarmMonitor> alarmMonitor;
Alert alert;
alert.set_id(101);
alert.set_metric_id(metricId);
@@ -365,7 +366,7 @@
-1 /*not pulled*/, bucketStartTimeNs);
valueProducer.setBucketSize(60 * NS_PER_SEC);
- sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
shared_ptr<LogEvent> event1
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 7568348..242b6eb 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -391,9 +391,10 @@
sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
const ConfigKey& key) {
sp<UidMap> uidMap = new UidMap();
- sp<AnomalyMonitor> anomalyMonitor = new AnomalyMonitor(10); // 10 seconds
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
sp<StatsLogProcessor> processor = new StatsLogProcessor(
- uidMap, anomalyMonitor, timeBaseSec, [](const ConfigKey&){});
+ uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
processor->OnConfigUpdated(key, config);
return processor;
}
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 752b662..2c400e0 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -659,7 +659,6 @@
Landroid/graphics/drawable/GradientDrawable$GradientState;->mPadding:Landroid/graphics/Rect;
Landroid/graphics/drawable/GradientDrawable$GradientState;->mPositions:[F
Landroid/graphics/drawable/GradientDrawable;->mPadding:Landroid/graphics/Rect;
-Landroid/graphics/drawable/Icon;->getResPackage()Ljava/lang/String;
Landroid/graphics/drawable/NinePatchDrawable;->mNinePatchState:Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;
Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;->mNinePatch:Landroid/graphics/NinePatch;
Landroid/graphics/drawable/StateListDrawable;->extractStateSet(Landroid/util/AttributeSet;)[I
@@ -977,8 +976,6 @@
Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V
Landroid/media/RemoteDisplay;->notifyDisplayError(I)V
Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone;
-Landroid/media/Ringtone;->setLooping(Z)V
-Landroid/media/Ringtone;->setVolume(F)V
Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper;
Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler;
Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap;
@@ -2306,6 +2303,12 @@
Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$string;->byteShort:I
+Lcom/android/internal/R$string;->gigabyteShort:I
+Lcom/android/internal/R$string;->kilobyteShort:I
+Lcom/android/internal/R$string;->megabyteShort:I
+Lcom/android/internal/R$string;->petabyteShort:I
+Lcom/android/internal/R$string;->terabyteShort:I
Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 03faeee..2d73ce0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -44,7 +44,6 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
-import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -71,6 +70,7 @@
import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.MemInfoReader;
import com.android.server.LocalServices;
import org.xmlpull.v1.XmlSerializer;
@@ -964,6 +964,17 @@
}
/**
+ * Return the total number of bytes of RAM this device has.
+ * @hide
+ */
+ @TestApi
+ public long getTotalRam() {
+ MemInfoReader memreader = new MemInfoReader();
+ memreader.readMemInfo();
+ return memreader.getTotalSize();
+ }
+
+ /**
* Return the maximum number of recents entries that we will maintain and show.
* @hide
*/
@@ -2751,30 +2762,6 @@
}
/**
- * Updates (grants or revokes) a persitable URI permission.
- *
- * @param uri URI to be granted or revoked.
- * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
- * applies to all URIs that are prefixed by this URI.
- * @param packageName target package.
- * @param grant if {@code true} a new permission will be granted, otherwise an existing
- * permission will be revoked.
- *
- * @return whether or not the requested succeeded.
- *
- * @hide
- */
- public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
- boolean grant) {
- try {
- return getService().updatePersistableUriPermission(uri, prefix, packageName, grant,
- UserHandle.myUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Information you can retrieve about any processes that are in an error condition.
*/
public static class ProcessErrorStateInfo implements Parcelable {
@@ -3335,6 +3322,28 @@
}
/**
+ * Query whether the user has enabled background restrictions for this app.
+ *
+ * <p> The user may chose to do this, if they see that an app is consuming an unreasonable
+ * amount of battery while in the background. </p>
+ *
+ * <p> If true, any work that the app tries to do will be aggressively restricted while it is in
+ * the background. At a minimum, jobs and alarms will not execute and foreground services
+ * cannot be started unless an app activity is in the foreground. </p>
+ *
+ * <p><b> Note that these restrictions stay in effect even when the device is charging.</b></p>
+ *
+ * @return true if user has enforced background restrictions for this app, false otherwise.
+ */
+ public boolean isBackgroundRestricted() {
+ try {
+ return getService().isBackgroundRestricted(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Sets the memory trim mode for a process and schedules a memory trim operation.
*
* <p><b>Note: this method is only intended for testing framework.</b></p>
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index feeb0f2..c78255f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -353,6 +353,11 @@
public abstract boolean isCallerRecents(int callingUid);
/**
+ * Returns whether the recents component is the home activity for the given user.
+ */
+ public abstract boolean isRecentsComponentHomeActivity(int userId);
+
+ /**
* Whether an UID is active or idle.
*/
public abstract boolean isUidActive(int uid);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 21d146a..379944e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -143,7 +143,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
-import com.android.server.am.proto.MemInfoProto;
+import com.android.server.am.proto.MemInfoDumpProto;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.CloseGuard;
@@ -1251,55 +1251,62 @@
long parcelCount = Parcel.getGlobalAllocCount();
SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
- final long mToken = proto.start(MemInfoProto.AppData.PROCESS_MEMORY);
- proto.write(MemInfoProto.ProcessMemory.PID, Process.myPid());
- proto.write(MemInfoProto.ProcessMemory.PROCESS_NAME,
+ final long mToken = proto.start(MemInfoDumpProto.AppData.PROCESS_MEMORY);
+ proto.write(MemInfoDumpProto.ProcessMemory.PID, Process.myPid());
+ proto.write(MemInfoDumpProto.ProcessMemory.PROCESS_NAME,
(mBoundApplication != null) ? mBoundApplication.processName : "unknown");
dumpMemInfoTable(proto, memInfo, dumpDalvik, dumpSummaryOnly,
nativeMax, nativeAllocated, nativeFree,
dalvikMax, dalvikAllocated, dalvikFree);
proto.end(mToken);
- final long oToken = proto.start(MemInfoProto.AppData.OBJECTS);
- proto.write(MemInfoProto.AppData.ObjectStats.VIEW_INSTANCE_COUNT, viewInstanceCount);
- proto.write(MemInfoProto.AppData.ObjectStats.VIEW_ROOT_INSTANCE_COUNT,
+ final long oToken = proto.start(MemInfoDumpProto.AppData.OBJECTS);
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.VIEW_INSTANCE_COUNT,
+ viewInstanceCount);
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.VIEW_ROOT_INSTANCE_COUNT,
viewRootInstanceCount);
- proto.write(MemInfoProto.AppData.ObjectStats.APP_CONTEXT_INSTANCE_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.APP_CONTEXT_INSTANCE_COUNT,
appContextInstanceCount);
- proto.write(MemInfoProto.AppData.ObjectStats.ACTIVITY_INSTANCE_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.ACTIVITY_INSTANCE_COUNT,
activityInstanceCount);
- proto.write(MemInfoProto.AppData.ObjectStats.GLOBAL_ASSET_COUNT, globalAssetCount);
- proto.write(MemInfoProto.AppData.ObjectStats.GLOBAL_ASSET_MANAGER_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.GLOBAL_ASSET_COUNT,
+ globalAssetCount);
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.GLOBAL_ASSET_MANAGER_COUNT,
globalAssetManagerCount);
- proto.write(MemInfoProto.AppData.ObjectStats.LOCAL_BINDER_OBJECT_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.LOCAL_BINDER_OBJECT_COUNT,
binderLocalObjectCount);
- proto.write(MemInfoProto.AppData.ObjectStats.PROXY_BINDER_OBJECT_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.PROXY_BINDER_OBJECT_COUNT,
binderProxyObjectCount);
- proto.write(MemInfoProto.AppData.ObjectStats.PARCEL_MEMORY_KB, parcelSize / 1024);
- proto.write(MemInfoProto.AppData.ObjectStats.PARCEL_COUNT, parcelCount);
- proto.write(MemInfoProto.AppData.ObjectStats.BINDER_OBJECT_DEATH_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.PARCEL_MEMORY_KB,
+ parcelSize / 1024);
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.PARCEL_COUNT, parcelCount);
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.BINDER_OBJECT_DEATH_COUNT,
binderDeathObjectCount);
- proto.write(MemInfoProto.AppData.ObjectStats.OPEN_SSL_SOCKET_COUNT, openSslSocketCount);
- proto.write(MemInfoProto.AppData.ObjectStats.WEBVIEW_INSTANCE_COUNT,
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.OPEN_SSL_SOCKET_COUNT,
+ openSslSocketCount);
+ proto.write(MemInfoDumpProto.AppData.ObjectStats.WEBVIEW_INSTANCE_COUNT,
webviewInstanceCount);
proto.end(oToken);
// SQLite mem info
- final long sToken = proto.start(MemInfoProto.AppData.SQL);
- proto.write(MemInfoProto.AppData.SqlStats.MEMORY_USED_KB, stats.memoryUsed / 1024);
- proto.write(MemInfoProto.AppData.SqlStats.PAGECACHE_OVERFLOW_KB,
+ final long sToken = proto.start(MemInfoDumpProto.AppData.SQL);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.MEMORY_USED_KB,
+ stats.memoryUsed / 1024);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.PAGECACHE_OVERFLOW_KB,
stats.pageCacheOverflow / 1024);
- proto.write(MemInfoProto.AppData.SqlStats.MALLOC_SIZE_KB, stats.largestMemAlloc / 1024);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.MALLOC_SIZE_KB,
+ stats.largestMemAlloc / 1024);
int n = stats.dbStats.size();
for (int i = 0; i < n; i++) {
DbStats dbStats = stats.dbStats.get(i);
- final long dToken = proto.start(MemInfoProto.AppData.SqlStats.DATABASES);
- proto.write(MemInfoProto.AppData.SqlStats.Database.NAME, dbStats.dbName);
- proto.write(MemInfoProto.AppData.SqlStats.Database.PAGE_SIZE, dbStats.pageSize);
- proto.write(MemInfoProto.AppData.SqlStats.Database.DB_SIZE, dbStats.dbSize);
- proto.write(MemInfoProto.AppData.SqlStats.Database.LOOKASIDE_B, dbStats.lookaside);
- proto.write(MemInfoProto.AppData.SqlStats.Database.CACHE, dbStats.cache);
+ final long dToken = proto.start(MemInfoDumpProto.AppData.SqlStats.DATABASES);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.Database.NAME, dbStats.dbName);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.Database.PAGE_SIZE, dbStats.pageSize);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.Database.DB_SIZE, dbStats.dbSize);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.Database.LOOKASIDE_B,
+ dbStats.lookaside);
+ proto.write(MemInfoDumpProto.AppData.SqlStats.Database.CACHE, dbStats.cache);
proto.end(dToken);
}
proto.end(sToken);
@@ -1307,7 +1314,7 @@
// Asset details.
String assetAlloc = AssetManager.getAssetAllocations();
if (assetAlloc != null) {
- proto.write(MemInfoProto.AppData.ASSET_ALLOCATIONS, assetAlloc);
+ proto.write(MemInfoDumpProto.AppData.ASSET_ALLOCATIONS, assetAlloc);
}
// Unreachable native memory
@@ -1315,7 +1322,7 @@
int flags = mBoundApplication == null ? 0 : mBoundApplication.appInfo.flags;
boolean showContents = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
|| android.os.Build.IS_DEBUGGABLE;
- proto.write(MemInfoProto.AppData.UNREACHABLE_MEMORY,
+ proto.write(MemInfoDumpProto.AppData.UNREACHABLE_MEMORY,
Debug.getUnreachableMemory(100, showContents));
}
}
@@ -2505,17 +2512,17 @@
boolean hasSwappedOutPss, int dirtySwap, int dirtySwapPss) {
final long token = proto.start(fieldId);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.NAME, name);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.TOTAL_PSS_KB, pss);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.CLEAN_PSS_KB, cleanPss);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.SHARED_DIRTY_KB, sharedDirty);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.PRIVATE_DIRTY_KB, privateDirty);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.SHARED_CLEAN_KB, sharedClean);
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.PRIVATE_CLEAN_KB, privateClean);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.NAME, name);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.TOTAL_PSS_KB, pss);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.CLEAN_PSS_KB, cleanPss);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.SHARED_DIRTY_KB, sharedDirty);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.PRIVATE_DIRTY_KB, privateDirty);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.SHARED_CLEAN_KB, sharedClean);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.PRIVATE_CLEAN_KB, privateClean);
if (hasSwappedOutPss) {
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.DIRTY_SWAP_PSS_KB, dirtySwapPss);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.DIRTY_SWAP_PSS_KB, dirtySwapPss);
} else {
- proto.write(MemInfoProto.ProcessMemory.MemoryInfo.DIRTY_SWAP_KB, dirtySwap);
+ proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.DIRTY_SWAP_KB, dirtySwap);
}
proto.end(token);
@@ -2530,26 +2537,26 @@
long dalvikMax, long dalvikAllocated, long dalvikFree) {
if (!dumpSummaryOnly) {
- final long nhToken = proto.start(MemInfoProto.ProcessMemory.NATIVE_HEAP);
- dumpMemoryInfo(proto, MemInfoProto.ProcessMemory.HeapInfo.MEM_INFO, "Native Heap",
+ final long nhToken = proto.start(MemInfoDumpProto.ProcessMemory.NATIVE_HEAP);
+ dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.HeapInfo.MEM_INFO, "Native Heap",
memInfo.nativePss, memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
memInfo.nativePrivateClean, memInfo.hasSwappedOutPss,
memInfo.nativeSwappedOut, memInfo.nativeSwappedOutPss);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, nativeMax);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, nativeAllocated);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, nativeFree);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, nativeMax);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, nativeAllocated);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, nativeFree);
proto.end(nhToken);
- final long dvToken = proto.start(MemInfoProto.ProcessMemory.DALVIK_HEAP);
- dumpMemoryInfo(proto, MemInfoProto.ProcessMemory.HeapInfo.MEM_INFO, "Dalvik Heap",
+ final long dvToken = proto.start(MemInfoDumpProto.ProcessMemory.DALVIK_HEAP);
+ dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.HeapInfo.MEM_INFO, "Dalvik Heap",
memInfo.dalvikPss, memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss,
memInfo.dalvikSwappedOut, memInfo.dalvikSwappedOutPss);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, dalvikMax);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, dalvikAllocated);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, dalvikFree);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, dalvikMax);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, dalvikAllocated);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, dalvikFree);
proto.end(dvToken);
int otherPss = memInfo.otherPss;
@@ -2573,7 +2580,7 @@
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
|| mySharedClean != 0 || myPrivateClean != 0
|| (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
- dumpMemoryInfo(proto, MemInfoProto.ProcessMemory.OTHER_HEAPS,
+ dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.OTHER_HEAPS,
Debug.MemoryInfo.getOtherLabel(i),
myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
mySharedClean, myPrivateClean,
@@ -2590,21 +2597,23 @@
}
}
- dumpMemoryInfo(proto, MemInfoProto.ProcessMemory.UNKNOWN_HEAP, "Unknown",
+ dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.UNKNOWN_HEAP, "Unknown",
otherPss, otherSwappablePss,
otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
memInfo.hasSwappedOutPss, otherSwappedOut, otherSwappedOutPss);
- final long tToken = proto.start(MemInfoProto.ProcessMemory.TOTAL_HEAP);
- dumpMemoryInfo(proto, MemInfoProto.ProcessMemory.HeapInfo.MEM_INFO, "TOTAL",
+ final long tToken = proto.start(MemInfoDumpProto.ProcessMemory.TOTAL_HEAP);
+ dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.HeapInfo.MEM_INFO, "TOTAL",
memInfo.getTotalPss(), memInfo.getTotalSwappablePss(),
memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
memInfo.hasSwappedOutPss, memInfo.getTotalSwappedOut(),
memInfo.getTotalSwappedOutPss());
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, nativeMax + dalvikMax);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB,
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB,
+ nativeMax + dalvikMax);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB,
nativeAllocated + dalvikAllocated);
- proto.write(MemInfoProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, nativeFree + dalvikFree);
+ proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_FREE_KB,
+ nativeFree + dalvikFree);
proto.end(tToken);
if (dumpDalvik) {
@@ -2622,7 +2631,7 @@
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
|| mySharedClean != 0 || myPrivateClean != 0
|| (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
- dumpMemoryInfo(proto, MemInfoProto.ProcessMemory.DALVIK_DETAILS,
+ dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.DALVIK_DETAILS,
Debug.MemoryInfo.getOtherLabel(i),
myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
mySharedClean, myPrivateClean,
@@ -2632,24 +2641,26 @@
}
}
- final long asToken = proto.start(MemInfoProto.ProcessMemory.APP_SUMMARY);
- proto.write(MemInfoProto.ProcessMemory.AppSummary.JAVA_HEAP_PSS_KB,
+ final long asToken = proto.start(MemInfoDumpProto.ProcessMemory.APP_SUMMARY);
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.JAVA_HEAP_PSS_KB,
memInfo.getSummaryJavaHeap());
- proto.write(MemInfoProto.ProcessMemory.AppSummary.NATIVE_HEAP_PSS_KB,
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.NATIVE_HEAP_PSS_KB,
memInfo.getSummaryNativeHeap());
- proto.write(MemInfoProto.ProcessMemory.AppSummary.CODE_PSS_KB, memInfo.getSummaryCode());
- proto.write(MemInfoProto.ProcessMemory.AppSummary.STACK_PSS_KB, memInfo.getSummaryStack());
- proto.write(MemInfoProto.ProcessMemory.AppSummary.GRAPHICS_PSS_KB,
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.CODE_PSS_KB,
+ memInfo.getSummaryCode());
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.STACK_PSS_KB,
+ memInfo.getSummaryStack());
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.GRAPHICS_PSS_KB,
memInfo.getSummaryGraphics());
- proto.write(MemInfoProto.ProcessMemory.AppSummary.PRIVATE_OTHER_PSS_KB,
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.PRIVATE_OTHER_PSS_KB,
memInfo.getSummaryPrivateOther());
- proto.write(MemInfoProto.ProcessMemory.AppSummary.SYSTEM_PSS_KB,
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.SYSTEM_PSS_KB,
memInfo.getSummarySystem());
if (memInfo.hasSwappedOutPss) {
- proto.write(MemInfoProto.ProcessMemory.AppSummary.TOTAL_SWAP_PSS,
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.TOTAL_SWAP_PSS,
memInfo.getSummaryTotalSwapPss());
} else {
- proto.write(MemInfoProto.ProcessMemory.AppSummary.TOTAL_SWAP_PSS,
+ proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.TOTAL_SWAP_PSS,
memInfo.getSummaryTotalSwap());
}
proto.end(asToken);
@@ -3716,6 +3727,10 @@
if (localLOGV) Slog.v(TAG, "Performing resume of " + r
+ " finished=" + r.activity.mFinished);
if (r != null && !r.activity.mFinished) {
+ if (r.getLifecycleState() == ON_RESUME) {
+ throw new IllegalStateException(
+ "Trying to resume activity which is already resumed");
+ }
if (clearHide) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
@@ -3900,8 +3915,7 @@
@Override
public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
- int configChanges, boolean dontReport, PendingTransactionActions pendingActions,
- String reason) {
+ int configChanges, PendingTransactionActions pendingActions, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
if (userLeaving) {
@@ -3915,15 +3929,6 @@
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
-
- // Tell the activity manager we have paused.
- if (!dontReport) {
- try {
- ActivityManager.getService().activityPaused(token);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
mSomeActivitiesChanged = true;
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index c5b3a4a..05a9861 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -31,7 +31,6 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -168,12 +167,14 @@
/** @hide */
public static final int OP_WRITE_SETTINGS = 23;
/** @hide Required to draw on top of other apps. */
+ @TestApi
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
/** @hide */
public static final int OP_ACCESS_NOTIFICATIONS = 25;
/** @hide */
public static final int OP_CAMERA = 26;
/** @hide */
+ @TestApi
public static final int OP_RECORD_AUDIO = 27;
/** @hide */
public static final int OP_PLAY_AUDIO = 28;
@@ -1540,6 +1541,7 @@
*
* @hide
*/
+ @TestApi
public interface OnOpActiveChangedListener {
/**
* Called when the active state of an app op changes.
@@ -1731,15 +1733,14 @@
* Monitor for changes to the operating mode for the given op in the given app package.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
- * to watch changes only for your UID.
+ * you can watch changes only for your UID.
*
* @param op The operation to monitor, one of OP_*.
* @param packageName The name of the application to monitor.
* @param callback Where to report changes.
* @hide
*/
- // TODO: Uncomment below annotation once b/73559440 is fixed
- // @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
+ @RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.get(callback);
@@ -1788,6 +1789,9 @@
* watched ops for a registered callback you need to unregister and register it
* again.
*
+ * <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
+ * you can watch changes only for your UID.
+ *
* @param ops The ops to watch.
* @param callback Where to report changes.
*
@@ -1798,7 +1802,9 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.WATCH_APPOPS)
+ @TestApi
+ // TODO: Uncomment below annotation once b/73559440 is fixed
+ // @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingActive(@NonNull int[] ops,
@NonNull OnOpActiveChangedListener callback) {
Preconditions.checkNotNull(ops, "ops cannot be null");
@@ -1836,6 +1842,7 @@
*
* @hide
*/
+ @TestApi
public void stopWatchingActive(@NonNull OnOpActiveChangedListener callback) {
synchronized (mActiveWatchers) {
final IAppOpsActiveCallback cb = mActiveWatchers.get(callback);
@@ -2087,15 +2094,11 @@
* @hide
*/
public int noteOp(int op, int uid, String packageName) {
- try {
- int mode = mService.noteOperation(op, uid, packageName);
- if (mode == MODE_ERRORED) {
- throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
- }
- return mode;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ final int mode = noteOpNoThrow(op, uid, packageName);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
+ return mode;
}
/**
@@ -2174,6 +2177,11 @@
}
}
+ /** @hide */
+ public int startOp(int op) {
+ return startOp(op, Process.myUid(), mContext.getOpPackageName());
+ }
+
/**
* 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
@@ -2182,6 +2190,7 @@
* the current time and the operation will be marked as "running". In this case you must
* later call {@link #finishOp(int, int, String)} to report when the application is no
* longer performing the operation.
+ *
* @param op The operation to start. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
@@ -2192,15 +2201,34 @@
* @hide
*/
public int startOp(int op, int uid, String packageName) {
- try {
- int mode = mService.startOperation(getToken(mService), op, uid, packageName);
- if (mode == MODE_ERRORED) {
- throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
- }
- return mode;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ return startOp(op, uid, packageName, false);
+ }
+
+ /**
+ * Report that an application has started executing a long-running operation. Similar
+ * to {@link #startOp(String, int, String) except that if the mode is {@link #MODE_DEFAULT}
+ * the operation should succeed since the caller has performed its standard permission
+ * checks which passed and would perform the protected operation for this mode.
+ *
+ * @param op The operation to start. One of the OP_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
+ *
+ * @throws SecurityException If the app has been configured to crash on this op or
+ * the package is not in the passed in UID.
+ *
+ * @hide
+ */
+ public int startOp(int op, int uid, String packageName, boolean startIfModeDefault) {
+ final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
+ return mode;
}
/**
@@ -2209,18 +2237,32 @@
* @hide
*/
public int startOpNoThrow(int op, int uid, String packageName) {
+ return startOpNoThrow(op, uid, packageName, false);
+ }
+
+ /**
+ * Like {@link #startOp(int, int, String, boolean)} but instead of throwing a
+ * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ *
+ * @param op The operation to start. One of the OP_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
+ *
+ * @hide
+ */
+ public int startOpNoThrow(int op, int uid, String packageName, boolean startIfModeDefault) {
try {
- return mService.startOperation(getToken(mService), op, uid, packageName);
+ return mService.startOperation(getToken(mService), op, uid, packageName,
+ startIfModeDefault);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- /** @hide */
- public int startOp(int op) {
- return startOp(op, Process.myUid(), mContext.getOpPackageName());
- }
-
/**
* Report that an application is no longer performing an operation that had previously
* been started with {@link #startOp(int, int, String)}. There is no validation of input
@@ -2241,8 +2283,21 @@
finishOp(op, Process.myUid(), mContext.getOpPackageName());
}
- /** @hide */
- @RequiresPermission(Manifest.permission.WATCH_APPOPS)
+ /**
+ * Checks whether the given op for a UID and package is active.
+ *
+ * <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
+ * you can query only for your UID.
+ *
+ * @see #startWatchingActive(int[], OnOpActiveChangedListener)
+ * @see #stopWatchingMode(OnOpChangedListener)
+ * @see #finishOp(int)
+ * @see #startOp(int)
+ *
+ * @hide */
+ @TestApi
+ // TODO: Uncomment below annotation once b/73559440 is fixed
+ // @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public boolean isOperationActive(int code, int uid, String packageName) {
try {
return mService.isOperationActive(code, uid, packageName);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f8f50a2..21fb18a 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1354,11 +1354,10 @@
if (badgeColor == null) {
return null;
}
- badgeColor.setTint(getUserBadgeColor(user));
Drawable badgeForeground = getDrawableForDensity(
com.android.internal.R.drawable.ic_corp_badge_case, density);
- Drawable badge = new LayerDrawable(
- new Drawable[] {badgeColor, badgeForeground });
+ badgeForeground.setTint(getUserBadgeColor(user));
+ Drawable badge = new LayerDrawable(new Drawable[] {badgeColor, badgeForeground });
return badge;
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index cb52a85..6bc66ec 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -65,8 +65,7 @@
/** Pause the activity. */
public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
- int configChanges, boolean dontReport, PendingTransactionActions pendingActions,
- String reason);
+ int configChanges, PendingTransactionActions pendingActions, String reason);
/** Resume the activity. */
public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index ac301b3..0d45dfa 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -423,10 +423,8 @@
void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
void restart();
void performIdleMaintenance();
- void takePersistableUriPermission(in Uri uri, int modeFlags, int userId);
- boolean updatePersistableUriPermission(in Uri uri, boolean prefix, String packageName,
- boolean grant, int userId);
- void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId);
+ void takePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
+ void releasePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
void appNotRespondingViaProvider(in IBinder connection);
Rect getTaskBounds(int taskId);
@@ -614,7 +612,7 @@
int sendIntentSender(in IIntentSender target, in IBinder whitelistToken, int code,
in Intent intent, in String resolvedType, in IIntentReceiver finishedReceiver,
in String requiredPermission, in Bundle options);
-
+ boolean isBackgroundRestricted(in String packageName);
// Start of N MR1 transactions
void setVrThread(int tid);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 233e09d..13a6be5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -360,6 +360,23 @@
@Deprecated
public RemoteViews headsUpContentView;
+ private boolean mUsesStandardHeader;
+
+ private static final ArraySet<Integer> STANDARD_LAYOUTS = new ArraySet<>();
+ static {
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_base);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_base);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_picture);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_text);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_inbox);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_messaging);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_media);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_media);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_ambient_header);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_header);
+ STANDARD_LAYOUTS.add(R.layout.notification_template_material_ambient);
+ }
+
/**
* A large bitmap to be shown in the notification content area.
*
@@ -2534,6 +2551,8 @@
}
parcel.writeInt(mGroupAlertBehavior);
+
+ // mUsesStandardHeader is not written because it should be recomputed in listeners
}
/**
@@ -4092,6 +4111,25 @@
}
}
+ /**
+ * @hide
+ */
+ public boolean usesStandardHeader() {
+ if (mN.mUsesStandardHeader) {
+ return true;
+ }
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.N) {
+ if (mN.contentView == null && mN.bigContentView == null) {
+ return true;
+ }
+ }
+ boolean contentViewUsesHeader = mN.contentView == null
+ || STANDARD_LAYOUTS.contains(mN.contentView.getLayoutId());
+ boolean bigContentViewUsesHeader = mN.bigContentView == null
+ || STANDARD_LAYOUTS.contains(mN.bigContentView.getLayoutId());
+ return contentViewUsesHeader && bigContentViewUsesHeader;
+ }
+
private void resetStandardTemplate(RemoteViews contentView) {
resetNotificationHeader(contentView);
resetContentMargins(contentView);
@@ -4123,6 +4161,7 @@
contentView.setViewVisibility(R.id.time, View.GONE);
contentView.setImageViewIcon(R.id.profile_badge, null);
contentView.setViewVisibility(R.id.profile_badge, View.GONE);
+ mN.mUsesStandardHeader = false;
}
private void resetContentMargins(RemoteViews contentView) {
@@ -4444,6 +4483,7 @@
bindProfileBadge(contentView);
}
bindExpandButton(contentView);
+ mN.mUsesStandardHeader = true;
}
private void bindExpandButton(RemoteViews contentView) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 4e2cb64..49faf40 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -33,7 +33,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -752,6 +751,8 @@
*
* <p>This function can be safely called at any time (even if no search is active.)
*
+ * <p>{@link Configuration#UI_MODE_TYPE_TELEVISION} does not support this method.
+ *
* @see #startSearch
*/
public void stopSearch() {
@@ -802,6 +803,8 @@
/**
* Set or clear the callback that will be invoked whenever the search UI is dismissed.
*
+ * <p>{@link Configuration#UI_MODE_TYPE_TELEVISION} does not support this method.
+ *
* @param listener The {@link OnDismissListener} to use, or null.
*/
public void setOnDismissListener(final OnDismissListener listener) {
@@ -811,6 +814,8 @@
/**
* Set or clear the callback that will be invoked whenever the search UI is canceled.
*
+ * <p>{@link Configuration#UI_MODE_TYPE_TELEVISION} does not support this method.
+ *
* @param listener The {@link OnCancelListener} to use, or null.
*/
public void setOnCancelListener(OnCancelListener listener) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 16e36bc..2c4bf82 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -56,8 +56,11 @@
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManager.UserOperationException;
+import android.os.UserManager.UserOperationResult;
import android.provider.ContactsContract.Directory;
import android.provider.Settings;
import android.security.AttestedKeyPair;
@@ -5627,6 +5630,29 @@
}
/**
+ * Called by a device owner to set the default SMS application.
+ * <p>
+ * The calling device admin must be a device owner. If it is not, a security exception will be
+ * thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The name of the package to set as the default SMS application.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ *
+ * @hide
+ */
+ public void setDefaultSmsApplication(@NonNull ComponentName admin, String packageName) {
+ throwIfParentInstance("setDefaultSmsApplication");
+ if (mService != null) {
+ try {
+ mService.setDefaultSmsApplication(admin, packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Called by a profile owner or device owner to grant permission to a package to manage
* application restrictions for the calling user via {@link #setApplicationRestrictions} and
* {@link #getApplicationRestrictions}.
@@ -6549,6 +6575,9 @@
* <p>
* If the adminExtras are not null, they will be stored on the device until the user is started
* for the first time. Then the extras will be passed to the admin when onEnable is called.
+ * <p>From {@link android.os.Build.VERSION_CODES#P} onwards, if targeting
+ * {@link android.os.Build.VERSION_CODES#P}, throws {@link UserOperationException} instead of
+ * returning {@code null} on failure.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param name The user's name.
@@ -6563,6 +6592,9 @@
* @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
* user could not be created.
* @throws SecurityException if {@code admin} is not a device owner.
+ * @throws UserOperationException if the user could not be created and the calling app is
+ * targeting {@link android.os.Build.VERSION_CODES#P} and running on
+ * {@link android.os.Build.VERSION_CODES#P}.
*/
public @Nullable UserHandle createAndManageUser(@NonNull ComponentName admin,
@NonNull String name,
@@ -6571,6 +6603,8 @@
throwIfParentInstance("createAndManageUser");
try {
return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
+ } catch (ServiceSpecificException e) {
+ throw new UserOperationException(e.getMessage(), e.errorCode);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -6614,77 +6648,15 @@
}
/**
- * Indicates user operation is successful.
- *
- * @see #startUserInBackground(ComponentName, UserHandle)
- * @see #stopUser(ComponentName, UserHandle)
- * @see #logoutUser(ComponentName)
- */
- public static final int USER_OPERATION_SUCCESS = 0;
-
- /**
- * Indicates user operation failed for unknown reason.
- *
- * @see #startUserInBackground(ComponentName, UserHandle)
- * @see #stopUser(ComponentName, UserHandle)
- * @see #logoutUser(ComponentName)
- */
- public static final int USER_OPERATION_ERROR_UNKNOWN = 1;
-
- /**
- * Indicates user operation failed because target user is a managed profile.
- *
- * @see #startUserInBackground(ComponentName, UserHandle)
- * @see #stopUser(ComponentName, UserHandle)
- * @see #logoutUser(ComponentName)
- */
- public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2;
-
- /**
- * Indicates user operation failed because maximum running user limit has reached.
- *
- * @see #startUserInBackground(ComponentName, UserHandle)
- */
- public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3;
-
- /**
- * Indicates user operation failed because the target user is in foreground.
- *
- * @see #stopUser(ComponentName, UserHandle)
- * @see #logoutUser(ComponentName)
- */
- public static final int USER_OPERATION_ERROR_CURRENT_USER = 4;
-
- /**
- * Result returned from
- * <ul>
- * <li>{@link #startUserInBackground(ComponentName, UserHandle)}</li>
- * <li>{@link #stopUser(ComponentName, UserHandle)}</li>
- * <li>{@link #logoutUser(ComponentName)}</li>
- * </ul>
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "USER_OPERATION_" }, value = {
- USER_OPERATION_SUCCESS,
- USER_OPERATION_ERROR_UNKNOWN,
- USER_OPERATION_ERROR_MANAGED_PROFILE,
- USER_OPERATION_ERROR_MAX_RUNNING_USERS,
- USER_OPERATION_ERROR_CURRENT_USER
- })
- public @interface UserOperationResult {}
-
- /**
* Called by a device owner to start the specified secondary user in background.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle the user to be started in background.
* @return one of the following result codes:
- * {@link #USER_OPERATION_ERROR_UNKNOWN},
- * {@link #USER_OPERATION_SUCCESS},
- * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE},
- * {@link #USER_OPERATION_ERROR_MAX_RUNNING_USERS},
+ * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN},
+ * {@link UserManager#USER_OPERATION_SUCCESS},
+ * {@link UserManager#USER_OPERATION_ERROR_MANAGED_PROFILE},
+ * {@link UserManager#USER_OPERATION_ERROR_MAX_RUNNING_USERS},
* @throws SecurityException if {@code admin} is not a device owner.
* @see #getSecondaryUsers(ComponentName)
*/
@@ -6704,10 +6676,10 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle the user to be stopped.
* @return one of the following result codes:
- * {@link #USER_OPERATION_ERROR_UNKNOWN},
- * {@link #USER_OPERATION_SUCCESS},
- * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE},
- * {@link #USER_OPERATION_ERROR_CURRENT_USER}
+ * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN},
+ * {@link UserManager#USER_OPERATION_SUCCESS},
+ * {@link UserManager#USER_OPERATION_ERROR_MANAGED_PROFILE},
+ * {@link UserManager#USER_OPERATION_ERROR_CURRENT_USER}
* @throws SecurityException if {@code admin} is not a device owner.
* @see #getSecondaryUsers(ComponentName)
*/
@@ -6727,10 +6699,10 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return one of the following result codes:
- * {@link #USER_OPERATION_ERROR_UNKNOWN},
- * {@link #USER_OPERATION_SUCCESS},
- * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE},
- * {@link #USER_OPERATION_ERROR_CURRENT_USER}
+ * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN},
+ * {@link UserManager#USER_OPERATION_SUCCESS},
+ * {@link UserManager#USER_OPERATION_ERROR_MANAGED_PROFILE},
+ * {@link UserManager#USER_OPERATION_ERROR_CURRENT_USER}
* @throws SecurityException if {@code admin} is not a profile owner affiliated with the device.
* @see #getSecondaryUsers(ComponentName)
*/
@@ -9420,6 +9392,11 @@
/**
* Called by device owner to add an override APN.
*
+ * <p>This method may returns {@code -1} if {@code apnSetting} conflicts with an existing
+ * override APN. Update the existing conflicted APN with
+ * {@link #updateOverrideApn(ComponentName, int, ApnSetting)} instead of adding a new entry.
+ * <p>See {@link ApnSetting} for the definition of conflict.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnSetting the override APN to insert
* @return The {@code id} of inserted override APN. Or {@code -1} when failed to insert into
@@ -9443,6 +9420,12 @@
/**
* Called by device owner to update an override APN.
*
+ * <p>This method may returns {@code false} if there is no override APN with the given
+ * {@code apnId}.
+ * <p>This method may also returns {@code false} if {@code apnSetting} conflicts with an
+ * existing override APN. Update the existing conflicted APN instead.
+ * <p>See {@link ApnSetting} for the definition of conflict.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnId the {@code id} of the override APN to update
* @param apnSetting the override APN to update
@@ -9468,6 +9451,9 @@
/**
* Called by device owner to remove an override APN.
*
+ * <p>This method may returns {@code false} if there is no override APN with the given
+ * {@code apnId}.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnId the {@code id} of the override APN to remove
* @return {@code true} if the required override APN is successfully removed, {@code false}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5218a73..c29369f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -192,6 +192,8 @@
void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
+ void setDefaultSmsApplication(in ComponentName admin, String packageName);
+
void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings);
Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName);
boolean setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName);
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 1312a2e..ef41b10 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1309,6 +1309,11 @@
if (domain == null) return;
final Uri uri = Uri.parse(domain);
+ if (uri == null) {
+ // Cannot log domain because it could contain PII;
+ Log.w(TAG, "Failed to parse web domain");
+ return;
+ }
mWebScheme = uri.getScheme();
mWebDomain = uri.getHost();
}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index f456395..0963594 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -83,6 +83,13 @@
*/
public static final int FLAG_NON_INCREMENTAL = 1 << 2;
+ /**
+ * Used as a boolean extra in the binding intent of transports. We pass {@code true} to
+ * notify transports that the current connection is used for registering the transport.
+ */
+ public static final String EXTRA_TRANSPORT_REGISTRATION =
+ "android.app.backup.extra.TRANSPORT_REGISTRATION";
+
IBackupTransport mBinderImpl = new TransportImpl();
public IBinder getBinder() {
diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java
index 73b5ec4..545463c 100644
--- a/core/java/android/app/servertransaction/ActivityResultItem.java
+++ b/core/java/android/app/servertransaction/ActivityResultItem.java
@@ -16,7 +16,7 @@
package android.app.servertransaction;
-import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import android.app.ClientTransactionHandler;
@@ -38,8 +38,8 @@
private List<ResultInfo> mResultInfoList;
@Override
- public int getPreExecutionState() {
- return ON_PAUSE;
+ public int getPostExecutionState() {
+ return ON_RESUME;
}
@Override
diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java
index 6f2cc00..d94f08b 100644
--- a/core/java/android/app/servertransaction/ClientTransactionItem.java
+++ b/core/java/android/app/servertransaction/ClientTransactionItem.java
@@ -32,12 +32,6 @@
*/
public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable {
- /** Get the state in which this callback can be executed. */
- @LifecycleState
- public int getPreExecutionState() {
- return UNDEFINED;
- }
-
/** Get the state that must follow this callback. */
@LifecycleState
public int getPostExecutionState() {
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
index 7dfde73..e5ce3b0 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -38,11 +38,6 @@
// TODO(lifecycler): Switch new intent handling to this scheme.
/*@Override
- public int getPreExecutionState() {
- return ON_PAUSE;
- }
-
- @Override
public int getPostExecutionState() {
return ON_RESUME;
}*/
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index 578f0e3..65e4291 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -42,8 +42,8 @@
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
- client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, mDontReport,
- pendingActions, "PAUSE_ACTIVITY_ITEM");
+ client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
+ "PAUSE_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index b66d61b..0e52b34 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -24,6 +24,7 @@
import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+import static android.app.servertransaction.TransactionExecutorHelper.lastCallbackRequestingState;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
@@ -48,11 +49,7 @@
private ClientTransactionHandler mTransactionHandler;
private PendingTransactionActions mPendingActions = new PendingTransactionActions();
-
- // Temp holder for lifecycle path.
- // No direct transition between two states should take more than one complete cycle of 6 states.
- @ActivityLifecycleItem.LifecycleState
- private IntArray mLifecycleSequence = new IntArray(6);
+ private TransactionExecutorHelper mHelper = new TransactionExecutorHelper();
/** Initialize an instance with transaction handler, that will execute all requested actions. */
public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) {
@@ -89,13 +86,25 @@
final IBinder token = transaction.getActivityToken();
ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
+
+ // In case when post-execution state of the last callback matches the final state requested
+ // for the activity in this transaction, we won't do the last transition here and do it when
+ // moving to final state instead (because it may contain additional parameters from server).
+ final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
+ final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState()
+ : UNDEFINED;
+ // Index of the last callback that requests some post-execution state.
+ final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
+
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
log("Resolving callback: " + item);
- final int preExecutionState = item.getPreExecutionState();
- if (preExecutionState != UNDEFINED) {
- cycleToPath(r, preExecutionState);
+ final int postExecutionState = item.getPostExecutionState();
+ final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
+ item.getPostExecutionState());
+ if (closestPreExecutionState != UNDEFINED) {
+ cycleToPath(r, closestPreExecutionState);
}
item.execute(mTransactionHandler, token, mPendingActions);
@@ -105,9 +114,11 @@
r = mTransactionHandler.getActivityClient(token);
}
- final int postExecutionState = item.getPostExecutionState();
- if (postExecutionState != UNDEFINED) {
- cycleToPath(r, postExecutionState);
+ if (postExecutionState != UNDEFINED && r != null) {
+ // Skip the very last transition and perform it by explicit state request instead.
+ final boolean shouldExcludeLastTransition =
+ i == lastCallbackRequestingState && finalState == postExecutionState;
+ cycleToPath(r, postExecutionState, shouldExcludeLastTransition);
}
}
}
@@ -162,15 +173,15 @@
boolean excludeLastState) {
final int start = r.getLifecycleState();
log("Cycle from: " + start + " to: " + finish + " excludeLastState:" + excludeLastState);
- initLifecyclePath(start, finish, excludeLastState);
- performLifecycleSequence(r);
+ final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
+ performLifecycleSequence(r, path);
}
/** Transition the client through previously initialized state sequence. */
- private void performLifecycleSequence(ActivityClientRecord r) {
- final int size = mLifecycleSequence.size();
+ private void performLifecycleSequence(ActivityClientRecord r, IntArray path) {
+ final int size = path.size();
for (int i = 0, state; i < size; i++) {
- state = mLifecycleSequence.get(i);
+ state = path.get(i);
log("Transitioning to state: " + state);
switch (state) {
case ON_CREATE:
@@ -185,8 +196,8 @@
break;
case ON_PAUSE:
mTransactionHandler.handlePauseActivity(r.token, false /* finished */,
- false /* userLeaving */, 0 /* configChanges */,
- true /* dontReport */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY");
+ false /* userLeaving */, 0 /* configChanges */, mPendingActions,
+ "LIFECYCLER_PAUSE_ACTIVITY");
break;
case ON_STOP:
mTransactionHandler.handleStopActivity(r.token, false /* show */,
@@ -195,8 +206,7 @@
case ON_DESTROY:
mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
0 /* configChanges */, false /* getNonConfigInstance */,
- "performLifecycleSequence. cycling to:"
- + mLifecycleSequence.get(size - 1));
+ "performLifecycleSequence. cycling to:" + path.get(size - 1));
break;
case ON_RESTART:
mTransactionHandler.performRestartActivity(r.token, false /* start */);
@@ -207,60 +217,6 @@
}
}
- /**
- * Calculate the path through main lifecycle states for an activity and fill
- * @link #mLifecycleSequence} with values starting with the state that follows the initial
- * state.
- */
- public void initLifecyclePath(int start, int finish, boolean excludeLastState) {
- mLifecycleSequence.clear();
- if (finish >= start) {
- // just go there
- for (int i = start + 1; i <= finish; i++) {
- mLifecycleSequence.add(i);
- }
- } else { // finish < start, can't just cycle down
- if (start == ON_PAUSE && finish == ON_RESUME) {
- // Special case when we can just directly go to resumed state.
- mLifecycleSequence.add(ON_RESUME);
- } else if (start <= ON_STOP && finish >= ON_START) {
- // Restart and go to required state.
-
- // Go to stopped state first.
- for (int i = start + 1; i <= ON_STOP; i++) {
- mLifecycleSequence.add(i);
- }
- // Restart
- mLifecycleSequence.add(ON_RESTART);
- // Go to required state
- for (int i = ON_START; i <= finish; i++) {
- mLifecycleSequence.add(i);
- }
- } else {
- // Relaunch and go to required state
-
- // Go to destroyed state first.
- for (int i = start + 1; i <= ON_DESTROY; i++) {
- mLifecycleSequence.add(i);
- }
- // Go to required state
- for (int i = ON_CREATE; i <= finish; i++) {
- mLifecycleSequence.add(i);
- }
- }
- }
-
- // Remove last transition in case we want to perform it with some specific params.
- if (excludeLastState && mLifecycleSequence.size() != 0) {
- mLifecycleSequence.remove(mLifecycleSequence.size() - 1);
- }
- }
-
- @VisibleForTesting
- public int[] getLifecycleSequence() {
- return mLifecycleSequence.toArray();
- }
-
private static void log(String message) {
if (DEBUG_RESOLVER) Slog.d(TAG, message);
}
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
new file mode 100644
index 0000000..7e66fd7
--- /dev/null
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2018 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.app.servertransaction;
+
+import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESTART;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+
+import android.app.ActivityThread;
+import android.util.IntArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/**
+ * Helper class for {@link TransactionExecutor} that contains utils for lifecycle path resolution.
+ * @hide
+ */
+public class TransactionExecutorHelper {
+ // A penalty applied to path with destruction when looking for the shortest one.
+ private static final int DESTRUCTION_PENALTY = 10;
+
+ private static final int[] ON_RESUME_PRE_EXCUTION_STATES = new int[] { ON_START, ON_PAUSE };
+
+ // Temp holder for lifecycle path.
+ // No direct transition between two states should take more than one complete cycle of 6 states.
+ @ActivityLifecycleItem.LifecycleState
+ private IntArray mLifecycleSequence = new IntArray(6);
+
+ /**
+ * Calculate the path through main lifecycle states for an activity and fill
+ * @link #mLifecycleSequence} with values starting with the state that follows the initial
+ * state.
+ * <p>NOTE: The returned value is used internally in this class and is not a copy. It's contents
+ * may change after calling other methods of this class.</p>
+ */
+ @VisibleForTesting
+ public IntArray getLifecyclePath(int start, int finish, boolean excludeLastState) {
+ if (start == UNDEFINED || finish == UNDEFINED) {
+ throw new IllegalArgumentException("Can't resolve lifecycle path for undefined state");
+ }
+ if (start == ON_RESTART || finish == ON_RESTART) {
+ throw new IllegalArgumentException(
+ "Can't start or finish in intermittent RESTART state");
+ }
+ if (finish == PRE_ON_CREATE && start != finish) {
+ throw new IllegalArgumentException("Can only start in pre-onCreate state");
+ }
+
+ mLifecycleSequence.clear();
+ if (finish >= start) {
+ // just go there
+ for (int i = start + 1; i <= finish; i++) {
+ mLifecycleSequence.add(i);
+ }
+ } else { // finish < start, can't just cycle down
+ if (start == ON_PAUSE && finish == ON_RESUME) {
+ // Special case when we can just directly go to resumed state.
+ mLifecycleSequence.add(ON_RESUME);
+ } else if (start <= ON_STOP && finish >= ON_START) {
+ // Restart and go to required state.
+
+ // Go to stopped state first.
+ for (int i = start + 1; i <= ON_STOP; i++) {
+ mLifecycleSequence.add(i);
+ }
+ // Restart
+ mLifecycleSequence.add(ON_RESTART);
+ // Go to required state
+ for (int i = ON_START; i <= finish; i++) {
+ mLifecycleSequence.add(i);
+ }
+ } else {
+ // Relaunch and go to required state
+
+ // Go to destroyed state first.
+ for (int i = start + 1; i <= ON_DESTROY; i++) {
+ mLifecycleSequence.add(i);
+ }
+ // Go to required state
+ for (int i = ON_CREATE; i <= finish; i++) {
+ mLifecycleSequence.add(i);
+ }
+ }
+ }
+
+ // Remove last transition in case we want to perform it with some specific params.
+ if (excludeLastState && mLifecycleSequence.size() != 0) {
+ mLifecycleSequence.remove(mLifecycleSequence.size() - 1);
+ }
+
+ return mLifecycleSequence;
+ }
+
+ /**
+ * Pick a state that goes before provided post-execution state and would require the least
+ * lifecycle transitions to get to.
+ * It will also make sure to try avoiding a path with activity destruction and relaunch if
+ * possible.
+ * @param r An activity that we're trying to resolve the transition for.
+ * @param postExecutionState Post execution state to compute for.
+ * @return One of states that precede the provided post-execution state, or
+ * {@link ActivityLifecycleItem#UNDEFINED} if there is not path.
+ */
+ @VisibleForTesting
+ public int getClosestPreExecutionState(ActivityThread.ActivityClientRecord r,
+ int postExecutionState) {
+ switch (postExecutionState) {
+ case UNDEFINED:
+ return UNDEFINED;
+ case ON_RESUME:
+ return getClosestOfStates(r, ON_RESUME_PRE_EXCUTION_STATES);
+ default:
+ throw new UnsupportedOperationException("Pre-execution states for state: "
+ + postExecutionState + " is not supported.");
+ }
+ }
+
+ /**
+ * Pick a state that would require the least lifecycle transitions to get to.
+ * It will also make sure to try avoiding a path with activity destruction and relaunch if
+ * possible.
+ * @param r An activity that we're trying to resolve the transition for.
+ * @param finalStates An array of valid final states.
+ * @return One of the provided final states, or {@link ActivityLifecycleItem#UNDEFINED} if none
+ * were provided or there is not path.
+ */
+ @VisibleForTesting
+ public int getClosestOfStates(ActivityThread.ActivityClientRecord r, int[] finalStates) {
+ if (finalStates == null || finalStates.length == 0) {
+ return UNDEFINED;
+ }
+
+ final int currentState = r.getLifecycleState();
+ int closestState = UNDEFINED;
+ for (int i = 0, shortestPath = Integer.MAX_VALUE, pathLength; i < finalStates.length; i++) {
+ getLifecyclePath(currentState, finalStates[i], false /* excludeLastState */);
+ pathLength = mLifecycleSequence.size();
+ if (pathInvolvesDestruction(mLifecycleSequence)) {
+ pathLength += DESTRUCTION_PENALTY;
+ }
+ if (shortestPath > pathLength) {
+ shortestPath = pathLength;
+ closestState = finalStates[i];
+ }
+ }
+ return closestState;
+ }
+
+ /**
+ * Check if there is a destruction involved in the path. We want to avoid a lifecycle sequence
+ * that involves destruction and recreation if there is another path.
+ */
+ private static boolean pathInvolvesDestruction(IntArray lifecycleSequence) {
+ final int size = lifecycleSequence.size();
+ for (int i = 0; i < size; i++) {
+ if (lifecycleSequence.get(i) == ON_DESTROY) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the index of the last callback that requests the state in which activity will be after
+ * execution. If there is a group of callbacks in the end that requests the same specific state
+ * or doesn't request any - we will find the first one from such group.
+ *
+ * E.g. ActivityResult requests RESUMED post-execution state, Configuration does not request any
+ * specific state. If there is a sequence
+ * Configuration - ActivityResult - Configuration - ActivityResult
+ * index 1 will be returned, because ActivityResult request on position 1 will be the last
+ * request that moves activity to the RESUMED state where it will eventually end.
+ */
+ static int lastCallbackRequestingState(ClientTransaction transaction) {
+ final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
+ if (callbacks == null || callbacks.size() == 0) {
+ return -1;
+ }
+
+ // Go from the back of the list to front, look for the request closes to the beginning that
+ // requests the state in which activity will end after all callbacks are executed.
+ int lastRequestedState = UNDEFINED;
+ int lastRequestingCallback = -1;
+ for (int i = callbacks.size() - 1; i >= 0; i--) {
+ final ClientTransactionItem callback = callbacks.get(i);
+ final int postExecutionState = callback.getPostExecutionState();
+ if (postExecutionState != UNDEFINED) {
+ // Found a callback that requests some post-execution state.
+ if (lastRequestedState == UNDEFINED || lastRequestedState == postExecutionState) {
+ // It's either a first-from-end callback that requests state or it requests
+ // the same state as the last one. In both cases, we will use it as the new
+ // candidate.
+ lastRequestedState = postExecutionState;
+ lastRequestingCallback = i;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return lastRequestingCallback;
+ }
+}
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index 0a5795e..b5c69d8 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -436,7 +436,7 @@
}
/**
- * Add a color to the slice being constructed
+ * Add an integer to the slice being constructed
* @param subType Optional template-specific type information
* @see {@link SliceItem#getSubType()}
*/
@@ -446,7 +446,7 @@
}
/**
- * Add a color to the slice being constructed
+ * Add an integer to the slice being constructed
* @param subType Optional template-specific type information
* @see {@link SliceItem#getSubType()}
*/
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index a2e714e..94fd138 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,7 +25,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.media.AudioManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelUuid;
@@ -599,34 +598,6 @@
}
/**
- * Tells remote device to adjust volume. Only if absolute volume is
- * supported. Uses the following values:
- * <ul>
- * <li>{@link AudioManager#ADJUST_LOWER}</li>
- * <li>{@link AudioManager#ADJUST_RAISE}</li>
- * <li>{@link AudioManager#ADJUST_MUTE}</li>
- * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
- * </ul>
- *
- * @param direction One of the supported adjust values.
- * @hide
- */
- public void adjustAvrcpAbsoluteVolume(int direction) {
- if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
- try {
- mServiceLock.readLock().lock();
- if (mService != null && isEnabled()) {
- mService.adjustAvrcpAbsoluteVolume(direction);
- }
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- }
-
- /**
* Tells remote device to set an absolute volume. Only if absolute volume is supported
*
* @param volume Absolute volume to be set on AVRCP side
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 0a0d214..605dbd2 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -79,9 +79,8 @@
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
- /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */
public static final ParcelUuid HearingAid =
- ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05");
+ ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 718e465..73b6eb2 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -16,13 +16,16 @@
package android.content;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemService;
import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import com.android.internal.util.Preconditions;
+
import java.util.ArrayList;
/**
@@ -45,6 +48,7 @@
@SystemService(Context.CLIPBOARD_SERVICE)
public class ClipboardManager extends android.text.ClipboardManager {
private final Context mContext;
+ private final Handler mHandler;
private final IClipboard mService;
private final ArrayList<OnPrimaryClipChangedListener> mPrimaryClipChangedListeners
@@ -52,20 +56,11 @@
private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener
= new IOnPrimaryClipChangedListener.Stub() {
- public void dispatchPrimaryClipChanged() {
- mHandler.sendEmptyMessage(MSG_REPORT_PRIMARY_CLIP_CHANGED);
- }
- };
-
- static final int MSG_REPORT_PRIMARY_CLIP_CHANGED = 1;
-
- private final Handler mHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_REPORT_PRIMARY_CLIP_CHANGED:
- reportPrimaryClipChanged();
- }
+ public void dispatchPrimaryClipChanged() {
+ mHandler.post(() -> {
+ reportPrimaryClipChanged();
+ });
}
};
@@ -89,6 +84,7 @@
/** {@hide} */
public ClipboardManager(Context context, Handler handler) throws ServiceNotFoundException {
mContext = context;
+ mHandler = handler;
mService = IClipboard.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.CLIPBOARD_SERVICE));
}
@@ -98,12 +94,13 @@
* is involved in normal cut and paste operations.
*
* @param clip The clipped data item to set.
+ * @see #getPrimaryClip()
+ * @see #clearPrimaryClip()
*/
- public void setPrimaryClip(ClipData clip) {
+ public void setPrimaryClip(@NonNull ClipData clip) {
try {
- if (clip != null) {
- clip.prepareToLeaveProcess(true);
- }
+ Preconditions.checkNotNull(clip);
+ clip.prepareToLeaveProcess(true);
mService.setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -111,9 +108,24 @@
}
/**
- * Returns the current primary clip on the clipboard.
+ * Clears any current primary clip on the clipboard.
+ *
+ * @see #setPrimaryClip(ClipData)
*/
- public ClipData getPrimaryClip() {
+ public void clearPrimaryClip() {
+ try {
+ mService.clearPrimaryClip(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current primary clip on the clipboard.
+ *
+ * @see #setPrimaryClip(ClipData)
+ */
+ public @Nullable ClipData getPrimaryClip() {
try {
return mService.getPrimaryClip(mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -124,8 +136,10 @@
/**
* Returns a description of the current primary clip on the clipboard
* but not a copy of its data.
+ *
+ * @see #setPrimaryClip(ClipData)
*/
- public ClipDescription getPrimaryClipDescription() {
+ public @Nullable ClipDescription getPrimaryClipDescription() {
try {
return mService.getPrimaryClipDescription(mContext.getOpPackageName());
} catch (RemoteException e) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 22496a4..10331d4 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2102,7 +2102,23 @@
Preconditions.checkNotNull(uri, "uri");
try {
ActivityManager.getService().takePersistableUriPermission(
- ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
+ resolveUserId(uri));
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void takePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri,
+ @Intent.AccessUriMode int modeFlags) {
+ Preconditions.checkNotNull(toPackage, "toPackage");
+ Preconditions.checkNotNull(uri, "uri");
+ try {
+ ActivityManager.getService().takePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
+ resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -2120,7 +2136,23 @@
Preconditions.checkNotNull(uri, "uri");
try {
ActivityManager.getService().releasePersistableUriPermission(
- ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
+ resolveUserId(uri));
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void releasePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri,
+ @Intent.AccessUriMode int modeFlags) {
+ Preconditions.checkNotNull(toPackage, "toPackage");
+ Preconditions.checkNotNull(uri, "uri");
+ try {
+ ActivityManager.getService().releasePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
+ resolveUserId(uri));
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl
index af0b8f0..135a436 100644
--- a/core/java/android/content/IClipboard.aidl
+++ b/core/java/android/content/IClipboard.aidl
@@ -27,6 +27,7 @@
*/
interface IClipboard {
void setPrimaryClip(in ClipData clip, String callingPackage);
+ void clearPrimaryClip(String callingPackage);
ClipData getPrimaryClip(String pkg);
ClipDescription getPrimaryClipDescription(String callingPackage);
boolean hasPrimaryClip(String callingPackage);
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index a957aed..cec3bad 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1872,9 +1872,10 @@
du.println(sb.toString());
}
}
- if (mPriority != 0 || mHasPartialTypes) {
+ if (mPriority != 0 || mOrder != 0 || mHasPartialTypes) {
sb.setLength(0);
sb.append(prefix); sb.append("mPriority="); sb.append(mPriority);
+ sb.append(", mOrder="); sb.append(mOrder);
sb.append(", mHasPartialTypes="); sb.append(mHasPartialTypes);
du.println(sb.toString());
}
@@ -1951,6 +1952,7 @@
dest.writeInt(mHasPartialTypes ? 1 : 0);
dest.writeInt(getAutoVerify() ? 1 : 0);
dest.writeInt(mInstantAppVisibility);
+ dest.writeInt(mOrder);
}
/**
@@ -2020,6 +2022,7 @@
mHasPartialTypes = source.readInt() > 0;
setAutoVerify(source.readInt() > 0);
setVisibilityToInstantApp(source.readInt());
+ mOrder = source.readInt();
}
private final boolean findMimeType(String type) {
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 2c0c6ad0..53ffd55 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -43,6 +43,14 @@
*/
public class PackageItemInfo {
private static final float MAX_LABEL_SIZE_PX = 500f;
+
+ private static volatile boolean sForceSafeLabels = false;
+
+ /** {@hide} */
+ public static void setForceSafeLabels(boolean forceSafeLabels) {
+ sForceSafeLabels = forceSafeLabels;
+ }
+
/**
* Public name of this item. From the "android:name" attribute.
*/
@@ -128,7 +136,16 @@
* @return Returns a CharSequence containing the item's label. If the
* item does not have a label, its name is returned.
*/
- public CharSequence loadLabel(PackageManager pm) {
+ public @NonNull CharSequence loadLabel(@NonNull PackageManager pm) {
+ if (sForceSafeLabels) {
+ return loadSafeLabel(pm);
+ } else {
+ return loadUnsafeLabel(pm);
+ }
+ }
+
+ /** {@hide} */
+ public CharSequence loadUnsafeLabel(PackageManager pm) {
if (nonLocalizedLabel != null) {
return nonLocalizedLabel;
}
@@ -163,7 +180,7 @@
@SystemApi
public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
// loadLabel() always returns non-null
- String label = loadLabel(pm).toString();
+ String label = loadUnsafeLabel(pm).toString();
// strip HTML tags to avoid <br> and other tags overwriting original message
String labelStr = Html.fromHtml(label).toString();
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 41aa9c3..514112f 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -236,6 +236,11 @@
int userId);
/**
+ * @return The default home activity component name.
+ */
+ public abstract ComponentName getDefaultHomeActivity(int userId);
+
+ /**
* Called by DeviceOwnerManagerService to set the package names of device owner and profile
* owners.
*/
@@ -539,4 +544,16 @@
/** Updates the flags for the given permission. */
public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
@NonNull String packageName, int flagMask, int flagValues, int userId);
+
+ /**
+ * Returns true if it's still safe to restore data backed up from this app's version
+ * that was signed with restoringFromSigHash.
+ */
+ public abstract boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName);
+
+ /**
+ * Returns true if it's still safe to restore data backed up from this app's version
+ * that was signed with restoringFromSig.
+ */
+ public abstract boolean isDataRestoreSafe(Signature restoringFromSig, String packageName);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2420b63..04a028b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3190,7 +3190,7 @@
&& (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0
&& (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
PermissionInfo.PROTECTION_SIGNATURE) {
- outError[0] = "<permission> protectionLevel specifies a non-instnat flag but is "
+ outError[0] = "<permission> protectionLevel specifies a non-instant flag but is "
+ "not based on signature type";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3641,7 +3641,9 @@
// getting added to the wrong package.
final CachedComponentArgs cachedArgs = new CachedComponentArgs();
int type;
-
+ boolean hasActivityOrder = false;
+ boolean hasReceiverOrder = false;
+ boolean hasServiceOrder = false;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -3657,6 +3659,7 @@
return false;
}
+ hasActivityOrder |= (a.order != 0);
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
@@ -3667,6 +3670,7 @@
return false;
}
+ hasReceiverOrder |= (a.order != 0);
owner.receivers.add(a);
} else if (tagName.equals("service")) {
@@ -3676,6 +3680,7 @@
return false;
}
+ hasServiceOrder |= (s.order != 0);
owner.services.add(s);
} else if (tagName.equals("provider")) {
@@ -3694,6 +3699,7 @@
return false;
}
+ hasActivityOrder |= (a.order != 0);
owner.activities.add(a);
} else if (parser.getName().equals("meta-data")) {
@@ -3827,6 +3833,15 @@
}
}
+ if (hasActivityOrder) {
+ Collections.sort(owner.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
+ }
+ if (hasReceiverOrder) {
+ Collections.sort(owner.receivers, (r1, r2) -> Integer.compare(r2.order, r1.order));
+ }
+ if (hasServiceOrder) {
+ Collections.sort(owner.services, (s1, s2) -> Integer.compare(s2.order, s1.order));
+ }
// Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
// every activity info has had a chance to set it from its attributes.
setMaxAspectRatio(owner);
@@ -4368,6 +4383,7 @@
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
+ a.order = Math.max(intent.getOrder(), a.order);
a.intents.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
@@ -4678,6 +4694,7 @@
info.windowLayout = target.info.windowLayout;
info.resizeMode = target.info.resizeMode;
info.maxAspectRatio = target.info.maxAspectRatio;
+ info.requestedVrComponent = target.info.requestedVrComponent;
info.encryptionAware = info.directBootAware = target.info.directBootAware;
@@ -4745,6 +4762,7 @@
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
+ a.order = Math.max(intent.getOrder(), a.order);
a.intents.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
@@ -4952,6 +4970,7 @@
intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
}
+ outInfo.order = Math.max(intent.getOrder(), outInfo.order);
outInfo.intents.add(intent);
} else if (parser.getName().equals("meta-data")) {
@@ -5241,6 +5260,7 @@
intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
}
+ s.order = Math.max(intent.getOrder(), s.order);
s.intents.add(intent);
} else if (parser.getName().equals("meta-data")) {
if ((s.metaData=parseMetaData(res, parser, s.metaData,
@@ -5466,6 +5486,10 @@
com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
outInfo.setPriority(priority);
+ int order = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestIntentFilter_order, 0);
+ outInfo.setOrder(order);
+
TypedValue v = sa.peekValue(
com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
@@ -7053,6 +7077,8 @@
public Bundle metaData;
public Package owner;
+ /** The order of this component in relation to its peers */
+ public int order;
ComponentName componentName;
String componentShortName;
@@ -7571,6 +7597,7 @@
for (ActivityIntentInfo aii : intents) {
aii.activity = this;
+ order = Math.max(aii.getOrder(), order);
}
if (info.permission != null) {
@@ -7660,6 +7687,7 @@
for (ServiceIntentInfo aii : intents) {
aii.service = this;
+ order = Math.max(aii.getOrder(), order);
}
if (info.permission != null) {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 93690bf..19b5c45 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -16,10 +16,11 @@
package android.content.res;
+import static android.content.ConfigurationProto.COLOR_MODE;
import static android.content.ConfigurationProto.DENSITY_DPI;
import static android.content.ConfigurationProto.FONT_SCALE;
import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN;
-import static android.content.ConfigurationProto.HDR_COLOR_MODE;
+import static android.content.ConfigurationProto.KEYBOARD;
import static android.content.ConfigurationProto.KEYBOARD_HIDDEN;
import static android.content.ConfigurationProto.LOCALES;
import static android.content.ConfigurationProto.MCC;
@@ -33,7 +34,6 @@
import static android.content.ConfigurationProto.SMALLEST_SCREEN_WIDTH_DP;
import static android.content.ConfigurationProto.TOUCHSCREEN;
import static android.content.ConfigurationProto.UI_MODE;
-import static android.content.ConfigurationProto.WIDE_COLOR_GAMUT;
import static android.content.ConfigurationProto.WINDOW_CONFIGURATION;
import static android.content.ResourcesConfigurationProto.CONFIGURATION;
import static android.content.ResourcesConfigurationProto.SCREEN_HEIGHT_PX;
@@ -1095,11 +1095,9 @@
protoOutputStream.write(MNC, mnc);
mLocaleList.writeToProto(protoOutputStream, LOCALES);
protoOutputStream.write(SCREEN_LAYOUT, screenLayout);
- protoOutputStream.write(HDR_COLOR_MODE,
- (colorMode & Configuration.COLOR_MODE_HDR_MASK) >> COLOR_MODE_HDR_SHIFT);
- protoOutputStream.write(WIDE_COLOR_GAMUT,
- colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK);
+ protoOutputStream.write(COLOR_MODE, colorMode);
protoOutputStream.write(TOUCHSCREEN, touchscreen);
+ protoOutputStream.write(KEYBOARD, keyboard);
protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden);
protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden);
protoOutputStream.write(NAVIGATION, navigation);
@@ -1615,12 +1613,7 @@
dest.writeInt(mnc);
fixUpLocaleList();
- final int localeListSize = mLocaleList.size();
- dest.writeInt(localeListSize);
- for (int i = 0; i < localeListSize; ++i) {
- final Locale l = mLocaleList.get(i);
- dest.writeString(l.toLanguageTag());
- }
+ dest.writeParcelable(mLocaleList, flags);
if(userSetLocale) {
dest.writeInt(1);
@@ -1654,12 +1647,7 @@
mcc = source.readInt();
mnc = source.readInt();
- final int localeListSize = source.readInt();
- final Locale[] localeArray = new Locale[localeListSize];
- for (int i = 0; i < localeListSize; ++i) {
- localeArray[i] = Locale.forLanguageTag(source.readString());
- }
- mLocaleList = new LocaleList(localeArray);
+ mLocaleList = source.readParcelable(LocaleList.class.getClassLoader());
locale = mLocaleList.get(0);
userSetLocale = (source.readInt()==1);
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 6b2059e..36d5615 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -615,6 +615,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public Point getStableDisplaySize() {
return mGlobal.getStableDisplaySize();
}
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index f85ce3e..e1c69d7 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -33,7 +33,7 @@
*/
@SystemApi
@Deprecated
-public class ContextHubMessage {
+public class ContextHubMessage implements Parcelable {
private static final int DEBUG_LOG_NUM_BYTES = 16;
private int mType;
private int mVersion;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index b5c01ec..ded1bb8 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -36,7 +36,7 @@
*/
@SystemApi
@Deprecated
-public class NanoApp {
+public class NanoApp implements Parcelable {
private final String TAG = "NanoApp";
private final String UNKNOWN = "Unknown";
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 75a96ee..4d8e734 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -28,7 +28,7 @@
*/
@SystemApi
@Deprecated
-public class NanoAppFilter {
+public class NanoAppFilter implements Parcelable {
private static final String TAG = "NanoAppFilter";
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index f1926eaa..75fb915 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -34,7 +34,7 @@
*/
@SystemApi
@Deprecated
-public class NanoAppInstanceInfo {
+public class NanoAppInstanceInfo implements Parcelable {
private String mPublisher = "Unknown";
private String mName = "Unknown";
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 6e2654e..4631c56 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -25,6 +25,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
+import java.util.Comparator;
/**
* This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
@@ -187,6 +188,20 @@
}
/**
+ * Returns whether the specified prefix is entirely contained in this prefix.
+ *
+ * Note this is mathematical inclusion, so a prefix is always contained within itself.
+ * @param otherPrefix the prefix to test
+ * @hide
+ */
+ public boolean containsPrefix(IpPrefix otherPrefix) {
+ if (otherPrefix.getPrefixLength() < prefixLength) return false;
+ final byte[] otherAddress = otherPrefix.getRawAddress();
+ NetworkUtils.maskRawAddress(otherAddress, prefixLength);
+ return Arrays.equals(otherAddress, address);
+ }
+
+ /**
* @hide
*/
public boolean isIPv6() {
@@ -230,6 +245,38 @@
}
/**
+ * Returns a comparator ordering IpPrefixes by length, shorter to longer.
+ * Contents of the address will break ties.
+ * @hide
+ */
+ public static Comparator<IpPrefix> lengthComparator() {
+ return new Comparator<IpPrefix>() {
+ @Override
+ public int compare(IpPrefix prefix1, IpPrefix prefix2) {
+ if (prefix1.isIPv4()) {
+ if (prefix2.isIPv6()) return -1;
+ } else {
+ if (prefix2.isIPv4()) return 1;
+ }
+ final int p1len = prefix1.getPrefixLength();
+ final int p2len = prefix2.getPrefixLength();
+ if (p1len < p2len) return -1;
+ if (p2len < p1len) return 1;
+ final byte[] a1 = prefix1.address;
+ final byte[] a2 = prefix2.address;
+ final int len = a1.length < a2.length ? a1.length : a2.length;
+ for (int i = 0; i < len; ++i) {
+ if (a1[i] < a2[i]) return -1;
+ if (a1[i] > a2[i]) return 1;
+ }
+ if (a2.length < len) return 1;
+ if (a1.length < len) return -1;
+ return 0;
+ }
+ };
+ }
+
+ /**
* Implement the Parcelable interface.
*/
public static final Creator<IpPrefix> CREATOR =
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index bae373d..17b46c6 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -117,6 +117,7 @@
NET_CAPABILITY_FOREGROUND,
NET_CAPABILITY_NOT_CONGESTED,
NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_OEM_PAID,
})
public @interface NetCapability { }
@@ -264,8 +265,15 @@
*/
public static final int NET_CAPABILITY_NOT_SUSPENDED = 21;
+ /**
+ * Indicates that traffic that goes through this network is paid by oem. For example,
+ * this network can be used by system apps to upload telemetry data.
+ * @hide
+ */
+ public static final int NET_CAPABILITY_OEM_PAID = 22;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_SUSPENDED;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_OEM_PAID;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -313,7 +321,8 @@
(1 << NET_CAPABILITY_IA) |
(1 << NET_CAPABILITY_IMS) |
(1 << NET_CAPABILITY_RCS) |
- (1 << NET_CAPABILITY_XCAP);
+ (1 << NET_CAPABILITY_XCAP) |
+ (1 << NET_CAPABILITY_OEM_PAID);
/**
* Capabilities that suggest that a network is unrestricted.
@@ -882,7 +891,16 @@
/**
* List of UIDs this network applies to. No restriction if null.
* <p>
- * This is typically (and at this time, only) used by VPN. This network is only available to
+ * For networks, mUids represent the list of network this applies to, and null means this
+ * network applies to all UIDs.
+ * For requests, mUids is the list of UIDs this network MUST apply to to match ; ALL UIDs
+ * must be included in a network so that they match. As an exception to the general rule,
+ * a null mUids field for requests mean "no requirements" rather than what the general rule
+ * would suggest ("must apply to all UIDs") : this is because this has shown to be what users
+ * of this API expect in practice. A network that must match all UIDs can still be
+ * expressed with a set ranging the entire set of possible UIDs.
+ * <p>
+ * mUids is typically (and at this time, only) used by VPN. This network is only available to
* the UIDs in this list, and it is their default network. Apps in this list that wish to
* bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
* member is null, then the network is not restricted by app UID. If it's an empty list, then
@@ -1004,8 +1022,7 @@
* @hide
*/
public boolean satisfiedByUids(NetworkCapabilities nc) {
- if (null == nc.mUids) return true; // The network satisfies everything.
- if (null == mUids) return false; // Not everything allowed but requires everything
+ if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
for (UidRange requiredRange : mUids) {
if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
if (!nc.appliesToUidRange(requiredRange)) {
@@ -1218,34 +1235,68 @@
@Override
public String toString() {
- // TODO: enumerate bits for transports and capabilities instead of creating arrays.
- // TODO: use a StringBuilder instead of string concatenation.
- int[] types = getTransportTypes();
- String transports = (types.length > 0) ? " Transports: " + transportNamesOf(types) : "";
-
- types = getCapabilities();
- String capabilities = (types.length > 0 ? " Capabilities: " : "");
- for (int i = 0; i < types.length; ) {
- capabilities += capabilityNameOf(types[i]);
- if (++i < types.length) capabilities += "&";
+ final StringBuilder sb = new StringBuilder("[");
+ if (0 != mTransportTypes) {
+ sb.append(" Transports: ");
+ appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes,
+ NetworkCapabilities::transportNameOf, "|");
+ }
+ if (0 != mNetworkCapabilities) {
+ sb.append(" Capabilities: ");
+ appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
+ NetworkCapabilities::capabilityNameOf, "&");
+ }
+ if (mLinkUpBandwidthKbps > 0) {
+ sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps");
+ }
+ if (mLinkDownBandwidthKbps > 0) {
+ sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps");
+ }
+ if (mNetworkSpecifier != null) {
+ sb.append(" Specifier: <").append(mNetworkSpecifier).append(">");
+ }
+ if (hasSignalStrength()) {
+ sb.append(" SignalStrength: ").append(mSignalStrength);
}
- String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
- mLinkUpBandwidthKbps + "Kbps" : "");
- String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" +
- mLinkDownBandwidthKbps + "Kbps" : "");
+ if (null != mUids) {
+ if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) {
+ sb.append(" Uid: ").append(mUids.valueAt(0).start);
+ } else {
+ sb.append(" Uids: <").append(mUids).append(">");
+ }
+ }
+ if (mEstablishingVpnAppUid != INVALID_UID) {
+ sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
+ }
- String specifier = (mNetworkSpecifier == null ?
- "" : " Specifier: <" + mNetworkSpecifier + ">");
+ sb.append("]");
+ return sb.toString();
+ }
- String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : "");
- String uids = (null != mUids ? " Uids: <" + mUids + ">" : "");
-
- String establishingAppUid = " EstablishingAppUid: " + mEstablishingVpnAppUid;
-
- return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength
- + uids + establishingAppUid + "]";
+ private interface NameOf {
+ String nameOf(int value);
+ }
+ /**
+ * @hide
+ */
+ public static void appendStringRepresentationOfBitMaskToStringBuilder(StringBuilder sb,
+ long bitMask, NameOf nameFetcher, String separator) {
+ int bitPos = 0;
+ boolean firstElementAdded = false;
+ while (bitMask != 0) {
+ if ((bitMask & 1) != 0) {
+ if (firstElementAdded) {
+ sb.append(separator);
+ } else {
+ firstElementAdded = true;
+ }
+ sb.append(nameFetcher.nameOf(bitPos));
+ }
+ bitMask >>= 1;
+ ++bitPos;
+ }
}
/** @hide */
@@ -1313,6 +1364,7 @@
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED";
case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED";
+ case NET_CAPABILITY_OEM_PAID: return "OEM_PAID";
default: return Integer.toString(capability);
}
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index a072409..61199f9 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
@@ -132,12 +133,18 @@
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
- private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities();
+ private final NetworkCapabilities mNetworkCapabilities;
/**
* Default constructor for Builder.
*/
- public Builder() {}
+ public Builder() {
+ // By default, restrict this request to networks available to this app.
+ // Apps can rescind this restriction, but ConnectivityService will enforce
+ // it for apps that do not have the NETWORK_SETTINGS permission.
+ mNetworkCapabilities = new NetworkCapabilities();
+ mNetworkCapabilities.setSingleUid(Process.myUid());
+ }
/**
* Build {@link NetworkRequest} give the current set of capabilities.
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index fe9563d..9a5d502 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,19 +16,20 @@
package android.net;
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Collection;
-import java.util.Locale;
-
import android.os.Parcel;
import android.util.Log;
import android.util.Pair;
+import java.io.FileDescriptor;
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.TreeSet;
/**
* Native methods for managing network interfaces.
@@ -385,4 +386,72 @@
result = builder.toString();
return result;
}
+
+ /**
+ * Returns a prefix set without overlaps.
+ *
+ * This expects the src set to be sorted from shorter to longer. Results are undefined
+ * failing this condition. The returned prefix set is sorted in the same order as the
+ * passed set, with the same comparator.
+ */
+ private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
+ final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
+ // Prefixes match addresses that share their upper part up to their length, therefore
+ // the only kind of possible overlap in two prefixes is strict inclusion of the longer
+ // (more restrictive) in the shorter (including equivalence if they have the same
+ // length).
+ // Because prefixes in the src set are sorted from shorter to longer, deduplicating
+ // is done by simply iterating in order, and not adding any longer prefix that is
+ // already covered by a shorter one.
+ newPrefixes:
+ for (IpPrefix newPrefix : src) {
+ for (IpPrefix existingPrefix : dst) {
+ if (existingPrefix.containsPrefix(newPrefix)) {
+ continue newPrefixes;
+ }
+ }
+ dst.add(newPrefix);
+ }
+ return dst;
+ }
+
+ /**
+ * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
+ *
+ * Obviously this returns an integral value between 0 and 2**32.
+ * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
+ * set is not ordered smallest prefix to longer prefix.
+ *
+ * @param prefixes the set of prefixes, ordered by length
+ */
+ public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
+ long routedIPCount = 0;
+ for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
+ if (!prefix.isIPv4()) {
+ Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
+ }
+ int rank = 32 - prefix.getPrefixLength();
+ routedIPCount += 1L << rank;
+ }
+ return routedIPCount;
+ }
+
+ /**
+ * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
+ *
+ * This returns a BigInteger between 0 and 2**128.
+ * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
+ * set is not ordered smallest prefix to longer prefix.
+ */
+ public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
+ BigInteger routedIPCount = BigInteger.ZERO;
+ for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
+ if (!prefix.isIPv6()) {
+ Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
+ }
+ int rank = 128 - prefix.getPrefixLength();
+ routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
+ }
+ return routedIPCount;
+ }
}
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index fd465d9..3164929 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -21,8 +21,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.IllegalArgumentException;
-
/**
* An inclusive range of UIDs.
*
@@ -53,6 +51,13 @@
}
/**
+ * Returns the count of UIDs in this range.
+ */
+ public int count() {
+ return 1 + stop - start;
+ }
+
+ /**
* @return {@code true} if this range contains every UID contained by the {@param other} range.
*/
public boolean containsRange(UidRange other) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 48f5684..6d8831b 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
@@ -287,6 +288,7 @@
* we are operating under, we bump the assumed resource platform version by 1.
* @hide
*/
+ @TestApi
public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length;
/**
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index eae7d70..3d072c5 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -63,6 +63,8 @@
/**
* Device temperature types.
*/
+ // These constants are also defined in android/os/enums.proto.
+ // Any change to the types here or in the thermal hal should be made in the proto as well.
/** Temperature of CPUs in Celsius. */
public static final int DEVICE_TEMPERATURE_CPU = Constants.TemperatureType.CPU;
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index eae5217..29c298e 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -41,7 +41,7 @@
oneway void cancelAnomalyAlarm();
/**
- * Register a repeating alarm for polling to fire at the given timestamp and every
+ * Register a repeating alarm for pulling to fire at the given timestamp and every
* intervalMs thereafter (in ms since epoch).
* If polling alarm had already been registered, it will be replaced by new one.
* Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
@@ -49,9 +49,19 @@
*/
oneway void setPullingAlarms(long timestampMs, long intervalMs);
- /** Cancel any repeating polling alarm. */
+ /** Cancel any repeating pulling alarm. */
oneway void cancelPullingAlarms();
+ /**
+ * Register an alarm when we want to trigger subscribers at the given
+ * timestamp (in ms since epoch).
+ * If an alarm had already been registered, it will be replaced by new one.
+ */
+ oneway void setAlarmForSubscriberTriggering(long timestampMs);
+
+ /** Cancel any alarm for the purpose of subscriber triggering. */
+ oneway void cancelAlarmForSubscriberTriggering();
+
/** Pull the specified data. Results will be sent to statsd when complete. */
StatsLogEventWrapper[] pullData(int pullCode);
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 682a24f1..2a68714 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -47,6 +47,13 @@
void informPollAlarmFired();
/**
+ * Tells statsd that it is time to handle periodic alarms. Statsd will be responsible for
+ * determing what alarm subscriber to trigger.
+ * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
+ */
+ void informAlarmForSubscriberTriggeringFired();
+
+ /**
* Tells statsd to store data to disk.
*/
void writeDataToDisk();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 811cc5e..97d415e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -538,6 +538,7 @@
ServiceType.DATA_SAVER,
ServiceType.FORCE_ALL_APPS_STANDBY,
ServiceType.OPTIONAL_SENSORS,
+ ServiceType.AOD,
})
public @interface ServiceType {
int NULL = 0;
@@ -551,6 +552,7 @@
int SOUND = 8;
int BATTERY_STATS = 9;
int DATA_SAVER = 10;
+ int AOD = 14;
/**
* Whether to enable force-app-standby on all apps or not.
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 76c13be..a93e25a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -479,6 +479,8 @@
/** Initialize a Builder from an existing ThreadPolicy. */
public Builder(ThreadPolicy policy) {
mMask = policy.mask;
+ mListener = policy.mListener;
+ mExecutor = policy.mCallbackExecutor;
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1856200..a9eb360 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -36,6 +36,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -691,14 +692,13 @@
/**
* Specifies that system error dialogs for crashed or unresponsive apps should not be shown.
* In this case, the system will force-stop the app as if the user chooses the "close app"
- * option on the UI. No feedback report will be collected as there is no way for the user to
- * provide explicit consent.
+ * option on the UI. A feedback report isn't collected as there is no way for the user to
+ * provide explicit consent. The default value is <code>false</code>.
*
- * When this user restriction is set by device owners, it's applied to all users; when it's set
- * by profile owners, it's only applied to the relevant profiles.
- * The default value is <code>false</code>.
+ * <p>When this user restriction is set by device owners, it's applied to all users. When set by
+ * the profile owner of the primary user or a secondary user, the restriction affects only the
+ * calling user. This user restriction has no effect on managed profiles.
*
- * <p>This user restriction has no effect on managed profiles.
* <p>Key for user restrictions.
* <p>Type: Boolean
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
@@ -913,6 +913,9 @@
* Specifies if user switching is blocked on the current user.
*
* <p> This restriction can only be set by the device owner, it will be applied to all users.
+ * Device owner can still switch user via
+ * {@link DevicePolicyManager#switchUser(ComponentName, UserHandle)} when this restriction is
+ * set.
*
* <p>The default value is <code>false</code>.
*
@@ -1039,6 +1042,85 @@
*/
public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1;
+ /**
+ * Indicates user operation is successful.
+ */
+ public static final int USER_OPERATION_SUCCESS = 0;
+
+ /**
+ * Indicates user operation failed for unknown reason.
+ */
+ public static final int USER_OPERATION_ERROR_UNKNOWN = 1;
+
+ /**
+ * Indicates user operation failed because target user is a managed profile.
+ */
+ public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2;
+
+ /**
+ * Indicates user operation failed because maximum running user limit has been reached.
+ */
+ public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3;
+
+ /**
+ * Indicates user operation failed because the target user is in the foreground.
+ */
+ public static final int USER_OPERATION_ERROR_CURRENT_USER = 4;
+
+ /**
+ * Indicates user operation failed because device has low data storage.
+ */
+ public static final int USER_OPERATION_ERROR_LOW_STORAGE = 5;
+
+ /**
+ * Indicates user operation failed because maximum user limit has been reached.
+ */
+ public static final int USER_OPERATION_ERROR_MAX_USERS = 6;
+
+ /**
+ * Result returned from various user operations.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "USER_OPERATION_" }, value = {
+ USER_OPERATION_SUCCESS,
+ USER_OPERATION_ERROR_UNKNOWN,
+ USER_OPERATION_ERROR_MANAGED_PROFILE,
+ USER_OPERATION_ERROR_MAX_RUNNING_USERS,
+ USER_OPERATION_ERROR_CURRENT_USER,
+ USER_OPERATION_ERROR_LOW_STORAGE,
+ USER_OPERATION_ERROR_MAX_USERS
+ })
+ public @interface UserOperationResult {}
+
+ /**
+ * Thrown to indicate user operation failed.
+ */
+ public static class UserOperationException extends RuntimeException {
+ private final @UserOperationResult int mUserOperationResult;
+
+ /**
+ * Constructs a UserOperationException with specific result code.
+ *
+ * @param message the detail message
+ * @param userOperationResult the result code
+ * @hide
+ */
+ public UserOperationException(String message,
+ @UserOperationResult int userOperationResult) {
+ super(message);
+ mUserOperationResult = userOperationResult;
+ }
+
+ /**
+ * Returns the operation result code.
+ */
+ public @UserOperationResult int getUserOperationResult() {
+ return mUserOperationResult;
+ }
+ }
+
/** @hide */
public static UserManager get(Context context) {
return (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -2530,8 +2612,13 @@
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
- // Svelte devices don't get multi-user.
- if (ActivityManager.isLowRamDeviceStatic()) return 1;
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ // Low-ram devices are Svelte. Most of the time they don't get multi-user.
+ if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK)
+ != Configuration.UI_MODE_TYPE_TELEVISION) {
+ return 1;
+ }
+ }
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 57418c8..ca4c796 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -493,11 +493,12 @@
* Instructs the zygote to pre-load the classes and native libraries at the given paths
* for the specified abi. Not all zygotes support this function.
*/
- public boolean preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
- String abi) throws ZygoteStartFailedEx, IOException {
+ public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
+ String cacheKey, String abi) throws ZygoteStartFailedEx,
+ IOException {
synchronized(mLock) {
ZygoteState state = openZygoteSocketIfNeeded(abi);
- state.writer.write("4");
+ state.writer.write("5");
state.writer.newLine();
state.writer.write("--preload-package");
@@ -509,6 +510,9 @@
state.writer.write(libsPath);
state.writer.newLine();
+ state.writer.write(libFileName);
+ state.writer.newLine();
+
state.writer.write(cacheKey);
state.writer.newLine();
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 60df467..70de09e 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -223,14 +223,14 @@
/** Call was WIFI call. */
public static final int FEATURES_WIFI = 1 << 3;
- /** Call was on RTT at some point */
- public static final int FEATURES_RTT = 1 << 4;
-
/**
* Indicates the call underwent Assisted Dialing.
* @hide
*/
- public static final Integer FEATURES_ASSISTED_DIALING_USED = 0x10;
+ public static final int FEATURES_ASSISTED_DIALING_USED = 1 << 4;
+
+ /** Call was on RTT at some point */
+ public static final int FEATURES_RTT = 1 << 5;
/**
* The phone number as the user entered it.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0442c9c..8fc6901 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7103,6 +7103,14 @@
SHOW_ROTATION_SUGGESTIONS_ENABLED;
/**
+ * The number of accepted rotation suggestions. Used to determine if the user has been
+ * introduced to rotation suggestions.
+ * @hide
+ */
+ public static final String NUM_ROTATION_SUGGESTIONS_ACCEPTED =
+ "num_rotation_suggestions_accepted";
+
+ /**
* Read only list of the service components that the current user has explicitly allowed to
* see and assist with all of the user's notifications.
*
@@ -8573,6 +8581,7 @@
* (0 = false, 1 = true)
* @hide
*/
+ @SystemApi
public static final String EUICC_PROVISIONED = "euicc_provisioned";
/**
@@ -10507,8 +10516,13 @@
* entity_list_default use ":" as delimiter for values. Ex:
*
* <pre>
- * smart_selection_dark_launch (boolean)
- * smart_selection_enabled_for_edit_text (boolean)
+ * smart_linkify_enabled (boolean)
+ * system_textclassifier_enabled (boolean)
+ * model_dark_launch_enabled (boolean)
+ * smart_selection_enabled (boolean)
+ * smart_text_share_enabled (boolean)
+ * smart_linkify_enabled (boolean)
+ * smart_select_animation_enabled (boolean)
* suggest_selection_max_range_length (int)
* classify_text_max_range_length (int)
* generate_links_max_text_length (int)
@@ -10521,7 +10535,7 @@
* <p>
* Type: string
* @hide
- * see also android.view.textclassifier.TextClassifierConstants
+ * see also android.view.textclassifier.TextClassificationConstants
*/
public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants";
@@ -10581,6 +10595,23 @@
= "forced_app_standby_for_small_battery_enabled";
/**
+ * Whether or not to enable the Off Body, Radios Off feature on small battery devices.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED
+ = "off_body_radios_off_for_small_battery_enabled";
+
+ /**
+ * How long after the device goes off body to disable radios, in milliseconds.
+ * Type: long
+ * Default: 10 minutes
+ * @hide
+ */
+ public static final String OFF_BODY_RADIOS_OFF_DELAY_MS = "off_body_radios_off_delay_ms";
+
+ /**
* Whether or not to enable Time Only Mode for watch type devices.
* Type: int (0 for false, 1 for true)
* Default: 0
@@ -11437,6 +11468,7 @@
*
* @hide
*/
+ @TestApi
public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS =
"hidden_api_blacklist_exemptions";
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java
index e9df370..f6127e1 100644
--- a/core/java/android/security/ConfirmationDialog.java
+++ b/core/java/android/security/ConfirmationDialog.java
@@ -17,7 +17,10 @@
package android.security;
import android.annotation.NonNull;
+import android.content.ContentResolver;
import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Log;
@@ -86,6 +89,7 @@
private byte[] mExtraData;
private ConfirmationCallback mCallback;
private Executor mExecutor;
+ private Context mContext;
private final KeyStore mKeyStore = KeyStore.getInstance();
@@ -190,15 +194,39 @@
if (mExtraData == null) {
throw new IllegalArgumentException("extraData must be set");
}
- return new ConfirmationDialog(mPromptText, mExtraData);
+ return new ConfirmationDialog(context, mPromptText, mExtraData);
}
}
- private ConfirmationDialog(CharSequence promptText, byte[] extraData) {
+ private ConfirmationDialog(Context context, CharSequence promptText, byte[] extraData) {
+ mContext = context;
mPromptText = promptText;
mExtraData = extraData;
}
+ private static final int UI_OPTION_ACCESSIBILITY_INVERTED_FLAG = 1 << 0;
+ private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1;
+
+ private int getUiOptionsAsFlags() {
+ int uiOptionsAsFlags = 0;
+ try {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ int inversionEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ if (inversionEnabled == 1) {
+ uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
+ }
+ float fontScale = Settings.System.getFloat(contentResolver,
+ Settings.System.FONT_SCALE);
+ if (fontScale > 1.0) {
+ uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
+ }
+ } catch (SettingNotFoundException e) {
+ Log.w(TAG, "Unexpected SettingNotFoundException");
+ }
+ return uiOptionsAsFlags;
+ }
+
/**
* Requests a confirmation prompt to be presented to the user.
*
@@ -220,8 +248,7 @@
mCallback = callback;
mExecutor = executor;
- int uiOptionsAsFlags = 0;
- // TODO: set AccessibilityInverted, AccessibilityMagnified in uiOptionsAsFlags as needed.
+ int uiOptionsAsFlags = getUiOptionsAsFlags();
String locale = Locale.getDefault().toLanguageTag();
int responseCode = mKeyStore.presentConfirmationPrompt(
mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
@@ -277,7 +304,6 @@
* @return true if confirmation prompts are supported by the device.
*/
public static boolean isSupported() {
- // TODO: read and return system property.
- return true;
+ return KeyStore.getInstance().isConfirmationPromptSupported();
}
}
diff --git a/core/java/android/security/keystore/BadCertificateFormatException.java b/core/java/android/security/keystore/BadCertificateFormatException.java
index ddc7bd2..c51b773 100644
--- a/core/java/android/security/keystore/BadCertificateFormatException.java
+++ b/core/java/android/security/keystore/BadCertificateFormatException.java
@@ -17,8 +17,7 @@
package android.security.keystore;
/**
- * Error thrown when the recovery agent supplies an invalid X509 certificate.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.BadCertificateFormatException}.
* @hide
*/
public class BadCertificateFormatException extends RecoveryControllerException {
diff --git a/core/java/android/security/keystore/DecryptionFailedException.java b/core/java/android/security/keystore/DecryptionFailedException.java
index 945fcf6..c0b52f7 100644
--- a/core/java/android/security/keystore/DecryptionFailedException.java
+++ b/core/java/android/security/keystore/DecryptionFailedException.java
@@ -17,9 +17,7 @@
package android.security.keystore;
/**
- * Error thrown when decryption failed, due to an agent error. i.e., using the incorrect key,
- * trying to decrypt garbage data, trying to decrypt data that has somehow been corrupted, etc.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.DecryptionFailedException}.
* @hide
*/
public class DecryptionFailedException extends RecoveryControllerException {
diff --git a/core/java/android/security/keystore/InternalRecoveryServiceException.java b/core/java/android/security/keystore/InternalRecoveryServiceException.java
index 85829be..40076f7 100644
--- a/core/java/android/security/keystore/InternalRecoveryServiceException.java
+++ b/core/java/android/security/keystore/InternalRecoveryServiceException.java
@@ -17,11 +17,7 @@
package android.security.keystore;
/**
- * An error thrown when something went wrong internally in the recovery service.
- *
- * <p>This is an unexpected error, and indicates a problem with the service itself, rather than the
- * caller having performed some kind of illegal action.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.InternalRecoveryServiceException}.
* @hide
*/
public class InternalRecoveryServiceException extends RecoveryControllerException {
diff --git a/core/java/android/security/keystore/KeyDerivationParams.java b/core/java/android/security/keystore/KeyDerivationParams.java
index b19cee2..e475dc3 100644
--- a/core/java/android/security/keystore/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/KeyDerivationParams.java
@@ -27,9 +27,7 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Collection of parameters which define a key derivation function.
- * Currently only supports salted SHA-256
- *
+ * @deprecated Use {@link android.security.keystore.recovery.KeyDerivationParams}.
* @hide
*/
public final class KeyDerivationParams implements Parcelable {
diff --git a/core/java/android/security/keystore/KeychainProtectionParams.java b/core/java/android/security/keystore/KeychainProtectionParams.java
index a940fdc..19a087d 100644
--- a/core/java/android/security/keystore/KeychainProtectionParams.java
+++ b/core/java/android/security/keystore/KeychainProtectionParams.java
@@ -28,23 +28,7 @@
import java.util.Arrays;
/**
- * A {@link KeychainSnapshot} is protected with a key derived from the user's lock screen. This
- * class wraps all the data necessary to derive the same key on a recovering device:
- *
- * <ul>
- * <li>UI parameters for the user's lock screen - so that if e.g., the user was using a pattern,
- * the recovering device can display the pattern UI to the user when asking them to enter
- * the lock screen from their previous device.
- * <li>The algorithm used to derive a key from the user's lock screen, e.g. SHA-256 with a salt.
- * </ul>
- *
- * <p>As such, this data is sent along with the {@link KeychainSnapshot} when syncing the current
- * version of the keychain.
- *
- * <p>For now, the recoverable keychain only supports a single layer of protection, which is the
- * user's lock screen. In the future, the keychain will support multiple layers of protection
- * (e.g. an additional keychain password, along with the lock screen).
- *
+ * @deprecated Use {@link android.security.keystore.recovery.KeyChainProtectionParams}.
* @hide
*/
public final class KeychainProtectionParams implements Parcelable {
diff --git a/core/java/android/security/keystore/KeychainSnapshot.java b/core/java/android/security/keystore/KeychainSnapshot.java
index 23aec25..cf18fd1 100644
--- a/core/java/android/security/keystore/KeychainSnapshot.java
+++ b/core/java/android/security/keystore/KeychainSnapshot.java
@@ -25,21 +25,7 @@
import java.util.List;
/**
- * A snapshot of a version of the keystore. Two events can trigger the generation of a new snapshot:
- *
- * <ul>
- * <li>The user's lock screen changes. (A key derived from the user's lock screen is used to
- * protected the keychain, which is why this forces a new snapshot.)
- * <li>A key is added to or removed from the recoverable keychain.
- * </ul>
- *
- * <p>The snapshot data is also encrypted with the remote trusted hardware's public key, so even
- * the recovery agent itself should not be able to decipher the data. The recovery agent sends an
- * instance of this to the remote trusted hardware whenever a new snapshot is generated. During a
- * recovery flow, the recovery agent retrieves a snapshot from the remote trusted hardware. It then
- * sends it to the framework, where it is decrypted using the user's lock screen from their previous
- * device.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.KeyChainSnapshot}.
* @hide
*/
public final class KeychainSnapshot implements Parcelable {
diff --git a/core/java/android/security/keystore/LockScreenRequiredException.java b/core/java/android/security/keystore/LockScreenRequiredException.java
index b07fb9c..0970284 100644
--- a/core/java/android/security/keystore/LockScreenRequiredException.java
+++ b/core/java/android/security/keystore/LockScreenRequiredException.java
@@ -17,10 +17,7 @@
package android.security.keystore;
/**
- * Error thrown when trying to generate keys for a profile that has no lock screen set.
- *
- * <p>A lock screen must be set, as the lock screen is used to encrypt the snapshot.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.LockScreenRequiredException}.
* @hide
*/
public class LockScreenRequiredException extends RecoveryControllerException {
diff --git a/core/java/android/security/keystore/RecoveryClaim.java b/core/java/android/security/keystore/RecoveryClaim.java
index 6f566af..12be607 100644
--- a/core/java/android/security/keystore/RecoveryClaim.java
+++ b/core/java/android/security/keystore/RecoveryClaim.java
@@ -17,8 +17,7 @@
package android.security.keystore;
/**
- * An attempt to recover a keychain protected by remote secure hardware.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.RecoverySession}.
* @hide
*/
public class RecoveryClaim {
diff --git a/core/java/android/security/keystore/RecoveryController.java b/core/java/android/security/keystore/RecoveryController.java
index 4a0de5f..145261e 100644
--- a/core/java/android/security/keystore/RecoveryController.java
+++ b/core/java/android/security/keystore/RecoveryController.java
@@ -31,22 +31,6 @@
import java.util.Map;
/**
- * An assistant for generating {@link javax.crypto.SecretKey} instances that can be recovered by
- * other Android devices belonging to the user. The exported keychain is protected by the user's
- * lock screen.
- *
- * <p>The RecoveryController must be paired with a recovery agent. The recovery agent is responsible
- * for transporting the keychain to remote trusted hardware. This hardware must prevent brute force
- * attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10).
- * After that number of incorrect guesses, the trusted hardware no longer allows access to the
- * key chain.
- *
- * <p>For now only the recovery agent itself is able to create keys, so it is expected that the
- * recovery agent is itself the system app.
- *
- * <p>A recovery agent requires the privileged permission
- * {@code android.Manifest.permission#RECOVER_KEYSTORE}.
- *
* @deprecated Use {@link android.security.keystore.recovery.RecoveryController}.
* @hide
*/
diff --git a/core/java/android/security/keystore/RecoveryControllerException.java b/core/java/android/security/keystore/RecoveryControllerException.java
index 5b806b7..f990c23 100644
--- a/core/java/android/security/keystore/RecoveryControllerException.java
+++ b/core/java/android/security/keystore/RecoveryControllerException.java
@@ -19,8 +19,7 @@
import java.security.GeneralSecurityException;
/**
- * Base exception for errors thrown by {@link RecoveryController}.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.RecoveryController}.
* @hide
*/
public abstract class RecoveryControllerException extends GeneralSecurityException {
diff --git a/core/java/android/security/keystore/RecoverySession.java b/core/java/android/security/keystore/RecoverySession.java
index ae8d91a..8a3e06b 100644
--- a/core/java/android/security/keystore/RecoverySession.java
+++ b/core/java/android/security/keystore/RecoverySession.java
@@ -19,9 +19,7 @@
import java.security.SecureRandom;
/**
- * Session to recover a {@link KeychainSnapshot} from the remote trusted hardware, initiated by a
- * recovery agent.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.RecoverySession}.
* @hide
*/
public class RecoverySession implements AutoCloseable {
diff --git a/core/java/android/security/keystore/SessionExpiredException.java b/core/java/android/security/keystore/SessionExpiredException.java
index f13e206..7c8d5e4 100644
--- a/core/java/android/security/keystore/SessionExpiredException.java
+++ b/core/java/android/security/keystore/SessionExpiredException.java
@@ -17,8 +17,7 @@
package android.security.keystore;
/**
- * Error thrown when attempting to use a {@link RecoverySession} that has since expired.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.SessionExpiredException}.
* @hide
*/
public class SessionExpiredException extends RecoveryControllerException {
diff --git a/core/java/android/security/keystore/WrappedApplicationKey.java b/core/java/android/security/keystore/WrappedApplicationKey.java
index 522bb95..2ce8c7d 100644
--- a/core/java/android/security/keystore/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/WrappedApplicationKey.java
@@ -23,16 +23,7 @@
import com.android.internal.util.Preconditions;
/**
- * Helper class with data necessary recover a single application key, given a recovery key.
- *
- * <ul>
- * <li>Alias - Keystore alias of the key.
- * <li>Encrypted key material.
- * </ul>
- *
- * Note that Application info is not included. Recovery Agent can only make its own keys
- * recoverable.
- *
+ * @deprecated Use {@link android.security.keystore.recovery.WrappedApplicationKey}.
* @hide
*/
public final class WrappedApplicationKey implements Parcelable {
diff --git a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
index e0781a5..4275c29 100644
--- a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
+++ b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
@@ -17,10 +17,8 @@
package android.security.keystore.recovery;
/**
- * Error thrown when the recovery agent supplies an invalid X509 certificate.
- *
+ * @deprecated Not used.
* @hide
- * Deprecated
*/
public class BadCertificateFormatException extends RecoveryControllerException {
public BadCertificateFormatException(String msg) {
diff --git a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
index 218d26e..e62bfb1 100644
--- a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
+++ b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
@@ -19,6 +19,7 @@
import android.annotation.SystemApi;
import java.security.GeneralSecurityException;
+
/**
* An error thrown when something went wrong internally in the recovery service.
*
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index f043d6a..4580c47 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -116,7 +116,6 @@
* See implementation for binary key format.
*
* @deprecated Use {@link #getTrustedHardwareCertPath} instead.
- * @removed
*/
@Deprecated
public @NonNull byte[] getTrustedHardwarePublicKey() {
@@ -221,7 +220,6 @@
* @param publicKey The public key
* @return This builder.
* @deprecated Use {@link #setTrustedHardwareCertPath} instead.
- * @removed
*/
@Deprecated
public Builder setTrustedHardwarePublicKey(byte[] publicKey) {
diff --git a/core/java/android/security/keystore/recovery/RecoveryClaim.java b/core/java/android/security/keystore/recovery/RecoveryClaim.java
deleted file mode 100644
index 45c6b4ff..0000000
--- a/core/java/android/security/keystore/recovery/RecoveryClaim.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.security.keystore.recovery;
-
-/**
- * An attempt to recover a keychain protected by remote secure hardware.
- *
- * @hide
- * Deprecated
- */
-public class RecoveryClaim {
-
- private final RecoverySession mRecoverySession;
- private final byte[] mClaimBytes;
-
- RecoveryClaim(RecoverySession recoverySession, byte[] claimBytes) {
- mRecoverySession = recoverySession;
- mClaimBytes = claimBytes;
- }
-
- /**
- * Returns the session associated with the recovery attempt. This is used to match the symmetric
- * key, which remains internal to the framework, for decrypting the claim response.
- *
- * @return The session data.
- */
- public RecoverySession getRecoverySession() {
- return mRecoverySession;
- }
-
- /**
- * Returns the encrypted claim's bytes.
- *
- * <p>This should be sent by the recovery agent to the remote secure hardware, which will use
- * it to decrypt the keychain, before sending it re-encrypted with the session's symmetric key
- * to the device.
- */
- public byte[] getClaimBytes() {
- return mClaimBytes;
- }
-}
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 0d262c9..4881375 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -46,11 +46,11 @@
* <p>The RecoveryController must be paired with a recovery agent. The recovery agent is responsible
* for transporting the keychain to remote trusted hardware. This hardware must prevent brute force
* attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10).
- * After that number of incorrect guesses, the trusted hardware no longer allows access to the
+ * After that number of incorrect guesses, the trusted hardware no longer allows access to the
* key chain.
*
- * <p>For now only the recovery agent itself is able to create keys, so it is expected that the
- * recovery agent is itself the system app.
+ * <p>Only the recovery agent itself is able to create keys, so it is expected that the recovery
+ * agent is itself the system app.
*
* <p>A recovery agent requires the privileged permission
* {@code android.Manifest.permission#RECOVER_KEYSTORE}.
@@ -99,7 +99,11 @@
public static final int ERROR_SESSION_EXPIRED = 24;
/**
- * Failed because the provided certificate was not a valid X509 certificate.
+ * Failed because the format of the provided certificate is incorrect, e.g., cannot be decoded
+ * properly or misses necessary fields.
+ *
+ * <p>Note that this is different from {@link #ERROR_INVALID_CERTIFICATE}, which implies the
+ * certificate has a correct format but cannot be validated.
*
* @hide
*/
@@ -113,6 +117,24 @@
*/
public static final int ERROR_DECRYPTION_FAILED = 26;
+ /**
+ * Error thrown if the format of a given key is invalid. This might be because the key has a
+ * wrong length, invalid content, etc.
+ *
+ * @hide
+ */
+ public static final int ERROR_INVALID_KEY_FORMAT = 27;
+
+ /**
+ * Failed because the provided certificate cannot be validated, e.g., is expired or has invalid
+ * signatures.
+ *
+ * <p>Note that this is different from {@link #ERROR_BAD_CERTIFICATE_FORMAT}, which denotes
+ * incorrect certificate formats, e.g., due to wrong encoding or structure.
+ *
+ * @hide
+ */
+ public static final int ERROR_INVALID_CERTIFICATE = 28;
private final ILockSettings mBinder;
private final KeyStore mKeyStore;
@@ -141,23 +163,9 @@
}
/**
- * Initializes key recovery service for the calling application. RecoveryController
- * randomly chooses one of the keys from the list and keeps it to use for future key export
- * operations. Collection of all keys in the list must be signed by the provided {@code
- * rootCertificateAlias}, which must also be present in the list of root certificates
- * preinstalled on the device. The random selection allows RecoveryController to select
- * which of a set of remote recovery service devices will be used.
- *
- * <p>In addition, RecoveryController enforces a delay of three months between
- * consecutive initialization attempts, to limit the ability of an attacker to often switch
- * remote recovery devices and significantly increase number of recovery attempts.
- *
- * @param rootCertificateAlias alias of a root certificate preinstalled on the device
- * @param signedPublicKeyList binary blob a list of X509 certificates and signature
- * @throws CertificateException if the {@code signedPublicKeyList} is in a bad format.
- * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
- * service.
+ * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public void initRecoveryService(
@NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
@@ -167,7 +175,54 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
+ throw new CertificateException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
+ }
+
+ /**
+ * Initializes the recovery service for the calling application. The detailed steps should be:
+ * <ol>
+ * <li>Parse {@code signatureFile} to get relevant information.
+ * <li>Validate the signer's X509 certificate, contained in {@code signatureFile}, against
+ * the root certificate pre-installed in the OS and chosen by {@code
+ * rootCertificateAlias}.
+ * <li>Verify the public-key signature, contained in {@code signatureFile}, and verify it
+ * against the entire {@code certificateFile}.
+ * <li>Parse {@code certificateFile} to get relevant information.
+ * <li>Check the serial number, contained in {@code certificateFile}, and skip the following
+ * steps if the serial number is not larger than the one previously stored.
+ * <li>Randomly choose a X509 certificate from the endpoint X509 certificates, contained in
+ * {@code certificateFile}, and validate it against the root certificate pre-installed
+ * in the OS and chosen by {@code rootCertificateAlias}.
+ * <li>Store the chosen X509 certificate and the serial in local database for later use.
+ * </ol>
+ *
+ * @param rootCertificateAlias the alias of a root certificate pre-installed in the OS
+ * @param certificateFile the binary content of the XML file containing a list of recovery
+ * service X509 certificates, and other metadata including the serial number
+ * @param signatureFile the binary content of the XML file containing the public-key signature
+ * of the entire certificate file, and a signer's X509 certificate
+ * @throws CertificateException if the given certificate files cannot be parsed or validated
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
+ */
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+ public void initRecoveryService(
+ @NonNull String rootCertificateAlias, @NonNull byte[] certificateFile,
+ @NonNull byte[] signatureFile)
+ throws CertificateException, InternalRecoveryServiceException {
+ try {
+ mBinder.initRecoveryServiceWithSigFile(
+ rootCertificateAlias, certificateFile, signatureFile);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw wrapUnexpectedServiceSpecificException(e);
@@ -176,7 +231,6 @@
/**
* @deprecated Use {@link #getKeyChainSnapshot()}
- * @removed
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -254,7 +308,6 @@
/**
* @deprecated Use {@link #getAliases()}.
- * @removed
*/
@Deprecated
public List<String> getAliases(@Nullable String packageName)
@@ -278,7 +331,6 @@
/**
* @deprecated Use {@link #setRecoveryStatus(String, int)}
- * @removed
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -313,7 +365,6 @@
/**
* @deprecated Use {@link #getRecoveryStatus(String)}.
- * @removed
*/
@Deprecated
public int getRecoveryStatus(String packageName, String alias)
@@ -461,9 +512,9 @@
}
}
+ // TODO: Unhide the following APIs, generateKey(), importKey(), and getKey()
/**
* @deprecated Use {@link #generateKey(String)}.
- * @removed
*/
@Deprecated
public Key generateKey(@NonNull String alias, byte[] account)
@@ -503,6 +554,40 @@
}
/**
+ * Imports a 256-bit recoverable AES key with the given {@code alias} and the raw bytes {@code
+ * keyBytes}.
+ *
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
+ * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
+ * screen is required to generate recoverable keys.
+ *
+ * @hide
+ */
+ public Key importKey(@NonNull String alias, byte[] keyBytes)
+ throws InternalRecoveryServiceException, LockScreenRequiredException {
+ try {
+ String grantAlias = mBinder.importKey(alias, keyBytes);
+ if (grantAlias == null) {
+ throw new InternalRecoveryServiceException("Null grant alias");
+ }
+ return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+ mKeyStore,
+ grantAlias,
+ KeyStore.UID_SELF);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (UnrecoverableKeyException e) {
+ throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ERROR_INSECURE_USER) {
+ throw new LockScreenRequiredException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
+ }
+
+ /**
* Gets a key called {@code alias} from the recoverable key store.
*
* @param alias The key alias.
diff --git a/core/java/android/security/keystore/recovery/RecoveryControllerException.java b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
index 2733aca..1af61ce 100644
--- a/core/java/android/security/keystore/recovery/RecoveryControllerException.java
+++ b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
@@ -19,10 +19,8 @@
import java.security.GeneralSecurityException;
/**
- * Base exception for errors thrown by {@link RecoveryController}.
- *
+ * @deprecated Not used.
* @hide
- * Deprecated
*/
public abstract class RecoveryControllerException extends GeneralSecurityException {
RecoveryControllerException() { }
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 069af91..137dd89 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -50,7 +50,7 @@
}
/**
- * A new session, started by {@code recoveryManager}.
+ * A new session, started by the {@link RecoveryController}.
*/
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
static RecoverySession newInstance(RecoveryController recoveryController) {
@@ -72,28 +72,7 @@
}
/**
- * Starts a recovery session and returns a blob with proof of recovery secret possession.
- * The method generates a symmetric key for a session, which trusted remote device can use to
- * return recovery key.
- *
- * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
- * used to create the recovery blob on the source device.
- * Keystore will verify the certificate using root of trust.
- * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
- * Used to limit number of guesses.
- * @param vaultChallenge Data passed from server for this recovery session and used to prevent
- * replay attacks
- * @param secrets Secrets provided by user, the method only uses type and secret fields.
- * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
- * encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
- * key and parameters necessary to identify the counter with the number of failed recovery
- * attempts.
- * @throws CertificateException if the {@code verifierPublicKey} is in an incorrect
- * format.
- * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
- * service.
* @deprecated Use {@link #start(CertPath, byte[], byte[], List)} instead.
- * @removed
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -115,7 +94,8 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
@@ -132,7 +112,7 @@
* @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
* Used to limit number of guesses.
* @param vaultChallenge Data passed from server for this recovery session and used to prevent
- * replay attacks
+ * replay attacks.
* @param secrets Secrets provided by user, the method only uses type and secret fields.
* @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
* encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
@@ -164,7 +144,8 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index df9766d..714e35a 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -61,7 +61,6 @@
/**
* @deprecated AOSP does not associate keys with accounts. This may be done by system app.
- * @removed
*/
@Deprecated
public Builder setAccount(@NonNull byte[] account) {
@@ -120,7 +119,6 @@
/**
* @deprecated AOSP does not associate keys with accounts. This may be done by system app.
- * @removed
*/
@Deprecated
public @NonNull byte[] getAccount() {
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 422e36b..eebd22a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -85,7 +85,10 @@
* or after {@link #onListenerDisconnected()}.
* </p>
* <p> Notification listeners cannot get notification access or be bound by the system on
- * {@link ActivityManager#isLowRamDevice() low ram} devices</p>
+ * {@linkplain ActivityManager#isLowRamDevice() low-RAM} devices. The system also ignores
+ * notification listeners running in a work profile. A
+ * {@link android.app.admin.DevicePolicyManager} might block notifications originating from a work
+ * profile.</p>
*/
public abstract class NotificationListenerService extends Service {
@@ -1217,6 +1220,7 @@
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(sbn.getNotification());
maybePopulateRemoteViews(sbn.getNotification());
+ maybePopulatePeople(sbn.getNotification());
} catch (IllegalArgumentException e) {
// warn and drop corrupt notification
Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index eba9129..94025ef 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -159,9 +159,9 @@
private static Locale sIs24HourLocale;
private static boolean sIs24Hour;
-
/**
- * Returns true if user preference is set to 24-hour format.
+ * Returns true if times should be formatted as 24 hour times, false if times should be
+ * formatted as 12 hour (AM/PM) times. Based on the user's chosen locale and other preferences.
* @param context the context to use for the content resolver
* @return true if 24 hour time format is selected, false otherwise.
*/
@@ -170,7 +170,8 @@
}
/**
- * Returns true if user preference with the given user handle is set to 24-hour format.
+ * Returns true if times should be formatted as 24 hour times, false if times should be
+ * formatted as 12 hour (AM/PM) times. Based on the user's chosen locale and other preferences.
* @param context the context to use for the content resolver
* @param userHandle the user handle of the user to query.
* @return true if 24 hour time format is selected, false otherwise.
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 1ead0b4..a5a7cbc 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -37,7 +37,6 @@
private static final Map<String, String> DEFAULT_FLAGS;
static {
DEFAULT_FLAGS = new HashMap<>();
- DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
DEFAULT_FLAGS.put("settings_battery_v2", "true");
DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java
index 402bef9..cc9991a 100644
--- a/core/java/android/util/LauncherIcons.java
+++ b/core/java/android/util/LauncherIcons.java
@@ -110,9 +110,9 @@
Drawable badgeColor = sysRes.getDrawable(
com.android.internal.R.drawable.ic_corp_icon_badge_color)
.getConstantState().newDrawable().mutate();
- badgeColor.setTint(backgroundColor);
Drawable badgeForeground = sysRes.getDrawable(foregroundRes);
+ badgeForeground.setTint(backgroundColor);
Drawable[] drawables = base == null
? new Drawable[] {badgeShadow, badgeColor, badgeForeground }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 4adcb8f..914ba0c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -185,13 +185,6 @@
*/
void setScreenCaptureDisabled(int userId, boolean disabled);
- /**
- * Testing and debugging infrastructure for writing surface events
- * to given FD. See RemoteSurfaceTrace.java or Wm.java for format.
- */
- void enableSurfaceTrace(in ParcelFileDescriptor fd);
- void disableSurfaceTrace();
-
// These can only be called with the SET_ORIENTATION permission.
/**
* Update the current screen rotation based on the current state of
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index fbba8ab..137e820 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -17,6 +17,7 @@
package android.view;
import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
@@ -25,6 +26,7 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -53,6 +55,10 @@
private ImageView mExpandButton;
private CachingIconView mIcon;
private View mProfileBadge;
+ private View mOverlayIcon;
+ private View mCameraIcon;
+ private View mMicIcon;
+ private View mAppOps;
private int mIconColor;
private int mOriginalNotificationColor;
private boolean mExpanded;
@@ -108,6 +114,10 @@
mExpandButton = findViewById(com.android.internal.R.id.expand_button);
mIcon = findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
+ mCameraIcon = findViewById(com.android.internal.R.id.camera);
+ mMicIcon = findViewById(com.android.internal.R.id.mic);
+ mOverlayIcon = findViewById(com.android.internal.R.id.overlay);
+ mAppOps = findViewById(com.android.internal.R.id.app_ops);
}
@Override
@@ -198,6 +208,11 @@
layoutRight = end - paddingEnd;
end = layoutLeft = layoutRight - child.getMeasuredWidth();
}
+ if (child == mAppOps) {
+ int paddingEnd = mContentEndMargin;
+ layoutRight = end - paddingEnd;
+ end = layoutLeft = layoutRight - child.getMeasuredWidth();
+ }
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
int ltrLeft = layoutLeft;
layoutLeft = getWidth() - layoutRight;
@@ -289,6 +304,22 @@
updateExpandButton();
}
+ /**
+ * Shows or hides 'app op in use' icons based on app usage.
+ */
+ public void showAppOpsIcons(ArraySet<Integer> appOps) {
+ if (mOverlayIcon == null || mCameraIcon == null || mMicIcon == null) {
+ return;
+ }
+
+ mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
+ ? View.VISIBLE : View.GONE);
+ mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA)
+ ? View.VISIBLE : View.GONE);
+ mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO)
+ ? View.VISIBLE : View.GONE);
+ }
+
private void updateExpandButton() {
int drawableId;
int contentDescriptionId;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index bd7f8e5..b7524fb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -152,6 +152,7 @@
private static native void nativeSeverChildren(long transactionObj, long nativeObject);
private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
int scalingMode);
+ private static native void nativeDestroy(long transactionObj, long nativeObject);
private static native IBinder nativeGetHandle(long nativeObject);
private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
@@ -763,18 +764,14 @@
}
public void deferTransactionUntil(IBinder handle, long frame) {
- if (frame > 0) {
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.deferTransactionUntil(this, handle, frame);
- }
+ synchronized(SurfaceControl.class) {
+ sGlobalTransaction.deferTransactionUntil(this, handle, frame);
}
}
public void deferTransactionUntil(Surface barrier, long frame) {
- if (frame > 0) {
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
- }
+ synchronized(SurfaceControl.class) {
+ sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
}
}
@@ -1479,6 +1476,9 @@
public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
long frameNumber) {
+ if (frameNumber < 0) {
+ return this;
+ }
sc.checkNotReleased();
nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber);
return this;
@@ -1486,6 +1486,9 @@
public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
long frameNumber) {
+ if (frameNumber < 0) {
+ return this;
+ }
sc.checkNotReleased();
nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
barrierSurface.mNativeObject, frameNumber);
@@ -1570,6 +1573,16 @@
return this;
}
+ /**
+ * Same as {@link #destroy()} except this is invoked in a transaction instead of
+ * immediately.
+ */
+ public Transaction destroy(SurfaceControl sc) {
+ sc.checkNotReleased();
+ nativeDestroy(mNativeObject, sc.mNativeObject);
+ return this;
+ }
+
public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 6da51d1..db19681 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -1008,10 +1008,8 @@
final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L;
mFrameInfo.setVsync(vsync, vsync);
mFrameInfo.addFlags(1 << 2 /* VSYNC */);
- // TODO: remove this fence
- nFence(mNativeProxy);
if (callback != null) {
- callback.onFrameDraw(mSurface.getNextFrameNumber());
+ nSetFrameCallback(mNativeProxy, callback);
}
nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length);
}
@@ -1184,6 +1182,7 @@
private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
private static native void nSetContentDrawBounds(long nativeProxy, int left,
int top, int right, int bottom);
+ private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index dc50fa1..d6c43e8 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -105,11 +105,13 @@
boolean hit = true;
boolean handled = false;
- switch (event.getAction()) {
+ switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mDelegateTargeted = mBounds.contains(x, y);
sendToDelegate = mDelegateTargeted;
break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
sendToDelegate = mDelegateTargeted;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f61b652..e285222 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2953,6 +2953,9 @@
* 1 PFLAG3_NO_REVEAL_ON_FOCUS
* 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
* 1 PFLAG3_SCREEN_READER_FOCUSABLE
+ * 1 PFLAG3_AGGREGATED_VISIBLE
+ * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET
+ * 1 available
* |-------|-------|-------|-------|
*/
@@ -3243,6 +3246,12 @@
*/
private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000;
+ /**
+ * Used to indicate that {@link #mAutofillId} was explicitly set through
+ * {@link #setAutofillId(AutofillId)}.
+ */
+ private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000;
+
/* End of masks for mPrivateFlags3 */
/**
@@ -8205,16 +8214,28 @@
* @throws IllegalArgumentException if the id is an autofill id associated with a virtual view.
*/
public void setAutofillId(@Nullable AutofillId id) {
+ // TODO(b/37566627): add unit / CTS test for all possible combinations below
if (android.view.autofill.Helper.sVerbose) {
Log.v(VIEW_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id);
}
if (isAttachedToWindow()) {
throw new IllegalStateException("Cannot set autofill id when view is attached");
}
- if (id.isVirtual()) {
+ if (id != null && id.isVirtual()) {
throw new IllegalStateException("Cannot set autofill id assigned to virtual views");
}
+ if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) {
+ // Ignore reset because it was never explicitly set before.
+ return;
+ }
mAutofillId = id;
+ if (id != null) {
+ mAutofillViewId = id.getViewId();
+ mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET;
+ } else {
+ mAutofillViewId = NO_ID;
+ mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET;
+ }
}
/**
@@ -18524,7 +18545,17 @@
// Hence prevent the same autofill view id from being restored multiple times.
((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID;
- mAutofillViewId = baseState.mAutofillViewId;
+ if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) {
+ // Ignore when view already set it through setAutofillId();
+ if (android.view.autofill.Helper.sDebug) {
+ Log.d(VIEW_LOG_TAG, "onRestoreInstanceState(): not setting autofillId to "
+ + baseState.mAutofillViewId + " because view explicitly set it to "
+ + mAutofillId);
+ }
+ } else {
+ mAutofillViewId = baseState.mAutofillViewId;
+ mAutofillId = null; // will be set on demand by getAutofillId()
+ }
}
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 01d9265..95e4abb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -95,6 +95,7 @@
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
+import android.view.autofill.AutofillManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
@@ -4781,6 +4782,21 @@
ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
}
+ if (action == MotionEvent.ACTION_DOWN && mView instanceof ViewGroup) {
+ // Upon motion event within app window, close autofill ui.
+ ViewGroup decorView = (ViewGroup) mView;
+ if (decorView.getChildCount() > 0) {
+ // We cannot use decorView's Context for querying AutofillManager: DecorView's
+ // context is based on Application Context, it would allocate a different
+ // AutofillManager instance.
+ AutofillManager afm = (AutofillManager) decorView.getChildAt(0).getContext()
+ .getSystemService(Context.AUTOFILL_MANAGER_SERVICE);
+ if (afm != null) {
+ afm.requestHideFillUi();
+ }
+ }
+ }
+
if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
mAttachInfo.mTooltipHost.hideTooltip();
}
@@ -6440,18 +6456,24 @@
params.backup();
mTranslator.translateWindowLayout(params);
}
+
if (params != null) {
if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
- }
- if (params != null && mOrigWindowType != params.type) {
- // For compatibility with old apps, don't crash here.
- if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- Slog.w(mTag, "Window type can not be changed after "
- + "the window is added; ignoring change of " + mView);
- params.type = mOrigWindowType;
+ if (mOrigWindowType != params.type) {
+ // For compatibility with old apps, don't crash here.
+ if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ Slog.w(mTag, "Window type can not be changed after "
+ + "the window is added; ignoring change of " + mView);
+ params.type = mOrigWindowType;
+ }
+ }
+
+ if (mSurface.isValid()) {
+ params.frameNumber = mSurface.getNextFrameNumber();
}
}
+
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c0a9666..2354f25 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2234,6 +2234,7 @@
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
* @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
* @see DisplayCutout
+ * @see android.R.attr#layoutInDisplayCutoutMode
*/
@LayoutInDisplayCutoutMode
public int layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
@@ -2371,6 +2372,13 @@
public long hideTimeoutMilliseconds = -1;
/**
+ * A frame number in which changes requested in this layout will be rendered.
+ *
+ * @hide
+ */
+ public long frameNumber = -1;
+
+ /**
* The color mode requested by this window. The target display may
* not be able to honor the request. When the color mode is not set
* to {@link ActivityInfo#COLOR_MODE_DEFAULT}, it might override the
@@ -2543,6 +2551,7 @@
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
out.writeInt(mColorMode);
out.writeLong(hideTimeoutMilliseconds);
+ out.writeLong(frameNumber);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -2599,6 +2608,7 @@
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mColorMode = in.readInt();
hideTimeoutMilliseconds = in.readLong();
+ frameNumber = in.readLong();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2799,6 +2809,10 @@
changes |= SURFACE_INSETS_CHANGED;
}
+ // The frame number changing is only relevant in the context of other
+ // changes, and so we don't need to track it with a flag.
+ frameNumber = o.frameNumber;
+
if (hasManualSurfaceInsets != o.hasManualSurfaceInsets) {
hasManualSurfaceInsets = o.hasManualSurfaceInsets;
changes |= SURFACE_INSETS_CHANGED;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a4261eb..1e562ea 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -358,6 +358,9 @@
@GuardedBy("mLock")
@Nullable private ArraySet<AutofillId> mFillableIds;
+ /** id of last requested autofill ui */
+ @Nullable private AutofillId mIdShownFillUi;
+
/**
* Views that were already "entered" - if they're entered again when the session is not active,
* they're ignored
@@ -1547,6 +1550,7 @@
mTrackedViews = null;
mFillableIds = null;
mSaveTriggerId = null;
+ mIdShownFillUi = null;
if (resetEnteredIds) {
mEnteredIds = null;
}
@@ -1676,8 +1680,9 @@
if (client != null) {
if (client.autofillClientRequestShowFillUi(anchor, width, height,
- anchorBounds, presenter) && mCallback != null) {
+ anchorBounds, presenter)) {
callback = mCallback;
+ mIdShownFillUi = id;
}
}
}
@@ -1944,10 +1949,23 @@
}
}
- private void requestHideFillUi(AutofillId id) {
- final View anchor = findView(id);
+ /** @hide */
+ public void requestHideFillUi() {
+ requestHideFillUi(mIdShownFillUi, true);
+ }
+
+ private void requestHideFillUi(AutofillId id, boolean force) {
+ final View anchor = id == null ? null : findView(id);
if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor);
if (anchor == null) {
+ if (force) {
+ // When user taps outside autofill window, force to close fill ui even id does
+ // not match.
+ AutofillClient client = getClient();
+ if (client != null) {
+ client.autofillClientRequestHideFillUi();
+ }
+ }
return;
}
requestHideFillUi(id, anchor);
@@ -1963,7 +1981,8 @@
// service being uninstalled and the UI being dismissed.
AutofillClient client = getClient();
if (client != null) {
- if (client.autofillClientRequestHideFillUi() && mCallback != null) {
+ if (client.autofillClientRequestHideFillUi()) {
+ mIdShownFillUi = null;
callback = mCallback;
}
}
@@ -2655,7 +2674,7 @@
public void requestHideFillUi(int sessionId, AutofillId id) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() -> afm.requestHideFillUi(id));
+ afm.post(() -> afm.requestHideFillUi(id, false));
}
}
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 1789edf..2b335fb 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -29,6 +29,8 @@
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
+import com.android.internal.util.Preconditions;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -40,13 +42,16 @@
private static final String LOG_TAG = "SystemTextClassifier";
private final ITextClassifierService mManagerService;
+ private final TextClassificationConstants mSettings;
private final TextClassifier mFallback;
private final String mPackageName;
- SystemTextClassifier(Context context) throws ServiceManager.ServiceNotFoundException {
+ SystemTextClassifier(Context context, TextClassificationConstants settings)
+ throws ServiceManager.ServiceNotFoundException {
mManagerService = ITextClassifierService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE));
- mFallback = new TextClassifierImpl(context);
+ mSettings = Preconditions.checkNotNull(settings);
+ mFallback = new TextClassifierImpl(context, settings);
mPackageName = context.getPackageName();
}
@@ -108,6 +113,11 @@
public TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
Utils.validate(text, false /* allowInMainThread */);
+
+ if (!mSettings.isSmartLinkifyEnabled()) {
+ return TextClassifier.NO_OP.generateLinks(text, options);
+ }
+
try {
if (options == null) {
options = new TextLinks.Options().setCallingPackageName(mPackageName);
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
similarity index 62%
rename from core/java/android/view/textclassifier/TextClassifierConstants.java
rename to core/java/android/view/textclassifier/TextClassificationConstants.java
index 397473b..21b5603 100644
--- a/core/java/android/view/textclassifier/TextClassifierConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -30,11 +30,17 @@
* This is encoded as a key=value list, separated by commas. Ex:
*
* <pre>
- * smart_selection_dark_launch (boolean)
- * smart_selection_enabled_for_edit_text (boolean)
+ * smart_linkify_enabled (boolean)
+ * system_textclassifier_enabled (boolean)
+ * model_dark_launch_enabled (boolean)
+ * smart_selection_enabled (boolean)
+ * smart_text_share_enabled (boolean)
+ * smart_linkify_enabled (boolean)
+ * smart_select_animation_enabled (boolean)
* suggest_selection_max_range_length (int)
* classify_text_max_range_length (int)
* generate_links_max_text_length (int)
+ * generate_links_log_sample_rate (int)
* entity_list_default (String[])
* entity_list_not_editable (String[])
* entity_list_editable (String[])
@@ -46,20 +52,28 @@
*
* Example of setting the values for testing.
* adb shell settings put global text_classifier_constants \
- * smart_selection_dark_launch=true,smart_selection_enabled_for_edit_text=true,\
+ * model_dark_launch_enabled=true,smart_selection_enabled=true,\
* entity_list_default=phone:address
* @hide
*/
-public final class TextClassifierConstants {
+public final class TextClassificationConstants {
- private static final String LOG_TAG = "TextClassifierConstants";
+ private static final String LOG_TAG = "TextClassificationConstants";
- private static final String SMART_SELECTION_DARK_LAUNCH =
- "smart_selection_dark_launch";
- private static final String SMART_SELECTION_ENABLED_FOR_EDIT_TEXT =
- "smart_selection_enabled_for_edit_text";
+ private static final String LOCAL_TEXT_CLASSIFIER_ENABLED =
+ "local_textclassifier_enabled";
+ private static final String SYSTEM_TEXT_CLASSIFIER_ENABLED =
+ "system_textclassifier_enabled";
+ private static final String MODEL_DARK_LAUNCH_ENABLED =
+ "model_dark_launch_enabled";
+ private static final String SMART_SELECTION_ENABLED =
+ "smart_selection_enabled";
+ private static final String SMART_TEXT_SHARE_ENABLED =
+ "smart_text_share_enabled";
private static final String SMART_LINKIFY_ENABLED =
"smart_linkify_enabled";
+ private static final String SMART_SELECT_ANIMATION_ENABLED =
+ "smart_select_animation_enabled";
private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
"suggest_selection_max_range_length";
private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH =
@@ -75,9 +89,13 @@
private static final String ENTITY_LIST_EDITABLE =
"entity_list_editable";
- private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
- private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
+ private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
+ private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
+ private static final boolean MODEL_DARK_LAUNCH_ENABLED_DEFAULT = false;
+ private static final boolean SMART_SELECTION_ENABLED_DEFAULT = true;
+ private static final boolean SMART_TEXT_SHARE_ENABLED_DEFAULT = true;
private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
+ private static final boolean SMART_SELECT_ANIMATION_ENABLED_DEFAULT = true;
private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
@@ -92,12 +110,13 @@
.add(TextClassifier.TYPE_DATE_TIME)
.add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
- /** Default settings. */
- static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
-
- private final boolean mDarkLaunch;
- private final boolean mSuggestSelectionEnabledForEditableText;
+ private final boolean mSystemTextClassifierEnabled;
+ private final boolean mLocalTextClassifierEnabled;
+ private final boolean mModelDarkLaunchEnabled;
+ private final boolean mSmartSelectionEnabled;
+ private final boolean mSmartTextShareEnabled;
private final boolean mSmartLinkifyEnabled;
+ private final boolean mSmartSelectionAnimationEnabled;
private final int mSuggestSelectionMaxRangeLength;
private final int mClassifyTextMaxRangeLength;
private final int mGenerateLinksMaxTextLength;
@@ -106,20 +125,7 @@
private final List<String> mEntityListNotEditable;
private final List<String> mEntityListEditable;
- private TextClassifierConstants() {
- mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
- mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
- mSmartLinkifyEnabled = SMART_LINKIFY_ENABLED_DEFAULT;
- mSuggestSelectionMaxRangeLength = SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT;
- mClassifyTextMaxRangeLength = CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT;
- mGenerateLinksMaxTextLength = GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT;
- mGenerateLinksLogSampleRate = GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT;
- mEntityListDefault = parseEntityList(ENTITY_LIST_DEFAULT_VALUE);
- mEntityListNotEditable = mEntityListDefault;
- mEntityListEditable = mEntityListDefault;
- }
-
- private TextClassifierConstants(@Nullable String settings) {
+ private TextClassificationConstants(@Nullable String settings) {
final KeyValueListParser parser = new KeyValueListParser(',');
try {
parser.setString(settings);
@@ -127,15 +133,27 @@
// Failed to parse the settings string, log this and move on with defaults.
Slog.e(LOG_TAG, "Bad TextClassifier settings: " + settings);
}
- mDarkLaunch = parser.getBoolean(
- SMART_SELECTION_DARK_LAUNCH,
- SMART_SELECTION_DARK_LAUNCH_DEFAULT);
- mSuggestSelectionEnabledForEditableText = parser.getBoolean(
- SMART_SELECTION_ENABLED_FOR_EDIT_TEXT,
- SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT);
+ mSystemTextClassifierEnabled = parser.getBoolean(
+ SYSTEM_TEXT_CLASSIFIER_ENABLED,
+ SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT);
+ mLocalTextClassifierEnabled = parser.getBoolean(
+ LOCAL_TEXT_CLASSIFIER_ENABLED,
+ LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT);
+ mModelDarkLaunchEnabled = parser.getBoolean(
+ MODEL_DARK_LAUNCH_ENABLED,
+ MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
+ mSmartSelectionEnabled = parser.getBoolean(
+ SMART_SELECTION_ENABLED,
+ SMART_SELECTION_ENABLED_DEFAULT);
+ mSmartTextShareEnabled = parser.getBoolean(
+ SMART_TEXT_SHARE_ENABLED,
+ SMART_TEXT_SHARE_ENABLED_DEFAULT);
mSmartLinkifyEnabled = parser.getBoolean(
SMART_LINKIFY_ENABLED,
SMART_LINKIFY_ENABLED_DEFAULT);
+ mSmartSelectionAnimationEnabled = parser.getBoolean(
+ SMART_SELECT_ANIMATION_ENABLED,
+ SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
mSuggestSelectionMaxRangeLength = parser.getInt(
SUGGEST_SELECTION_MAX_RANGE_LENGTH,
SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
@@ -160,22 +178,38 @@
}
/** Load from a settings string. */
- public static TextClassifierConstants loadFromString(String settings) {
- return new TextClassifierConstants(settings);
+ public static TextClassificationConstants loadFromString(String settings) {
+ return new TextClassificationConstants(settings);
}
- public boolean isDarkLaunch() {
- return mDarkLaunch;
+ public boolean isLocalTextClassifierEnabled() {
+ return mLocalTextClassifierEnabled;
}
- public boolean isSuggestSelectionEnabledForEditableText() {
- return mSuggestSelectionEnabledForEditableText;
+ public boolean isSystemTextClassifierEnabled() {
+ return mSystemTextClassifierEnabled;
+ }
+
+ public boolean isModelDarkLaunchEnabled() {
+ return mModelDarkLaunchEnabled;
+ }
+
+ public boolean isSmartSelectionEnabled() {
+ return mSmartSelectionEnabled;
+ }
+
+ public boolean isSmartTextShareEnabled() {
+ return mSmartTextShareEnabled;
}
public boolean isSmartLinkifyEnabled() {
return mSmartLinkifyEnabled;
}
+ public boolean isSmartSelectionAnimationEnabled() {
+ return mSmartSelectionAnimationEnabled;
+ }
+
public int getSuggestSelectionMaxRangeLength() {
return mSuggestSelectionMaxRangeLength;
}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 300aef2..a7f1ca1 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -20,8 +20,11 @@
import android.annotation.SystemService;
import android.content.Context;
import android.os.ServiceManager;
+import android.provider.Settings;
import android.service.textclassifier.TextClassifierService;
+import android.view.textclassifier.TextClassifier.TextClassifierType;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
/**
@@ -30,55 +33,41 @@
@SystemService(Context.TEXT_CLASSIFICATION_SERVICE)
public final class TextClassificationManager {
- // TODO: Make this a configurable flag.
- private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED = true;
-
private static final String LOG_TAG = "TextClassificationManager";
private final Object mLock = new Object();
private final Context mContext;
+ private final TextClassificationConstants mSettings;
+
+ @GuardedBy("mLock")
private TextClassifier mTextClassifier;
+ @GuardedBy("mLock")
+ private TextClassifier mLocalTextClassifier;
+ @GuardedBy("mLock")
private TextClassifier mSystemTextClassifier;
/** @hide */
public TextClassificationManager(Context context) {
mContext = Preconditions.checkNotNull(context);
+ mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
+ context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
}
/**
- * Returns the system's default TextClassifier.
- * @hide
- */
- // TODO: Unhide when this is ready.
- public TextClassifier getSystemDefaultTextClassifier() {
- synchronized (mLock) {
- if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) {
- try {
- Log.d(LOG_TAG, "Initialized SystemTextClassifier");
- mSystemTextClassifier = new SystemTextClassifier(mContext);
- } catch (ServiceManager.ServiceNotFoundException e) {
- Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e);
- }
- }
- if (mSystemTextClassifier == null) {
- Log.d(LOG_TAG, "Using an in-process TextClassifier as the system default");
- mSystemTextClassifier = new TextClassifierImpl(mContext);
- }
- }
- return mSystemTextClassifier;
- }
-
- /**
- * Returns the text classifier.
+ * Returns the text classifier that was set via {@link #setTextClassifier(TextClassifier)}.
+ * If this is null, this method returns a default text classifier (i.e. either the system text
+ * classifier if one exists, or a local text classifier running in this app.)
+ *
+ * @see #setTextClassifier(TextClassifier)
*/
public TextClassifier getTextClassifier() {
synchronized (mLock) {
if (mTextClassifier == null) {
if (isSystemTextClassifierEnabled()) {
- mTextClassifier = getSystemDefaultTextClassifier();
+ mTextClassifier = getSystemTextClassifier();
} else {
- mTextClassifier = new TextClassifierImpl(mContext);
+ mTextClassifier = getLocalTextClassifier();
}
}
return mTextClassifier;
@@ -96,8 +85,75 @@
}
}
+ /**
+ * Returns a specific type of text classifier.
+ * If the specified text classifier cannot be found, this returns {@link TextClassifier#NO_OP}.
+ *
+ * @see TextClassifier#LOCAL
+ * @see TextClassifier#SYSTEM
+ * @hide
+ */
+ // TODO: Expose as system API.
+ public TextClassifier getTextClassifier(@TextClassifierType int type) {
+ switch (type) {
+ case TextClassifier.LOCAL:
+ return getLocalTextClassifier();
+ default:
+ return getSystemTextClassifier();
+ }
+ }
+
+ /** @hide */
+ public TextClassificationConstants getSettings() {
+ return mSettings;
+ }
+
+ private TextClassifier getSystemTextClassifier() {
+ synchronized (mLock) {
+ if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) {
+ try {
+ mSystemTextClassifier = new SystemTextClassifier(mContext, mSettings);
+ Log.d(LOG_TAG, "Initialized SystemTextClassifier");
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e);
+ }
+ }
+ }
+ if (mSystemTextClassifier != null) {
+ return mSystemTextClassifier;
+ }
+ return TextClassifier.NO_OP;
+ }
+
+ private TextClassifier getLocalTextClassifier() {
+ synchronized (mLock) {
+ if (mLocalTextClassifier == null) {
+ if (mSettings.isLocalTextClassifierEnabled()) {
+ mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings);
+ } else {
+ Log.d(LOG_TAG, "Local TextClassifier disabled");
+ mLocalTextClassifier = TextClassifierImpl.NO_OP;
+ }
+ }
+ return mLocalTextClassifier;
+ }
+ }
+
private boolean isSystemTextClassifierEnabled() {
- return SYSTEM_TEXT_CLASSIFIER_ENABLED
+ return mSettings.isSystemTextClassifierEnabled()
&& TextClassifierService.getServiceComponentName(mContext) != null;
}
+
+ /** @hide */
+ public static TextClassificationConstants getSettings(Context context) {
+ Preconditions.checkNotNull(context);
+ final TextClassificationManager tcm =
+ context.getSystemService(TextClassificationManager.class);
+ if (tcm != null) {
+ return tcm.mSettings;
+ } else {
+ return TextClassificationConstants.loadFromString(Settings.Global.getString(
+ context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index d52a30b..ec40fdd 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -16,6 +16,7 @@
package android.view.textclassifier;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -49,6 +50,16 @@
/** @hide */
String DEFAULT_LOG_TAG = "androidtc";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {LOCAL, SYSTEM})
+ @interface TextClassifierType {} // TODO: Expose as system APIs.
+ /** Specifies a TextClassifier that runs locally in the app's process. @hide */
+ int LOCAL = 0;
+ /** Specifies a TextClassifier that runs in the system process and serves all apps. @hide */
+ int SYSTEM = 1;
+
/** The TextClassifier failed to run. */
String TYPE_UNKNOWN = "";
/** The classifier ran, but didn't recognize a known entity. */
@@ -329,14 +340,6 @@
}
/**
- * Returns this TextClassifier's settings.
- * @hide
- */
- default TextClassifierConstants getSettings() {
- return TextClassifierConstants.DEFAULT;
- }
-
- /**
* Configuration object for specifying what entities to identify.
*
* Configs are initially based on a predefined preset, and can be modified from there.
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 5b7095b..41f1c69 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -34,7 +34,6 @@
import android.provider.Browser;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
-import android.provider.Settings;
import android.view.textclassifier.logging.DefaultLogger;
import android.view.textclassifier.logging.GenerateLinksLogger;
import android.view.textclassifier.logging.Logger;
@@ -99,13 +98,13 @@
@GuardedBy("mLoggerLock") // Do not access outside this lock.
private Logger mLogger; // Should never be null if mLoggerConfig.get() is not null.
- private TextClassifierConstants mSettings;
+ private final TextClassificationConstants mSettings;
- public TextClassifierImpl(Context context) {
+ public TextClassifierImpl(Context context, TextClassificationConstants settings) {
mContext = Preconditions.checkNotNull(context);
mFallback = TextClassifier.NO_OP;
- mGenerateLinksLogger = new GenerateLinksLogger(
- getSettings().getGenerateLinksLogSampleRate());
+ mSettings = Preconditions.checkNotNull(settings);
+ mGenerateLinksLogger = new GenerateLinksLogger(mSettings.getGenerateLinksLogSampleRate());
}
/** @inheritDoc */
@@ -117,7 +116,7 @@
try {
final int rangeLength = selectionEndIndex - selectionStartIndex;
if (text.length() > 0
- && rangeLength <= getSettings().getSuggestSelectionMaxRangeLength()) {
+ && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final String localesString = concatenateLocales(locales);
final Calendar refTime = Calendar.getInstance();
@@ -126,7 +125,7 @@
final String string = text.toString();
final int start;
final int end;
- if (getSettings().isDarkLaunch() && !darkLaunchAllowed) {
+ if (mSettings.isModelDarkLaunchEnabled() && !darkLaunchAllowed) {
start = selectionStartIndex;
end = selectionEndIndex;
} else {
@@ -179,7 +178,7 @@
Utils.validate(text, startIndex, endIndex, false /* allowInMainThread */);
try {
final int rangeLength = endIndex - startIndex;
- if (text.length() > 0 && rangeLength <= getSettings().getClassifyTextMaxRangeLength()) {
+ if (text.length() > 0 && rangeLength <= mSettings.getClassifyTextMaxRangeLength()) {
final String string = text.toString();
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final String localesString = concatenateLocales(locales);
@@ -214,7 +213,7 @@
final String textString = text.toString();
final TextLinks.Builder builder = new TextLinks.Builder(textString);
- if (!getSettings().isSmartLinkifyEnabled()) {
+ if (!mSettings.isSmartLinkifyEnabled()) {
return builder.build();
}
@@ -226,7 +225,7 @@
options != null && options.getEntityConfig() != null
? options.getEntityConfig().resolveEntityListModifications(
getEntitiesForHints(options.getEntityConfig().getHints()))
- : getSettings().getEntityListDefault();
+ : mSettings.getEntityListDefault();
final TextClassifierImplNative nativeImpl =
getNative(defaultLocales);
final TextClassifierImplNative.AnnotatedSpan[] annotations =
@@ -268,7 +267,7 @@
/** @inheritDoc */
@Override
public int getMaxGenerateLinksTextLength() {
- return getSettings().getGenerateLinksMaxTextLength();
+ return mSettings.getGenerateLinksMaxTextLength();
}
private Collection<String> getEntitiesForHints(Collection<String> hints) {
@@ -278,11 +277,11 @@
// Use the default if there is no hint, or conflicting ones.
final boolean useDefault = editable == notEditable;
if (useDefault) {
- return getSettings().getEntityListDefault();
+ return mSettings.getEntityListDefault();
} else if (editable) {
- return getSettings().getEntityListEditable();
+ return mSettings.getEntityListEditable();
} else { // notEditable
- return getSettings().getEntityListNotEditable();
+ return mSettings.getEntityListNotEditable();
}
}
@@ -298,16 +297,6 @@
}
}
- /** @hide */
- @Override
- public TextClassifierConstants getSettings() {
- if (mSettings == null) {
- mSettings = TextClassifierConstants.loadFromString(Settings.Global.getString(
- mContext.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
- }
- return mSettings;
- }
-
private TextClassifierImplNative getNative(LocaleList localeList)
throws FileNotFoundException {
synchronized (mLock) {
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 84c000a..ed122a6 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -39,7 +39,7 @@
// "file:///android_res/drawable/bar.png". Use "drawable" to refer to
// "drawable-hdpi" directory as well.
static final String RESOURCE_BASE = "file:///android_res/";
- static final String FILE_BASE = "file://";
+ static final String FILE_BASE = "file:";
static final String PROXY_BASE = "file:///cookieless_proxy/";
static final String CONTENT_BASE = "content:";
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a8f6b03..fadc3dc 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1683,7 +1683,7 @@
* @param callback will be called on the UI thread with {@code true} if initialization is
* successful, {@code false} otherwise.
*/
- public static void startSafeBrowsing(Context context,
+ public static void startSafeBrowsing(@NonNull Context context,
@Nullable ValueCallback<Boolean> callback) {
getFactory().getStatics().initSafeBrowsing(context, callback);
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index e9fe481..e0ccda9 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -205,25 +205,21 @@
}
PackageManager packageManager = AppGlobals.getInitialApplication().getPackageManager();
- PackageInfo packageInfo;
+ String libraryFileName;
try {
- packageInfo = packageManager.getPackageInfo(packageName,
+ PackageInfo packageInfo = packageManager.getPackageInfo(packageName,
PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
+ libraryFileName = getWebViewLibrary(packageInfo.applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOGTAG, "Couldn't find package " + packageName);
return LIBLOAD_WRONG_PACKAGE_NAME;
}
- try {
- int loadNativeRet = WebViewLibraryLoader.loadNativeLibrary(clazzLoader, packageInfo);
- // If we failed waiting for relro we want to return that fact even if we successfully
- // load the relro file.
- if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
- return loadNativeRet;
- } catch (MissingWebViewPackageException e) {
- Log.e(LOGTAG, "Couldn't load native library: " + e);
- return LIBLOAD_FAILED_TO_LOAD_LIBRARY;
- }
+ int loadNativeRet = WebViewLibraryLoader.loadNativeLibrary(clazzLoader, libraryFileName);
+ // If we failed waiting for relro we want to return that fact even if we successfully
+ // load the relro file.
+ if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
+ return loadNativeRet;
}
static WebViewFactoryProvider getProvider() {
@@ -454,7 +450,8 @@
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
- WebViewLibraryLoader.loadNativeLibrary(clazzLoader, sPackageInfo);
+ WebViewLibraryLoader.loadNativeLibrary(clazzLoader,
+ getWebViewLibrary(sPackageInfo.applicationInfo));
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index eb2b6bc..cabba06 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -234,17 +234,14 @@
* <p class="note"><b>Note:</b> Assumes that we have waited for relro creation.
*
* @param clazzLoader class loader used to find the linker namespace to load the library into.
- * @param packageInfo the package from which WebView is loaded.
+ * @param libraryFileName the filename of the library to load.
*/
- static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo)
- throws WebViewFactory.MissingWebViewPackageException {
+ public static int loadNativeLibrary(ClassLoader clazzLoader, String libraryFileName) {
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
return WebViewFactory.LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
}
- final String libraryFileName =
- WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo);
String relroPath = VMRuntime.getRuntime().is64Bit() ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 :
CHROMIUM_WEBVIEW_NATIVE_RELRO_32;
int result = nativeLoadWithRelroFile(libraryFileName, relroPath, clazzLoader);
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 63fbef3..07593a5 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -93,13 +93,11 @@
synchronized (sLock) {
sMultiprocessEnabled = enabled;
- // When toggling between multi-process being on/off, start or stop the
- // zygote. If it is enabled and the zygote is not yet started, launch it.
- // Otherwise, kill it. The name may be null if the package information has
- // not yet been resolved.
- if (enabled) {
- connectToZygoteIfNeededLocked();
- } else {
+ // When multi-process is disabled, kill the zygote. When it is enabled,
+ // the zygote is not explicitly started here to avoid waiting on the
+ // zygote launch at boot. Instead, the zygote will be started when it is
+ // first needed in getProcess().
+ if (!enabled) {
stopZygoteLocked();
}
}
@@ -169,6 +167,8 @@
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
+ String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo);
+
// In the case where the ApplicationInfo has been modified by the stub WebView,
// we need to use the original ApplicationInfo to determine what the original classpath
// would have been to use as a cache key.
@@ -179,7 +179,7 @@
ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
- sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
+ sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey,
Build.SUPPORTED_ABIS[0]);
} catch (Exception e) {
Log.e(LOGTAG, "Error connecting to webview zygote", e);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 2e7b2fd..02f35ca 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -107,6 +107,7 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextLinks;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView.Drawables;
@@ -4024,7 +4025,7 @@
private void updateAssistMenuItems(Menu menu) {
clearAssistMenuItems(menu);
- if (!mTextView.isDeviceProvisioned()) {
+ if (!shouldEnableAssistMenuItems()) {
return;
}
final TextClassification textClassification =
@@ -4097,7 +4098,7 @@
final TextClassification textClassification =
getSelectionActionModeHelper().getTextClassification();
- if (!mTextView.isDeviceProvisioned() || textClassification == null) {
+ if (!shouldEnableAssistMenuItems() || textClassification == null) {
// No textClassification result to handle the click. Eat the click.
return true;
}
@@ -4118,6 +4119,12 @@
return true;
}
+ private boolean shouldEnableAssistMenuItems() {
+ return mTextView.isDeviceProvisioned()
+ && TextClassificationManager.getSettings(mTextView.getContext())
+ .isSmartTextShareEnabled();
+ }
+
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
getSelectionActionModeHelper().onSelectionAction(item.getItemId());
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index eb2af60..85f68d7 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -319,6 +320,10 @@
* producing a shakiness effect for the magnifier content.
*/
private static class InternalPopupWindow {
+ // The alpha set on the magnifier's content, which defines how
+ // prominent the white background is.
+ private static final int CONTENT_BITMAP_ALPHA = 242;
+
// Display associated to the view the magnifier is attached to.
private final Display mDisplay;
// The size of the content of the magnifier.
@@ -483,12 +488,12 @@
* Destroys this instance.
*/
public void destroy() {
- mRenderer.destroy();
- mSurface.destroy();
- mSurfaceControl.destroy();
- mSurfaceSession.kill();
- mBitmapRenderNode.destroy();
synchronized (mLock) {
+ mRenderer.destroy();
+ mSurface.destroy();
+ mSurfaceControl.destroy();
+ mSurfaceSession.kill();
+ mBitmapRenderNode.destroy();
mHandler.removeCallbacks(mMagnifierUpdater);
if (mBitmap != null) {
mBitmap.recycle();
@@ -511,10 +516,13 @@
final DisplayListCanvas canvas =
mBitmapRenderNode.start(mContentWidth, mContentHeight);
try {
+ canvas.drawColor(Color.WHITE);
+
final Rect srcRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
final Rect dstRect = new Rect(0, 0, mContentWidth, mContentHeight);
final Paint paint = new Paint();
paint.setFilterBitmap(true);
+ paint.setAlpha(CONTENT_BITMAP_ALPHA);
canvas.drawBitmap(mBitmap, srcRect, dstRect, paint);
} finally {
mBitmapRenderNode.end(canvas);
@@ -530,17 +538,22 @@
final int pendingY = mWindowPositionY;
callback = frame -> {
- mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
- // Show or move the window at the content draw frame.
- SurfaceControl.openTransaction();
- mSurfaceControl.deferTransactionUntil(mSurface, frame);
- if (updateWindowPosition) {
- mSurfaceControl.setPosition(pendingX, pendingY);
+ synchronized (mLock) {
+ if (!mSurface.isValid()) {
+ return;
+ }
+ mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
+ // Show or move the window at the content draw frame.
+ SurfaceControl.openTransaction();
+ mSurfaceControl.deferTransactionUntil(mSurface, frame);
+ if (updateWindowPosition) {
+ mSurfaceControl.setPosition(pendingX, pendingY);
+ }
+ if (firstDraw) {
+ mSurfaceControl.show();
+ }
+ SurfaceControl.closeTransaction();
}
- if (firstDraw) {
- mSurfaceControl.show();
- }
- SurfaceControl.closeTransaction();
};
} else {
callback = null;
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index 7d556bf..4fb303e 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -20,15 +20,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.media.SessionToken2;
import android.media.session.MediaController;
import android.media.update.ApiLoader;
import android.media.update.MediaControlView2Provider;
import android.media.update.ViewGroupHelper;
import android.util.AttributeSet;
+import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+// TODO: Use link annotation to refer VideoView2 once VideoView2 became unhidden.
/**
* A View that contains the controls for MediaPlayer2.
* It provides a wide range of UI including buttons such as "Play/Pause", "Rewind", "Fast Forward",
@@ -55,10 +58,7 @@
* <p>
* It is also possible to add custom buttons with custom icons and actions inside MediaControlView2.
* Those buttons will be shown when the overflow button is clicked.
- * See {@link VideoView2#setCustomActions} for more details on how to add.
- *
- * TODO PUBLIC API
- * @hide
+ * See VideoView2#setCustomActions for more details on how to add.
*/
public class MediaControlView2 extends ViewGroupHelper<MediaControlView2Provider> {
/** @hide */
@@ -80,62 +80,75 @@
/**
* MediaControlView2 button value for playing and pausing media.
+ * @hide
*/
public static final int BUTTON_PLAY_PAUSE = 1;
/**
* MediaControlView2 button value for jumping 30 seconds forward.
+ * @hide
*/
public static final int BUTTON_FFWD = 2;
/**
* MediaControlView2 button value for jumping 10 seconds backward.
+ * @hide
*/
public static final int BUTTON_REW = 3;
/**
* MediaControlView2 button value for jumping to next media.
+ * @hide
*/
public static final int BUTTON_NEXT = 4;
/**
* MediaControlView2 button value for jumping to previous media.
+ * @hide
*/
public static final int BUTTON_PREV = 5;
/**
* MediaControlView2 button value for showing/hiding subtitle track.
+ * @hide
*/
public static final int BUTTON_SUBTITLE = 6;
/**
* MediaControlView2 button value for toggling full screen.
+ * @hide
*/
public static final int BUTTON_FULL_SCREEN = 7;
/**
* MediaControlView2 button value for showing/hiding overflow buttons.
+ * @hide
*/
public static final int BUTTON_OVERFLOW = 8;
/**
* MediaControlView2 button value for muting audio.
+ * @hide
*/
public static final int BUTTON_MUTE = 9;
/**
* MediaControlView2 button value for adjusting aspect ratio of view.
+ * @hide
*/
public static final int BUTTON_ASPECT_RATIO = 10;
/**
* MediaControlView2 button value for showing/hiding settings page.
+ * @hide
*/
public static final int BUTTON_SETTINGS = 11;
/**
* String for receiving command to show subtitle from MediaSession. Can be checked by
* implementing {@link android.media.session.MediaSession.Callback#onCommand}
+ * @hide
*/
public static final String COMMAND_SHOW_SUBTITLE = "showSubtitle";
/**
* String for receiving command to hide subtitle from MediaSession. Can be checked by
* implementing {@link android.media.session.MediaSession.Callback#onCommand}
+ * @hide
*/
public static final String COMMAND_HIDE_SUBTITLE = "hideSubtitle";
+
/**
- * String for receiving command to set fullscreen from MediaSession. Can be checked by
- * implementing {@link android.media.session.MediaSession.Callback#onCommand}
+ * @hide TODO: remove once the implementation is revised
*/
public static final String COMMAND_SET_FULLSCREEN = "setFullscreen";
@@ -163,10 +176,24 @@
}
/**
- * Sets MediaController instance to control corresponding MediaSession.
+ * Sets MediaSession2 token to control corresponding MediaSession2.
+ */
+ public void setMediaSessionToken(SessionToken2 token) {
+ mProvider.setMediaSessionToken_impl(token);
+ }
+
+ /**
+ * Registers a callback to be invoked when the fullscreen mode should be changed.
+ * @param l The callback that will be run
+ */
+ public void setOnFullScreenListener(OnFullScreenListener l) {
+ mProvider.setOnFullScreenListener_impl(l);
+ }
+
+ /**
+ * @hide TODO: remove once the implementation is revised
*/
public void setController(MediaController controller) {
- mProvider.setController_impl(controller);
}
/**
@@ -187,6 +214,7 @@
* <li>{@link #BUTTON_SETTINGS}
* </ul>
* @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
+ * @hide
*/
public void setButtonVisibility(@Button int button, @Visibility int visibility) {
mProvider.setButtonVisibility_impl(button, visibility);
@@ -203,4 +231,15 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mProvider.onLayout_impl(changed, l, t, r, b);
}
+
+ /**
+ * Interface definition of a callback to be invoked to inform the fullscreen mode is changed.
+ * Application should handle the fullscreen mode accordingly.
+ */
+ public interface OnFullScreenListener {
+ /**
+ * Called to indicate a fullscreen mode change.
+ */
+ void onFullScreen(View view, boolean fullScreen);
+ }
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 6ab09d6..12ab0ee 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -34,6 +34,8 @@
import android.util.Log;
import android.view.ActionMode;
import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationConstants;
+import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
@@ -65,12 +67,10 @@
private static final String LOG_TAG = "SelectActionModeHelper";
- // TODO: Make this a configurable flag.
- private static final boolean SMART_SELECT_ANIMATION_ENABLED = true;
-
private final Editor mEditor;
private final TextView mTextView;
private final TextClassificationHelper mTextClassificationHelper;
+ private final TextClassificationConstants mTextClassificationSettings;
private TextClassification mTextClassification;
private AsyncTask mTextClassificationAsyncTask;
@@ -84,6 +84,7 @@
SelectionActionModeHelper(@NonNull Editor editor) {
mEditor = Preconditions.checkNotNull(editor);
mTextView = mEditor.getTextView();
+ mTextClassificationSettings = TextClassificationManager.getSettings(mTextView.getContext());
mTextClassificationHelper = new TextClassificationHelper(
mTextView.getContext(),
mTextView.getTextClassifier(),
@@ -91,7 +92,7 @@
0, 1, mTextView.getTextLocales());
mSelectionTracker = new SelectionTracker(mTextView);
- if (SMART_SELECT_ANIMATION_ENABLED) {
+ if (mTextClassificationSettings.isSmartSelectionAnimationEnabled()) {
mSmartSelectSprite = new SmartSelectSprite(mTextView.getContext(),
editor.getTextView().mHighlightColor, mTextView::invalidate);
} else {
@@ -104,9 +105,7 @@
*/
public void startSelectionActionModeAsync(boolean adjustSelection) {
// Check if the smart selection should run for editable text.
- adjustSelection &= !mTextView.isTextEditable()
- || mTextView.getTextClassifier().getSettings()
- .isSuggestSelectionEnabledForEditableText();
+ adjustSelection &= mTextClassificationSettings.isSmartSelectionEnabled();
mSelectionTracker.onOriginalSelection(
getText(mTextView),
@@ -249,7 +248,7 @@
|| mTextView.isTextEditable()
|| actionMode == Editor.TextActionMode.TEXT_LINK)) {
// Do not change the selection if TextClassifier should be dark launched.
- if (!mTextView.getTextClassifier().getSettings().isDarkLaunch()) {
+ if (!mTextClassificationSettings.isModelDarkLaunchEnabled()) {
Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
mTextView.invalidate();
}
@@ -450,7 +449,6 @@
selectionEnd = mTextView.getSelectionEnd();
}
mTextClassificationHelper.init(
- mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
selectionStart, selectionEnd,
@@ -882,7 +880,8 @@
private static final int TRIM_DELTA = 120; // characters
- private Context mContext;
+ private final Context mContext;
+ private final boolean mDarkLaunchEnabled;
private TextClassifier mTextClassifier;
/** The original TextView text. **/
@@ -917,13 +916,15 @@
TextClassificationHelper(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
- init(context, textClassifier, text, selectionStart, selectionEnd, locales);
+ init(textClassifier, text, selectionStart, selectionEnd, locales);
+ mContext = Preconditions.checkNotNull(context);
+ mDarkLaunchEnabled = TextClassificationManager.getSettings(mContext)
+ .isModelDarkLaunchEnabled();
}
@UiThread
- public void init(Context context, TextClassifier textClassifier,
- CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
- mContext = Preconditions.checkNotNull(context);
+ public void init(TextClassifier textClassifier, CharSequence text,
+ int selectionStart, int selectionEnd, LocaleList locales) {
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
mLastClassificationText = null; // invalidate.
@@ -956,7 +957,7 @@
mSelectionOptions.getDefaultLocales());
}
// Do not classify new selection boundaries if TextClassifier should be dark launched.
- if (!mTextClassifier.getSettings().isDarkLaunch()) {
+ if (!mDarkLaunchEnabled) {
mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
mSelectionEnd = Math.min(
mText.length(), selection.getSelectionEndIndex() + mTrimStart);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2cfdb76..50e6393 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -319,6 +319,11 @@
// Enum for the "typeface" XML parameter.
// TODO: How can we get this from the XML instead of hardcoding it here?
+ /** @hide */
+ @IntDef(value = {DEFAULT_TYPEFACE, SANS, SERIF, MONOSPACE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface XMLTypefaceAttr{}
+ private static final int DEFAULT_TYPEFACE = -1;
private static final int SANS = 1;
private static final int SERIF = 2;
private static final int MONOSPACE = 3;
@@ -1976,33 +1981,52 @@
}
}
- private void setTypefaceFromAttrs(Typeface fontTypeface, String familyName, int typefaceIndex,
- int styleIndex) {
- Typeface tf = fontTypeface;
- if (tf == null && familyName != null) {
- tf = Typeface.create(familyName, styleIndex);
- } else if (tf != null && tf.getStyle() != styleIndex) {
- tf = Typeface.create(tf, styleIndex);
+ /**
+ * Sets the Typeface taking into account the given attributes.
+ *
+ * @param typeface a typeface
+ * @param familyName family name string, e.g. "serif"
+ * @param typefaceIndex an index of the typeface enum, e.g. SANS, SERIF.
+ * @param style a typeface style
+ * @param weight a weight value for the Typeface or -1 if not specified.
+ */
+ private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName,
+ @XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style,
+ @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
+ if (typeface == null && familyName != null) {
+ // Lookup normal Typeface from system font map.
+ final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL);
+ resolveStyleAndSetTypeface(normalTypeface, style, weight);
+ } else if (typeface != null) {
+ resolveStyleAndSetTypeface(typeface, style, weight);
+ } else { // both typeface and familyName is null.
+ switch (typefaceIndex) {
+ case SANS:
+ resolveStyleAndSetTypeface(Typeface.SANS_SERIF, style, weight);
+ break;
+ case SERIF:
+ resolveStyleAndSetTypeface(Typeface.SERIF, style, weight);
+ break;
+ case MONOSPACE:
+ resolveStyleAndSetTypeface(Typeface.MONOSPACE, style, weight);
+ break;
+ case DEFAULT_TYPEFACE:
+ default:
+ resolveStyleAndSetTypeface(null, style, weight);
+ break;
+ }
}
- if (tf != null) {
- setTypeface(tf);
- return;
+ }
+
+ private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style,
+ @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
+ if (weight >= 0) {
+ weight = Math.min(Typeface.MAX_WEIGHT, weight);
+ final boolean italic = (style & Typeface.ITALIC) != 0;
+ setTypeface(Typeface.create(typeface, weight, italic));
+ } else {
+ setTypeface(Typeface.create(typeface, style));
}
- switch (typefaceIndex) {
- case SANS:
- tf = Typeface.SANS_SERIF;
- break;
-
- case SERIF:
- tf = Typeface.SERIF;
- break;
-
- case MONOSPACE:
- tf = Typeface.MONOSPACE;
- break;
- }
-
- setTypeface(tf, styleIndex);
}
private void setRelativeDrawablesIfNeeded(Drawable start, Drawable end) {
@@ -3392,6 +3416,7 @@
boolean mFontFamilyExplicit = false;
int mTypefaceIndex = -1;
int mStyleIndex = -1;
+ int mFontWeight = -1;
boolean mAllCaps = false;
int mShadowColor = 0;
float mShadowDx = 0, mShadowDy = 0, mShadowRadius = 0;
@@ -3416,6 +3441,7 @@
+ " mFontFamilyExplicit:" + mFontFamilyExplicit + "\n"
+ " mTypefaceIndex:" + mTypefaceIndex + "\n"
+ " mStyleIndex:" + mStyleIndex + "\n"
+ + " mFontWeight:" + mFontWeight + "\n"
+ " mAllCaps:" + mAllCaps + "\n"
+ " mShadowColor:" + mShadowColor + "\n"
+ " mShadowDx:" + mShadowDx + "\n"
@@ -3451,6 +3477,8 @@
com.android.internal.R.styleable.TextAppearance_fontFamily);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_textStyle,
com.android.internal.R.styleable.TextAppearance_textStyle);
+ sAppearanceValues.put(com.android.internal.R.styleable.TextView_textFontWeight,
+ com.android.internal.R.styleable.TextAppearance_textFontWeight);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_textAllCaps,
com.android.internal.R.styleable.TextAppearance_textAllCaps);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_shadowColor,
@@ -3536,6 +3564,9 @@
case com.android.internal.R.styleable.TextAppearance_textStyle:
attributes.mStyleIndex = appearance.getInt(attr, attributes.mStyleIndex);
break;
+ case com.android.internal.R.styleable.TextAppearance_textFontWeight:
+ attributes.mFontWeight = appearance.getInt(attr, attributes.mFontWeight);
+ break;
case com.android.internal.R.styleable.TextAppearance_textAllCaps:
attributes.mAllCaps = appearance.getBoolean(attr, attributes.mAllCaps);
break;
@@ -3598,7 +3629,7 @@
attributes.mFontFamily = null;
}
setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily,
- attributes.mTypefaceIndex, attributes.mStyleIndex);
+ attributes.mTypefaceIndex, attributes.mStyleIndex, attributes.mFontWeight);
if (attributes.mShadowColor != 0) {
setShadowLayer(attributes.mShadowRadius, attributes.mShadowDx, attributes.mShadowDy,
@@ -5938,15 +5969,19 @@
boolean forceUpdate = false;
if (isPassword) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
- setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, 0);
+ setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE,
+ Typeface.NORMAL, -1 /* weight, not specifeid */);
} else if (isVisiblePassword) {
if (mTransformation == PasswordTransformationMethod.getInstance()) {
forceUpdate = true;
}
- setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, 0);
+ setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE,
+ Typeface.NORMAL, -1 /* weight, not specified */);
} else if (wasPassword || wasVisiblePassword) {
// not in password mode, clean up typeface and transformation
- setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, -1, -1);
+ setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */,
+ DEFAULT_TYPEFACE /* typeface index */, Typeface.NORMAL,
+ -1 /* weight, not specified */);
if (mTransformation == PasswordTransformationMethod.getInstance()) {
forceUpdate = true;
}
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 340be46..09ff337 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -22,8 +22,12 @@
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
+import android.media.DataSourceDesc;
+import android.media.MediaItem2;
import android.media.MediaMetadata2;
-import android.media.MediaPlayerInterface;
+import android.media.MediaPlayer2;
+import android.media.MediaPlayerBase;
+import android.media.SessionToken2;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
@@ -45,14 +49,14 @@
// TODO: Replace MediaSession wtih MediaSession2 once MediaSession2 is submitted.
/**
- * Displays a video file. VideoView2 class is a View class which is wrapping MediaPlayer2 so that
- * developers can easily implement a video rendering application.
+ * Displays a video file. VideoView2 class is a View class which is wrapping {@link MediaPlayer2}
+ * so that developers can easily implement a video rendering application.
*
* <p>
* <em> Data sources that VideoView2 supports : </em>
* VideoView2 can play video files and audio-only files as
* well. It can load from various sources such as resources or content providers. The supported
- * media file formats are the same as MediaPlayer2.
+ * media file formats are the same as {@link MediaPlayer2}.
*
* <p>
* <em> View type can be selected : </em>
@@ -101,8 +105,6 @@
* does not restore the current play state, play position, selected tracks. Applications should save
* and restore these on their own in {@link android.app.Activity#onSaveInstanceState} and
* {@link android.app.Activity#onRestoreInstanceState}.
- *
- * @hide
*/
public class VideoView2 extends ViewGroupHelper<VideoView2Provider> {
/** @hide */
@@ -199,12 +201,24 @@
* before calling this method.
*
* @throws IllegalStateException if interal MediaSession is not created yet.
+ * @hide TODO: remove
*/
public MediaController getMediaController() {
return mProvider.getMediaController_impl();
}
/**
+ * Returns {@link android.media.SessionToken2} so that developers create their own
+ * {@link android.media.MediaController2} instance. This method should be called when VideoView2
+ * is attached to window, or it throws IllegalStateException.
+ *
+ * @throws IllegalStateException if interal MediaSession is not created yet.
+ */
+ public SessionToken2 getMediaSessionToken() {
+ return mProvider.getMediaSessionToken_impl();
+ }
+
+ /**
* Shows or hides closed caption or subtitles if there is any.
* The first subtitle track will be chosen if there multiple subtitle tracks exist.
* Default behavior of VideoView2 is not showing subtitle.
@@ -265,6 +279,7 @@
mProvider.setAudioAttributes_impl(attributes);
}
+ // TODO: unhide this method when MediaPlayerInterface became unhidden.
/**
* Sets a remote player for handling playback of the selected route from MediaControlView2.
* If this is not called, MediaCotrolView2 will not show the route button.
@@ -277,7 +292,7 @@
* @hide
*/
public void setRouteAttributes(@NonNull List<String> routeCategories,
- @Nullable MediaPlayerInterface player) {
+ @Nullable MediaPlayerBase player) {
mProvider.setRouteAttributes_impl(routeCategories, player);
}
@@ -302,6 +317,8 @@
* Sets video path.
*
* @param path the path of the video.
+ *
+ * @hide TODO remove
*/
public void setVideoPath(String path) {
mProvider.setVideoPath_impl(path);
@@ -311,6 +328,8 @@
* Sets video URI.
*
* @param uri the URI of the video.
+ *
+ * @hide TODO remove
*/
public void setVideoUri(Uri uri) {
mProvider.setVideoUri_impl(uri);
@@ -325,12 +344,33 @@
* changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
* to disallow or allow cross domain redirection.
+ *
+ * @hide TODO remove
*/
public void setVideoUri(Uri uri, Map<String, String> headers) {
mProvider.setVideoUri_impl(uri, headers);
}
/**
+ * Sets {@link MediaItem2} object to render using VideoView2. Alternative way to set media
+ * object to VideoView2 is {@link #setDataSource}.
+ * @param mediaItem the MediaItem2 to play
+ * @see #setDataSource
+ */
+ public void setMediaItem(@NonNull MediaItem2 mediaItem) {
+ mProvider.setMediaItem_impl(mediaItem);
+ }
+
+ /**
+ * Sets {@link DataSourceDesc} object to render using VideoView2.
+ * @param dataSource the {@link DataSourceDesc} object to play.
+ * @see #setMediaItem
+ */
+ public void setDataSource(@NonNull DataSourceDesc dataSource) {
+ mProvider.setDataSource_impl(dataSource);
+ }
+
+ /**
* Selects which view will be used to render video between SurfacView and TextureView.
*
* @param viewType the view type to render video
@@ -361,6 +401,7 @@
* in {@link MediaControlView2}.
* @param executor executor to run callbacks on.
* @param listener A listener to be called when a custom button is clicked.
+ * @hide TODO remove
*/
public void setCustomActions(List<PlaybackState.CustomAction> actionList,
Executor executor, OnCustomActionListener listener) {
@@ -371,7 +412,6 @@
* Registers a callback to be invoked when a view type change is done.
* {@see #setViewType(int)}
* @param l The callback that will be run
- *
* @hide
*/
@VisibleForTesting
@@ -382,6 +422,7 @@
/**
* Registers a callback to be invoked when the fullscreen mode should be changed.
* @param l The callback that will be run
+ * @hide TODO remove
*/
public void setFullScreenRequestListener(OnFullScreenRequestListener l) {
mProvider.setFullScreenRequestListener_impl(l);
@@ -410,6 +451,7 @@
/**
* Interface definition of a callback to be invoked to inform the fullscreen mode is changed.
* Application should handle the fullscreen mode accordingly.
+ * @hide TODO remove
*/
public interface OnFullScreenRequestListener {
/**
@@ -420,8 +462,8 @@
/**
* Interface definition of a callback to be invoked to inform that a custom action is performed.
+ * @hide TODO remove
*/
- // TODO: When MediaSession2 is ready, modify the method to match the signature.
public interface OnCustomActionListener {
/**
* Called to indicate that a custom action is performed.
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 293471c..ffc21d5 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -319,7 +319,7 @@
}
final PackageManager pm = mContext.getPackageManager();
String label = serviceInfo.getResolveInfo().loadLabel(pm).toString();
- String summary = serviceInfo.loadSummary(pm).toString();
+ CharSequence summary = serviceInfo.loadSummary(pm);
if (!includeSummary || TextUtils.isEmpty(summary)) {
return label;
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index fabda4a..2505ea5 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -26,7 +26,8 @@
// be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h
int checkOperation(int code, int uid, String packageName);
int noteOperation(int code, int uid, String packageName);
- int startOperation(IBinder token, int code, int uid, String packageName);
+ int startOperation(IBinder token, int code, int uid, String packageName,
+ boolean startIfModeDefault);
void finishOperation(IBinder token, int code, int uid, String packageName);
void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
void stopWatchingMode(IAppOpsCallback callback);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5966a86..242f422 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -11597,7 +11597,7 @@
* time at the highest power level.
* @param activityInfo
*/
- private void addModemTxPowerToHistory(final ModemActivityInfo activityInfo) {
+ private synchronized void addModemTxPowerToHistory(final ModemActivityInfo activityInfo) {
if (activityInfo == null) {
return;
}
@@ -12606,7 +12606,7 @@
temp = Math.max(0, temp);
reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null,
- status, plugType, level, temp);
+ status, plugType, level);
final boolean onBattery = isOnBattery(plugType, status);
final long uptime = mClocks.uptimeMillis();
@@ -12805,7 +12805,7 @@
// Inform StatsLog of setBatteryState changes.
// If this is the first reporting, pass in recentPast == null.
private void reportChangesToStatsLog(HistoryItem recentPast,
- final int status, final int plugType, final int level, final int temp) {
+ final int status, final int plugType, final int level) {
if (recentPast == null || recentPast.batteryStatus != status) {
StatsLog.write(StatsLog.CHARGING_STATE_CHANGED, status);
@@ -12816,8 +12816,6 @@
if (recentPast == null || recentPast.batteryLevel != level) {
StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, level);
}
- // Let's just always print the temperature, regardless of whether it changed.
- StatsLog.write(StatsLog.DEVICE_TEMPERATURE_REPORTED, temp);
}
public long getAwakeTimeBattery() {
@@ -13350,7 +13348,7 @@
private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
- private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false;
+ private static final boolean DEFAULT_READ_BINARY_CPU_TIME = true;
private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000;
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000;
@@ -13438,6 +13436,7 @@
private void updateKernelUidReadersThrottleTime(long oldTimeMs, long newTimeMs) {
KERNEL_UID_READERS_THROTTLE_TIME = newTimeMs;
if (oldTimeMs != newTimeMs) {
+ mKernelUidCpuTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
mKernelUidCpuFreqTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
mKernelUidCpuActiveTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
mKernelUidCpuClusterTimeReader
diff --git a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
index 2519412..ce45f3c 100644
--- a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
@@ -17,7 +17,6 @@
package com.android.internal.os;
import android.annotation.Nullable;
-import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
@@ -46,20 +45,17 @@
* which has a shorter throttle interval and returns cached result from last read when the request
* is throttled.
*
- * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to
- * the nature of {@link #readDelta(Callback)}).
+ * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
+ * caller has its own view of delta.
*/
-public class KernelUidCpuActiveTimeReader {
- private static final String TAG = "KernelUidCpuActiveTimeReader";
- // Throttle interval in milliseconds
- private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L;
+public class KernelUidCpuActiveTimeReader extends
+ KernelUidCpuTimeReaderBase<KernelUidCpuActiveTimeReader.Callback> {
+ private static final String TAG = KernelUidCpuActiveTimeReader.class.getSimpleName();
private final KernelCpuProcReader mProcReader;
- private long mLastTimeReadMs = Long.MIN_VALUE;
- private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
private SparseArray<Double> mLastUidCpuActiveTimeMs = new SparseArray<>();
- public interface Callback {
+ public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
/**
* Notifies when new data is available.
*
@@ -78,11 +74,8 @@
mProcReader = procReader;
}
- public void readDelta(@Nullable Callback cb) {
- if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) {
- Slog.w(TAG, "Throttle");
- return;
- }
+ @Override
+ protected void readDeltaImpl(@Nullable Callback cb) {
synchronized (mProcReader) {
final ByteBuffer bytes = mProcReader.readBytes();
if (bytes == null || bytes.remaining() <= 4) {
@@ -124,14 +117,9 @@
}
}
}
- // Slog.i(TAG, "Read uids: " + numUids);
- }
- mLastTimeReadMs = SystemClock.elapsedRealtime();
- }
-
- public void setThrottleInterval(long throttleInterval) {
- if (throttleInterval >= 0) {
- mThrottleInterval = throttleInterval;
+ if (DEBUG) {
+ Slog.d(TAG, "Read uids: " + numUids);
+ }
}
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
index 41ef8f0..c21b766 100644
--- a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
@@ -17,7 +17,6 @@
package com.android.internal.os;
import android.annotation.Nullable;
-import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
@@ -50,17 +49,14 @@
* which has a shorter throttle interval and returns cached result from last read when the request
* is throttled.
*
- * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to
- * the nature of {@link #readDelta(Callback)}).
+ * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
+ * caller has its own view of delta.
*/
-public class KernelUidCpuClusterTimeReader {
- private static final String TAG = "KernelUidCpuClusterTimeReader";
- // Throttle interval in milliseconds
- private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L;
+public class KernelUidCpuClusterTimeReader extends
+ KernelUidCpuTimeReaderBase<KernelUidCpuClusterTimeReader.Callback> {
+ private static final String TAG = KernelUidCpuClusterTimeReader.class.getSimpleName();
private final KernelCpuProcReader mProcReader;
- private long mLastTimeReadMs = Long.MIN_VALUE;
- private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
private SparseArray<double[]> mLastUidPolicyTimeMs = new SparseArray<>();
private int mNumClusters = -1;
@@ -70,7 +66,7 @@
private double[] mCurTime; // Reuse to avoid GC.
private long[] mDeltaTime; // Reuse to avoid GC.
- public interface Callback {
+ public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
/**
* Notifies when new data is available.
*
@@ -90,17 +86,8 @@
mProcReader = procReader;
}
- public void setThrottleInterval(long throttleInterval) {
- if (throttleInterval >= 0) {
- mThrottleInterval = throttleInterval;
- }
- }
-
- public void readDelta(@Nullable Callback cb) {
- if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) {
- Slog.w(TAG, "Throttle");
- return;
- }
+ @Override
+ protected void readDeltaImpl(@Nullable Callback cb) {
synchronized (mProcReader) {
ByteBuffer bytes = mProcReader.readBytes();
if (bytes == null || bytes.remaining() <= 4) {
@@ -142,14 +129,15 @@
int numUids = buf.remaining() / (mNumCores + 1);
for (int i = 0; i < numUids; i++) {
- processUidLocked(buf, cb);
+ processUid(buf, cb);
}
- // Slog.i(TAG, "Read uids: " + numUids);
+ if (DEBUG) {
+ Slog.d(TAG, "Read uids: " + numUids);
+ }
}
- mLastTimeReadMs = SystemClock.elapsedRealtime();
}
- private void processUidLocked(IntBuffer buf, @Nullable Callback cb) {
+ private void processUid(IntBuffer buf, @Nullable Callback cb) {
int uid = buf.get();
double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
if (lastTimes == null) {
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index a21a70e..a0787a0 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -59,24 +59,21 @@
* which has a shorter throttle interval and returns cached result from last read when the request
* is throttled.
*
- * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to
- * the nature of {@link #readDelta(Callback)}).
+ * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
+ * caller has its own view of delta.
*/
-public class KernelUidCpuFreqTimeReader {
- private static final boolean DEBUG = false;
- private static final String TAG = "KernelUidCpuFreqTimeReader";
+public class KernelUidCpuFreqTimeReader extends
+ KernelUidCpuTimeReaderBase<KernelUidCpuFreqTimeReader.Callback> {
+ private static final String TAG = KernelUidCpuFreqTimeReader.class.getSimpleName();
static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
- // Throttle interval in milliseconds
- private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L;
- public interface Callback {
+ public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs);
}
private long[] mCpuFreqs;
private long[] mCurTimes; // Reuse to prevent GC.
private long[] mDeltaTimes; // Reuse to prevent GC.
- private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
private int mCpuFreqsCount;
private long mLastTimeReadMs = Long.MIN_VALUE;
private long mNowTimeMs;
@@ -150,30 +147,20 @@
mReadBinary = readBinary;
}
- public void setThrottleInterval(long throttleInterval) {
- if (throttleInterval >= 0) {
- mThrottleInterval = throttleInterval;
- }
- }
-
- public void readDelta(@Nullable Callback callback) {
+ @Override
+ protected void readDeltaImpl(@Nullable Callback callback) {
if (mCpuFreqs == null) {
return;
}
- if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) {
- Slog.w(TAG, "Throttle");
- return;
- }
- mNowTimeMs = SystemClock.elapsedRealtime();
if (mReadBinary) {
readDeltaBinary(callback);
} else {
readDeltaString(callback);
}
- mLastTimeReadMs = mNowTimeMs;
}
private void readDeltaString(@Nullable Callback callback) {
+ mNowTimeMs = SystemClock.elapsedRealtime();
final int oldMask = StrictMode.allowThreadDiskReadsMask();
try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
readDelta(reader, callback);
@@ -182,6 +169,7 @@
} finally {
StrictMode.setThreadPolicyMask(oldMask);
}
+ mLastTimeReadMs = mNowTimeMs;
}
@VisibleForTesting
@@ -232,7 +220,9 @@
}
}
}
- // Slog.i(TAG, "Read uids: "+numUids);
+ if (DEBUG) {
+ Slog.d(TAG, "Read uids: " + numUids);
+ }
}
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 444049e..4263b83 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -38,18 +38,19 @@
* maintains the previous results of a call to {@link #readDelta} in order to provide a proper
* delta.
*/
-public class KernelUidCpuTimeReader {
- private static final String TAG = "KernelUidCpuTimeReader";
+public class KernelUidCpuTimeReader extends
+ KernelUidCpuTimeReaderBase<KernelUidCpuTimeReader.Callback> {
+ private static final String TAG = KernelUidCpuTimeReader.class.getSimpleName();
private static final String sProcFile = "/proc/uid_cputime/show_uid_stat";
private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range";
/**
* Callback interface for processing each line of the proc file.
*/
- public interface Callback {
+ public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
/**
- * @param uid UID of the app
- * @param userTimeUs time spent executing in user space in microseconds
+ * @param uid UID of the app
+ * @param userTimeUs time spent executing in user space in microseconds
* @param systemTimeUs time spent executing in kernel space in microseconds
*/
void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs);
@@ -61,11 +62,13 @@
/**
* Reads the proc file, calling into the callback with a delta of time for each UID.
+ *
* @param callback The callback to invoke for each line of the proc file. If null,
* the data is consumed and subsequent calls to readDelta will provide
* a fresh delta.
*/
- public void readDelta(@Nullable Callback callback) {
+ @Override
+ protected void readDeltaImpl(@Nullable Callback callback) {
final int oldMask = StrictMode.allowThreadDiskReadsMask();
long nowUs = SystemClock.elapsedRealtime() * 1000;
try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
@@ -132,7 +135,10 @@
}
/**
- * Removes the UID from the kernel module and from internal accounting data.
+ * Removes the UID from the kernel module and from internal accounting data. Only
+ * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
+ * visible system wide.
+ *
* @param uid The UID to remove.
*/
public void removeUid(int uid) {
@@ -145,9 +151,12 @@
}
/**
- * Removes UIDs in a given range from the kernel module and internal accounting data.
+ * Removes UIDs in a given range from the kernel module and internal accounting data. Only
+ * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
+ * visible system wide.
+ *
* @param startUid the first uid to remove
- * @param endUid the last uid to remove
+ * @param endUid the last uid to remove
*/
public void removeUidsInRange(int startUid, int endUid) {
if (endUid < startUid) {
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java b/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java
new file mode 100644
index 0000000..11e50e1
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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.internal.os;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.util.Slog;
+
+/**
+ * The base class of all KernelUidCpuTimeReaders.
+ *
+ * This class is NOT designed to be thread-safe or accessed by more than one caller (due to
+ * the nature of {@link #readDelta(Callback)}).
+ */
+public abstract class KernelUidCpuTimeReaderBase<T extends KernelUidCpuTimeReaderBase.Callback> {
+ protected static final boolean DEBUG = false;
+ // Throttle interval in milliseconds
+ private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L;
+
+ private final String TAG = this.getClass().getSimpleName();
+ private long mLastTimeReadMs = Long.MIN_VALUE;
+ private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
+
+ // A generic Callback interface (used by readDelta) to be extended by subclasses.
+ public interface Callback {
+ }
+
+ public void readDelta(@Nullable T cb) {
+ if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) {
+ if (DEBUG) {
+ Slog.d(TAG, "Throttle");
+ }
+ return;
+ }
+ readDeltaImpl(cb);
+ mLastTimeReadMs = SystemClock.elapsedRealtime();
+ }
+
+ protected abstract void readDeltaImpl(@Nullable T cb);
+
+ public void setThrottleInterval(long throttleInterval) {
+ if (throttleInterval >= 0) {
+ mThrottleInterval = throttleInterval;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 32b580c..9f2434e 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -27,6 +27,7 @@
import android.util.Log;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;
+import android.webkit.WebViewLibraryLoader;
import java.io.DataOutputStream;
import java.io.File;
@@ -71,7 +72,8 @@
}
@Override
- protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) {
+ protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
+ String cacheKey) {
Log.i(TAG, "Beginning package preload");
// Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that
// our children will reuse the same classloader instead of creating their own.
@@ -80,6 +82,10 @@
ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
packagePath, libsPath, cacheKey);
+ // Load the native library using WebViewLibraryLoader to share the RELRO data with other
+ // processes.
+ WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
+
// Add the APK to the Zygote's list of allowed files for children.
String[] packageList = TextUtils.split(packagePath, File.pathSeparator);
for (String packageEntry : packageList) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a32fb43..cd83c57 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -155,7 +155,7 @@
if (parsedArgs.preloadPackage != null) {
handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
- parsedArgs.preloadPackageCacheKey);
+ parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
return null;
}
@@ -290,7 +290,8 @@
return mSocketOutStream;
}
- protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) {
+ protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
+ String cacheKey) {
throw new RuntimeException("Zyogte does not support package preloading");
}
@@ -402,10 +403,24 @@
String appDataDir;
/**
- * Whether to preload a package, with the package path in the remainingArgs.
+ * The APK path of the package to preload, when using --preload-package.
*/
String preloadPackage;
+
+ /**
+ * The native library path of the package to preload, when using --preload-package.
+ */
String preloadPackageLibs;
+
+ /**
+ * The filename of the native library to preload, when using --preload-package.
+ */
+ String preloadPackageLibFileName;
+
+ /**
+ * The cache key under which to enter the preloaded package into the classloader cache,
+ * when using --preload-package.
+ */
String preloadPackageCacheKey;
/**
@@ -571,6 +586,7 @@
} else if (arg.equals("--preload-package")) {
preloadPackage = args[++curArg];
preloadPackageLibs = args[++curArg];
+ preloadPackageLibFileName = args[++curArg];
preloadPackageCacheKey = args[++curArg];
} else if (arg.equals("--preload-default")) {
preloadDefault = true;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 50c9d6c..528888f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2464,6 +2464,15 @@
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}
+ if (a.hasValue(R.styleable.Window_windowLayoutInDisplayCutoutMode)) {
+ int mode = a.getInt(R.styleable.Window_windowLayoutInDisplayCutoutMode, -1);
+ if (mode < LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ || mode > LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
+ throw new UnsupportedOperationException("Unknown windowLayoutInDisplayCutoutMode: "
+ + a.getString(R.styleable.Window_windowLayoutInDisplayCutoutMode));
+ }
+ params.layoutInDisplayCutoutMode = mode;
+ }
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index d3fc644..5a06f7f 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -65,9 +65,12 @@
// {@code ServiceSpecificException} may be thrown to signal an error, which caller can
// convert to {@code RecoveryManagerException}.
void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
+ void initRecoveryServiceWithSigFile(in String rootCertificateAlias,
+ in byte[] recoveryServiceCertFile, in byte[] recoveryServiceSigFile);
KeyChainSnapshot getKeyChainSnapshot();
byte[] generateAndStoreKey(String alias);
String generateKey(String alias);
+ String importKey(String alias, in byte[] keyBytes);
String getKey(String alias);
void removeKey(String alias);
void setSnapshotCreatedPendingIntent(in PendingIntent intent);
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 5eecd9c..09adc82 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -23,16 +23,28 @@
YuvToJpegEncoder::YuvToJpegEncoder(int* strides) : fStrides(strides) {
}
+struct ErrorMgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf jmp;
+};
+
+void error_exit(j_common_ptr cinfo) {
+ ErrorMgr* err = (ErrorMgr*) cinfo->err;
+ (*cinfo->err->output_message) (cinfo);
+ longjmp(err->jmp, 1);
+}
+
bool YuvToJpegEncoder::encode(SkWStream* stream, void* inYuv, int width,
int height, int* offsets, int jpegQuality) {
jpeg_compress_struct cinfo;
- jpeg_error_mgr err;
+ ErrorMgr err;
skjpeg_destination_mgr sk_wstream(stream);
- cinfo.err = jpeg_std_error(&err);
- err.error_exit = skjpeg_error_exit;
- jmp_buf jmp;
- if (setjmp(jmp)) {
+ cinfo.err = jpeg_std_error(&err.pub);
+ err.pub.error_exit = error_exit;
+
+ if (setjmp(err.jmp)) {
+ jpeg_destroy_compress(&cinfo);
return false;
}
jpeg_create_compress(&cinfo);
@@ -47,6 +59,8 @@
jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
return true;
}
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 888db32..b163597 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -622,29 +622,25 @@
// ---------------------------------------------------------------------------
-static int checkInternalFormat(SkColorType colorType, int format, int type)
+static int checkInternalFormat(SkColorType colorType, int internalformat,
+ int type)
{
switch(colorType) {
case kN32_SkColorType:
+ return (type == GL_UNSIGNED_BYTE &&
+ internalformat == GL_RGBA) ? 0 : -1;
case kAlpha_8_SkColorType:
- if (type == GL_UNSIGNED_BYTE)
- return 0;
+ return (type == GL_UNSIGNED_BYTE &&
+ internalformat == GL_ALPHA) ? 0 : -1;
case kARGB_4444_SkColorType:
+ return (type == GL_UNSIGNED_SHORT_4_4_4_4 &&
+ internalformat == GL_RGBA) ? 0 : -1;
case kRGB_565_SkColorType:
- switch (type) {
- case GL_UNSIGNED_SHORT_4_4_4_4:
- case GL_UNSIGNED_SHORT_5_6_5:
- case GL_UNSIGNED_SHORT_5_5_5_1:
- return 0;
- case GL_UNSIGNED_BYTE:
- if (format == GL_LUMINANCE_ALPHA)
- return 0;
- }
- break;
+ return (type == GL_UNSIGNED_SHORT_5_6_5 &&
+ internalformat == GL_RGB) ? 0 : -1;
case kRGBA_F16_SkColorType:
- if (type == GL_HALF_FLOAT && format == GL_RGBA16F)
- return 0;
- break;
+ return (type == GL_HALF_FLOAT &&
+ internalformat == GL_RGBA16F) ? 0 : -1;
default:
break;
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 61a22c1..6456fe6 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -282,7 +282,7 @@
// compute the frame count
size_t frameCount;
- if (audio_is_linear_pcm(format)) {
+ if (audio_has_proportional_frames(format)) {
const size_t bytesPerSample = audio_bytes_per_sample(format);
frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
} else {
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index d18c172..5e2cd40 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -28,9 +28,9 @@
#include <sys/types.h>
#include <unistd.h>
-#include <utils/Atomic.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
+#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <utils/List.h>
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d17993a..1b206fd 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -35,8 +35,8 @@
#include <binder/Parcel.h>
#include <binder/BpBinder.h>
#include <binder/ProcessState.h>
+#include <cutils/atomic.h>
#include <log/log.h>
-#include <utils/Atomic.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/Log.h>
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0ef5445..8ca5062 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -846,6 +846,14 @@
transaction->setOverrideScalingMode(ctrl, scalingMode);
}
+static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz,
+ jlong transactionObj,
+ jlong nativeObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->destroySurface(ctrl);
+}
+
static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
return javaObjectForIBinder(env, ctrl->getHandle());
@@ -997,6 +1005,8 @@
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JJI)V",
(void*)nativeSetOverrideScalingMode },
+ {"nativeDestroy", "(JJ)V",
+ (void*)nativeDestroyInTransaction },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
{"nativeScreenshotToBuffer",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 9f3475a..13e0e4a 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -68,6 +68,10 @@
jmethodID callback;
} gFrameMetricsObserverClassInfo;
+struct {
+ jmethodID onFrameDraw;
+} gFrameDrawingCallback;
+
static JNIEnv* getenv(JavaVM* vm) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -849,6 +853,44 @@
proxy->setContentDrawBounds(left, top, right, bottom);
}
+class JGlobalRefHolder {
+public:
+ JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
+
+ virtual ~JGlobalRefHolder() {
+ getenv(mVm)->DeleteGlobalRef(mObject);
+ mObject = nullptr;
+ }
+
+ jobject object() { return mObject; }
+ JavaVM* vm() { return mVm; }
+
+private:
+ JGlobalRefHolder(const JGlobalRefHolder&) = delete;
+ void operator=(const JGlobalRefHolder&) = delete;
+
+ JavaVM* mVm;
+ jobject mObject;
+};
+
+static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
+ jobject clazz, jlong proxyPtr, jobject frameCallback) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ if (!frameCallback) {
+ proxy->setFrameCallback(nullptr);
+ } else {
+ JavaVM* vm = nullptr;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+ auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
+ env->NewGlobalRef(frameCallback));
+ proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) {
+ JNIEnv* env = getenv(globalCallbackRef->vm());
+ env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
+ static_cast<jlong>(frameNr));
+ });
+ }
+}
+
static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
jobject clazz, jobject jsurface, jint left, jint top,
jint right, jint bottom, jobject jbitmap) {
@@ -1034,6 +1076,8 @@
{ "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
{ "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
{ "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
+ { "nSetFrameCallback", "(JLandroid/view/ThreadedRenderer$FrameDrawingCallback;)V",
+ (void*)android_view_ThreadedRenderer_setFrameCallback},
{ "nAddFrameMetricsObserver",
"(JLandroid/view/FrameMetricsObserver;)J",
(void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
@@ -1078,6 +1122,11 @@
gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
env, metricsClass, "mTimingData", "[J");
+ jclass frameCallbackClass = FindClassOrDie(env,
+ "android/view/ThreadedRenderer$FrameDrawingCallback");
+ gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
+ "onFrameDraw", "(J)V");
+
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
index 834ecde..74b47d2 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -35,9 +35,9 @@
optional uint32 mnc = 3;
repeated LocaleProto locales = 4;
optional uint32 screen_layout = 5;
- optional uint32 hdr_color_mode = 6;
- optional uint32 wide_color_gamut = 7;
- optional uint32 touchscreen = 8;
+ optional uint32 color_mode = 6;
+ optional uint32 touchscreen = 7;
+ optional uint32 keyboard = 8;
optional uint32 keyboard_hidden = 9;
optional uint32 hard_keyboard_hidden = 10;
optional uint32 navigation = 11;
diff --git a/core/proto/android/os/data.proto b/core/proto/android/os/data.proto
new file mode 100644
index 0000000..c06f318
--- /dev/null
+++ b/core/proto/android/os/data.proto
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+// This file contains protobuf definitions used in incidentd directly.
+// The top level proto message must be used as a new SectionType in
+// incidentd.
+
+// Output of SECTION_GZIP section type, which reads a file, gzip it and attached
+// in incident report as a proto field, example is LAST_KMSG.
+// NOTE the content in the file must not contain sensitive PII otherwise
+// implement it with fine-grained proto definition.
+message GZippedFileProto {
+ optional string filename = 1;
+
+ optional bytes gzipped_data = 2;
+}
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
index fe9b7ac..aa99ac7 100644
--- a/core/proto/android/os/enums.proto
+++ b/core/proto/android/os/enums.proto
@@ -56,6 +56,17 @@
BATTERY_STATUS_FULL = 5;
}
+// These constants are defined in hardware/interfaces/thermal/1.0/types.hal
+// They are primarily used by android/os/HardwarePropertiesManager.java.
+// Any change to the types in the thermal hal should be made here as well.
+enum TemperatureTypeEnum {
+ TEMPERATURE_TYPE_UKNOWN = -1;
+ TEMPERATURE_TYPE_CPU = 0;
+ TEMPERATURE_TYPE_GPU = 1;
+ TEMPERATURE_TYPE_BATTERY = 2;
+ TEMPERATURE_TYPE_SKIN = 3;
+}
+
// Wakelock types, primarily used by android/os/PowerManager.java.
enum WakeLockLevelEnum {
// NOTE: Wake lock levels were previously defined as a bit field, except
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 9a53b89..7326829 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -20,6 +20,7 @@
import "frameworks/base/core/proto/android/os/batterytype.proto";
import "frameworks/base/core/proto/android/os/cpufreq.proto";
import "frameworks/base/core/proto/android/os/cpuinfo.proto";
+import "frameworks/base/core/proto/android/os/data.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
import "frameworks/base/core/proto/android/os/procrank.proto";
@@ -52,9 +53,8 @@
package android.os;
-// privacy field options must not be set at this level because all
-// the sections are able to be controlled and configured by section ids.
-// Instead privacy field options need to be configured in each section proto message.
+// Privacy tag can be marked to override UNSET messages so generic
+// message type can be handled case by case, e.g. GZippedFileProto.
message IncidentProto {
reserved 1001;
@@ -151,6 +151,12 @@
(section).args = "/sys/class/power_supply/bms/battery_type"
];
+ optional GZippedFileProto last_kmsg = 2007 [
+ (section).type = SECTION_GZIP,
+ (section).args = "/sys/fs/pstore/console-ramoops /sys/fs/pstore/console-ramoops-0 /proc/last_kmsg",
+ (privacy).dest = DEST_AUTOMATIC
+ ];
+
// System Services
optional com.android.server.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
(section).type = SECTION_DUMPSYS,
@@ -208,37 +214,37 @@
(section).args = "procstats --proto"
];
- optional com.android.server.am.proto.ActivityStackSupervisorProto activities = 3012 [
+ optional com.android.server.am.proto.ActivityManagerServiceDumpActivitiesProto activities = 3012 [
(section).type = SECTION_DUMPSYS,
(section).args = "activity --proto activities"
];
- optional com.android.server.am.proto.BroadcastProto broadcasts = 3013 [
+ optional com.android.server.am.proto.ActivityManagerServiceDumpBroadcastsProto broadcasts = 3013 [
(section).type = SECTION_DUMPSYS,
(section).args = "activity --proto broadcasts"
];
- optional com.android.server.am.proto.ActiveServicesProto amservices = 3014 [
+ optional com.android.server.am.proto.ActivityManagerServiceDumpServicesProto amservices = 3014 [
(section).type = SECTION_DUMPSYS,
(section).args = "activity --proto service"
];
- optional com.android.server.am.proto.ProcessesProto amprocesses = 3015 [
+ optional com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto amprocesses = 3015 [
(section).type = SECTION_DUMPSYS,
(section).args = "activity --proto processes"
];
- optional com.android.server.AlarmManagerServiceProto alarm = 3016 [
+ optional com.android.server.AlarmManagerServiceDumpProto alarm = 3016 [
(section).type = SECTION_DUMPSYS,
(section).args = "alarm --proto"
];
- optional com.android.server.wm.proto.WindowManagerServiceProto window = 3017 [
+ optional com.android.server.wm.proto.WindowManagerServiceDumpProto window = 3017 [
(section).type = SECTION_DUMPSYS,
(section).args = "window --proto"
];
- optional com.android.server.am.proto.MemInfoProto meminfo = 3018 [
+ optional com.android.server.am.proto.MemInfoDumpProto meminfo = 3018 [
(section).type = SECTION_DUMPSYS,
(section).args = "meminfo -a --proto"
];
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 788d901..3b9150f 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -40,16 +40,22 @@
message ActivityManagerServiceProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional ActivityStackSupervisorProto activities = 1;
+ optional ActivityManagerServiceDumpActivitiesProto activities = 1;
- optional BroadcastProto broadcasts = 2;
+ optional ActivityManagerServiceDumpBroadcastsProto broadcasts = 2;
- optional ActiveServicesProto services = 3;
+ optional ActivityManagerServiceDumpServicesProto services = 3;
- optional ProcessesProto processes = 4;
+ optional ActivityManagerServiceDumpProcessesProto processes = 4;
}
// "dumpsys activity --proto activities"
+message ActivityManagerServiceDumpActivitiesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional ActivityStackSupervisorProto activity_stack_supervisor = 1;
+}
+
message ActivityStackSupervisorProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -58,6 +64,9 @@
optional KeyguardControllerProto keyguard_controller = 3;
optional int32 focused_stack_id = 4;
optional .com.android.server.wm.proto.IdentifierProto resumed_activity = 5;
+ // Whether or not the home activity is the recents activity. This is needed for the CTS tests to
+ // know what activity types to check for when invoking splitscreen multi-window.
+ optional bool is_home_recents_component = 6;
}
/* represents ActivityStackSupervisor.ActivityDisplay */
@@ -118,7 +127,7 @@
}
// "dumpsys activity --proto broadcasts"
-message BroadcastProto {
+message ActivityManagerServiceDumpBroadcastsProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
repeated ReceiverListProto receiver_list = 1;
@@ -199,7 +208,7 @@
repeated BroadcastSummary historical_broadcasts_summary = 6;
}
-message MemInfoProto {
+message MemInfoDumpProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 uptime_duration_ms = 1;
@@ -403,6 +412,12 @@
}
// "dumpsys activity --proto service"
+message ActivityManagerServiceDumpServicesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional ActiveServicesProto active_services = 1;
+}
+
message ActiveServicesProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -582,7 +597,7 @@
}
// TODO: "dumpsys activity --proto processes"
-message ProcessesProto {
+message ActivityManagerServiceDumpProcessesProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
repeated ProcessRecordProto procs = 1;
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index d1c5db6..53e3ba9 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -28,7 +28,7 @@
option java_multiple_files = true;
// next ID: 43
-message AlarmManagerServiceProto {
+message AlarmManagerServiceDumpProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 current_time = 1;
@@ -220,6 +220,8 @@
optional int64 allow_while_idle_long_duration_ms = 5;
// BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE.
optional int64 allow_while_idle_whitelist_duration_ms = 6;
+ // Maximum alarm recurrence interval.
+ optional int64 max_interval_duration_ms = 7;
}
// A com.android.server.AlarmManagerService.FilterStats object.
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 2d31c5a..69abed3 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -36,6 +36,11 @@
optional ConstantsProto settings = 1;
+ optional int32 current_heartbeat = 14;
+ repeated int32 next_heartbeat = 15;
+ optional int64 last_heartbeat_time_millis = 16;
+ optional int64 next_heartbeat_time_millis = 17;
+
repeated int32 started_users = 2;
message RegisteredJob {
@@ -54,6 +59,8 @@
optional bool is_job_currently_active = 6;
optional bool is_uid_backing_up = 7;
optional bool is_component_present = 8;
+
+ optional int64 last_run_heartbeat = 9;
}
repeated RegisteredJob registered_jobs = 3;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c11058a..9598f24 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -32,7 +32,7 @@
option java_multiple_files = true;
-message WindowManagerServiceProto {
+message WindowManagerServiceDumpProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional WindowManagerPolicyProto policy = 1;
@@ -295,7 +295,6 @@
optional bool animating_exit = 14;
repeated WindowStateProto child_windows = 15;
optional .android.graphics.RectProto surface_position = 16;
- optional .android.graphics.RectProto shown_position = 17;
optional int32 requested_width = 18;
optional int32 requested_height = 19;
optional int32 view_visibility = 20;
diff --git a/core/proto/android/server/windowmanagertrace.proto b/core/proto/android/server/windowmanagertrace.proto
index d96953e..96a90bf 100644
--- a/core/proto/android/server/windowmanagertrace.proto
+++ b/core/proto/android/server/windowmanagertrace.proto
@@ -48,5 +48,5 @@
/* where the trace originated */
optional string where = 2;
- optional WindowManagerServiceProto window_manager_service = 3;
+ optional WindowManagerServiceDumpProto window_manager_service = 3;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a7178a0..5e12e7e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2978,7 +2978,18 @@
settings app. This permission cannot be granted to third-party apps.
<p>Protection level: signature
-->
- <permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+ <permission
+ android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide
+ Allows an application to change the status of a persistable URI permission granted
+ to another application.
+ <p>This permission should <em>only</em> be requested by the platform
+ settings app. This permission cannot be granted to third-party apps.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.FORCE_PERSISTABLE_URI_PERMISSIONS"
android:protectionLevel="signature" />
<!-- @SystemApi Old permission for deleting an app's cache files, no longer used,
diff --git a/core/res/res/drawable/ic_alert_window_layer.xml b/core/res/res/drawable/ic_alert_window_layer.xml
new file mode 100644
index 0000000..15931b8
--- /dev/null
+++ b/core/res/res/drawable/ic_alert_window_layer.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M11.99,18.54l-7.37,-5.73L3,14.07l9,7 9,-7 -1.63,-1.27 -7.38,5.74zM12,16l7.36,-5.73L21,9l-9,-7 -9,7 1.63,1.27L12,16z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_camera.xml b/core/res/res/drawable/ic_camera.xml
new file mode 100644
index 0000000..2921a68
--- /dev/null
+++ b/core/res/res/drawable/ic_camera.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"
+ android:fillColor="#FFFFFF"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
index 78cce58..915f5fb 100644
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ b/core/res/res/drawable/ic_corp_badge.xml
@@ -1,12 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2018 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
- android:viewportWidth="20.0"
- android:viewportHeight="20.0">
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+
<path
- android:pathData="M10,10m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
- android:fillColor="#FF6D00"/>
+ android:fillColor="#fcfcfc"
+ android:pathData="M 10 0 C 15.5228474983 0 20 4.47715250169 20 10 C 20 15.5228474983 15.5228474983 20 10 20 C 4.47715250169 20 0 15.5228474983 0 10 C 0 4.47715250169 4.47715250169 0 10 0 Z" />
<path
- android:pathData="M14.67,6.5h-2.33V5.33c0,-0.65 -0.52,-1.17 -1.17,-1.17H8.83c-0.65,0 -1.17,0.52 -1.17,1.17V6.5H5.33c-0.65,0 -1.16,0.52 -1.16,1.17l-0.01,6.42c0,0.65 0.52,1.17 1.17,1.17h9.33c0.65,0 1.17,-0.52 1.17,-1.17V7.67C15.83,7.02 15.31,6.5 14.67,6.5zM10,11.75c-0.64,0 -1.17,-0.52 -1.17,-1.17c0,-0.64 0.52,-1.17 1.17,-1.17c0.64,0 1.17,0.52 1.17,1.17C11.17,11.22 10.64,11.75 10,11.75zM11.17,6.5H8.83V5.33h2.33V6.5z"
- android:fillColor="#FFFFFF"/>
-</vector>
+ android:strokeColor="#e8eaed"
+ android:strokeWidth="0.25"
+ android:pathData="M 10 0.12 C 15.4565733283 0.12 19.88 4.54342667167 19.88 10 C 19.88 15.4565733283 15.4565733283 19.88 10 19.88 C 4.54342667167 19.88 0.12 15.4565733283 0.12 10 C 0.12 4.54342667167 4.54342667167 0.12 10 0.12 Z" />
+ <path
+ android:pathData="M 3.5 3.5 L 16.5 3.5 L 16.5 16.5 L 3.5 16.5 L 3.5 3.5 Z" />
+ <path
+ android:fillColor="#1a73e8"
+ android:pathData="M14.46,6.58H12.23V5.5a1.09,1.09,0,0,0-1.11-1.08H8.89A1.09,1.09,0,0,0,7.77,5.5V6.58H5.54A1.09,1.09,0,0,0,4.43,7.65v5.91a1.09,1.09,0,0,0,1.11,1.08h8.91a1.09,1.09,0,0,0,1.11-1.08V7.65A1.09,1.09,0,0,0,14.46,6.58ZM10,11.42a1.08,1.08,0,1,1,1.11-1.08A1.1,1.1,0,0,1,10,11.42Zm1.11-4.84H8.89V5.5h2.23Z" />
+ <path
+ android:pathData="M 0 0 H 20 V 20 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_badge_case.xml b/core/res/res/drawable/ic_corp_badge_case.xml
index 2d11ee6..1cd995e 100644
--- a/core/res/res/drawable/ic_corp_badge_case.xml
+++ b/core/res/res/drawable/ic_corp_badge_case.xml
@@ -5,5 +5,5 @@
android:viewportHeight="20.0">
<path
android:pathData="M14.67,6.5h-2.33V5.33c0,-0.65 -0.52,-1.17 -1.17,-1.17H8.83c-0.65,0 -1.17,0.52 -1.17,1.17V6.5H5.33c-0.65,0 -1.16,0.52 -1.16,1.17l-0.01,6.42c0,0.65 0.52,1.17 1.17,1.17h9.33c0.65,0 1.17,-0.52 1.17,-1.17V7.67C15.83,7.02 15.31,6.5 14.67,6.5zM10,11.75c-0.64,0 -1.17,-0.52 -1.17,-1.17c0,-0.64 0.52,-1.17 1.17,-1.17c0.64,0 1.17,0.52 1.17,1.17C11.17,11.22 10.64,11.75 10,11.75zM11.17,6.5H8.83V5.33h2.33V6.5z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#1A73E8"/>
</vector>
diff --git a/core/res/res/drawable/ic_corp_badge_color.xml b/core/res/res/drawable/ic_corp_badge_color.xml
index b6c7969..4aef7d0 100644
--- a/core/res/res/drawable/ic_corp_badge_color.xml
+++ b/core/res/res/drawable/ic_corp_badge_color.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 The Android Open Source Project
@@ -20,5 +21,5 @@
android:viewportHeight="20.0">
<path
android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0"
- android:fillColor="#FFFFFF"/>
-</vector>
+ android:fillColor="#fcfcfc"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_icon_badge_case.xml b/core/res/res/drawable/ic_corp_icon_badge_case.xml
index dd653c6..50551d40 100644
--- a/core/res/res/drawable/ic_corp_icon_badge_case.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_case.xml
@@ -1,9 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2016 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
- android:viewportWidth="64.0"
- android:viewportHeight="64.0">
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+
<path
- android:pathData="M55.67,44h-3.33v-1.67c0,-0.92 -0.74,-1.67 -1.67,-1.67h-3.33c-0.92,0 -1.67,0.74 -1.67,1.67V44h-3.33c-0.92,0 -1.66,0.74 -1.66,1.67l-0.01,9.17c0,0.93 0.74,1.67 1.67,1.67h13.33c0.92,0 1.67,-0.74 1.67,-1.67v-9.17C57.33,44.74 56.59,44 55.67,44zM49,51.5c-0.92,0 -1.67,-0.75 -1.67,-1.67c0,-0.92 0.75,-1.67 1.67,-1.67s1.67,0.75 1.67,1.67C50.67,50.75 49.92,51.5 49,51.5zM50.67,44h-3.33v-1.67h3.33V44z"
- android:fillColor="#FFFFFF"/>
-</vector>
+ android:pathData="M 42 42 L 58 42 L 58 58 L 42 58 L 42 42 Z" />
+ <path
+ android:fillColor="#1A73E8"
+ android:pathData="M55.33,46H52.67V44.67a1.33,1.33,0,0,0-1.33-1.33H48.67a1.33,1.33,0,0,0-1.33,1.33V46H44.67a1.32,1.32,0,0,0-1.33,1.33v7.33A1.33,1.33,0,0,0,44.67,56H55.33a1.33,1.33,0,0,0,1.33-1.33V47.33A1.33,1.33,0,0,0,55.33,46ZM50,52a1.33,1.33,0,1,1,1.33-1.33A1.34,1.34,0,0,1,50,52Zm1.33-6H48.67V44.67h2.67Z" />
+ <path
+ android:pathData="M 0 0 H 64 V 64 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_icon_badge_color.xml b/core/res/res/drawable/ic_corp_icon_badge_color.xml
index 3bc4e67..6dba277 100644
--- a/core/res/res/drawable/ic_corp_icon_badge_color.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_color.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 The Android Open Source Project
@@ -14,11 +15,16 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64.0dp"
- android:height="64.0dp"
- android:viewportWidth="64.0"
- android:viewportHeight="64.0">
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+
<path
- android:pathData="M49.1,48.8m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
- android:fillColor="#FFFFFF"/>
-</vector>
+ android:fillColor="#fcfcfc"
+ android:strokeColor="#e8eaed"
+ android:strokeWidth="0.25"
+ android:pathData="M62,50A12,12,0,1,1,50,38,12,12,0,0,1,62,50" />
+ <path
+ android:pathData="M 0 0 H 64 V 64 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_icon_badge_shadow.xml b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
index a546cdd..f33ed1f 100644
--- a/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 The Android Open Source Project
@@ -14,16 +15,35 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64.0dp"
- android:height="64.0dp"
- android:viewportWidth="64.0"
- android:viewportHeight="64.0">
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+
<path
- android:fillColor="#FF000000"
- android:pathData="M49.1,50.1m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
- android:fillAlpha="0.2"/>
+ android:fillColor="#000000"
+ android:fillAlpha="0.06"
+ android:strokeAlpha="0.06"
+ android:strokeWidth="1"
+ android:pathData="M62,51.25a12,12,0,1,1-12-12,12,12,0,0,1,12,12" />
<path
- android:fillColor="#FF000000"
- android:pathData="M49.1,49.4m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
- android:fillAlpha="0.2"/>
-</vector>
+ android:pathData="M 0 0 H 64 V 64 H 0 V 0 Z" />
+ <path
+ android:fillColor="#000000"
+ android:fillAlpha="0.06"
+ android:strokeAlpha="0.06"
+ android:strokeWidth="1"
+ android:pathData="M62,52.28A12,12,0,1,1,50.53,39.76,12,12,0,0,1,62,52.28" />
+ <path
+ android:fillColor="#000000"
+ android:fillAlpha="0.06"
+ android:strokeAlpha="0.06"
+ android:strokeWidth="1"
+ android:pathData="M62,50.75a12,12,0,1,1-12-12,12,12,0,0,1,12,12" />
+ <path
+ android:fillColor="#000000"
+ android:fillAlpha="0.06"
+ android:strokeAlpha="0.06"
+ android:strokeWidth="1"
+ android:pathData="M62,50.25a12,12,0,1,1-12-12,12,12,0,0,1,12,12" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_mic.xml b/core/res/res/drawable/ic_mic.xml
new file mode 100644
index 0000000..3212330
--- /dev/null
+++ b/core/res/res/drawable/ic_mic.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11L5,11c0,3.41 2.72,6.23 6,6.72L11,21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"
+ android:fillColor="#FFFFFF"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml
index c1795640..2f94d0c 100644
--- a/core/res/res/drawable/progress_horizontal_material.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -19,6 +19,7 @@
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle"
android:tint="?attr/colorControlNormal">
+ <corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/progress_bar_height_material" />
<solid android:color="@color/white_disabled_material" />
</shape>
@@ -28,6 +29,7 @@
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="?attr/colorControlActivated">
+ <corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/progress_bar_height_material" />
<solid android:color="@color/white_disabled_material" />
</shape>
@@ -38,6 +40,7 @@
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="?attr/colorControlActivated">
+ <corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/progress_bar_height_material" />
<solid android:color="@color/white" />
</shape>
diff --git a/core/res/res/drawable/seekbar_track_material.xml b/core/res/res/drawable/seekbar_track_material.xml
index e88a73f..62ef136 100644
--- a/core/res/res/drawable/seekbar_track_material.xml
+++ b/core/res/res/drawable/seekbar_track_material.xml
@@ -19,6 +19,7 @@
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle"
android:tint="@color/control_nodisable_material">
+ <corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/seekbar_track_background_height_material" />
<solid android:color="@color/white_disabled_material" />
</shape>
@@ -32,6 +33,7 @@
<item>
<shape android:shape="rectangle"
android:tint="?attr/colorControlActivated">
+ <corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/seekbar_track_progress_height_material" />
<solid android:color="@color/white_disabled_material" />
</shape>
@@ -48,6 +50,7 @@
<item>
<shape android:shape="rectangle"
android:tint="?attr/colorControlActivated">
+ <corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/seekbar_track_progress_height_material" />
<solid android:color="@color/white" />
</shape>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 20bdf3f..c03cf51 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
+<!-- extends ViewGroup -->
<NotificationHeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/Theme.Material.Notification"
@@ -126,5 +126,42 @@
android:visibility="gone"
android:contentDescription="@string/notification_work_profile_content_description"
/>
+
+ <LinearLayout
+ android:id="@+id/app_ops"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal" >
+ <ImageButton
+ android:id="@+id/camera"
+ android:layout_width="?attr/notificationHeaderIconSize"
+ android:layout_height="?attr/notificationHeaderIconSize"
+ android:src="@drawable/ic_camera"
+ android:tint="@color/notification_secondary_text_color_light"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_marginStart="6dp"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/mic"
+ android:layout_width="?attr/notificationHeaderIconSize"
+ android:layout_height="?attr/notificationHeaderIconSize"
+ android:src="@drawable/ic_mic"
+ android:tint="@color/notification_secondary_text_color_light"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_marginStart="4dp"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/overlay"
+ android:layout_width="?attr/notificationHeaderIconSize"
+ android:layout_height="?attr/notificationHeaderIconSize"
+ android:src="@drawable/ic_alert_window_layer"
+ android:tint="@color/notification_secondary_text_color_light"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_marginStart="4dp"
+ android:visibility="gone"
+ />
+ </LinearLayout>
</NotificationHeaderView>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 17742bf..86b9c51 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Begin programme."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Voltooi herlaai."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> loop"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tik om na program te wissel"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Wissel programme?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"\'n Ander program loop reeds wat gestop moet word voor jy \'n nuwe een kan begin."</string>
- <string name="old_app_action" msgid="493129172238566282">"Keer terug na <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Moenie die nuwe program begin nie."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Begin <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop die ou program sonder om te stoor."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> het berginglimiet oorskry"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Hoopstorting is ingesamel; tik om te deel"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Deel hoopstorting?"</string>
@@ -1833,6 +1838,6 @@
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Wysig"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"Stelselveranderinge"</string>
- <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Moenie steur nie het verander"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Moenie Steur Nie het verander"</string>
<string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Tik om jou optrede-instellings vir onderbrekings na te gaan"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 92783e9..58772d1 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"የኤስኤምኤስ መልዕክቶች"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"የድምጽ መልዕክቶች"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"የWi-Fi ጥሪ"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"የሲም ሁኔታ"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ FULL ጠይቋል"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ HCO ጠይቋል"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ VCO ጠይቋል"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"ቅንብሮች"</string>
<string name="global_action_assist" msgid="3892832961594295030">"ደግፍ"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"የድምጽ እርዳታ"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"መቆለፊያ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"አዲስ ማሳወቂያ"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ምናባዊ የቁልፍ ሰሌዳ"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"ጠቃሚ ምክር፦ ለማጉላት እና ለማሳነስ ሁለቴ-መታ አድርግ።"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ራስ ሙላ"</string>
<string name="setup_autofill" msgid="7103495070180590814">"በራስ ሰር ሙላ አዘጋጅ"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"ራስ-ሙላ"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"፣ "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"መተግበሪያዎችን በማስጀመር ላይ፡፡"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"አጨራረስ ማስነሻ፡፡"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ወደ መተግበሪያ ለመቀየር መታ ያድርጉ"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"መተግበሪያዎችን ለውጥ?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"አዲስ ከመጀመርህ በፊት መቆም ያለበት ሌላ መተግበሪያ እየሄደ ነው።"</string>
- <string name="old_app_action" msgid="493129172238566282">"ወደ <xliff:g id="OLD_APP">%1$s</xliff:g> ተመለስ"</string>
- <string name="old_app_description" msgid="2082094275580358049">"አዲሱን መተግበሪያ አትጀምር።"</string>
- <string name="new_app_action" msgid="5472756926945440706">"ጀምር <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"የድሮውን ትግበራ ሳታስቀምጥ አቁም።"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> የማህደረ ትውስታ ገደብን አልፏል"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"የቆሻሻ ቁልል ተሰብስቧል፤ ለማጋራት መታ ያድርጉ"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"የቆሻሻ ቁልል ይጋራ?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM ካርድ አክል"</string>
<string name="sim_added_message" msgid="6599945301141050216">"የተንቀሳቃሽ አውታረ መረብን ለመድረስ መሣሪያህን ድጋሚ አስነሳ።"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"ዳግም ጀምር"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"የሞባይል አገልግሎትን አግብር"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"የእርስዎን አዲስ ሲም ለማግበር የአገልግሎት አቅራቢውን መተግበሪያ ያውርዱ"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"መተግበሪያን አውርድ"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"አዲስ ሲም ገብቷል"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"ለማዋቀር መታ ያድርጉ"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"ጊዜ አዘጋጅ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 8bbf52e..1d48e88 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1165,13 +1165,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"بدء التطبيقات."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"جارٍ إعادة التشغيل."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> يعمل"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"انقر للتبديل إلى التطبيق"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"تبديل التطبيقات؟"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"يوجد تطبيق آخر قيد التشغيل فعلاً ويجب إيقافه حتى تتمكن من بدء تطبيق جديد."</string>
- <string name="old_app_action" msgid="493129172238566282">"عودة إلى <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"عدم بدء التطبيق الجديد."</string>
- <string name="new_app_action" msgid="5472756926945440706">"بدء <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"إيقاف التطبيق القديم بدون الحفظ."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"لقد تجاوزت <xliff:g id="PROC">%1$s</xliff:g> حد الذاكرة."</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"تم نسخ الذاكرة، انقر للمشاركة."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"هل تريد مشاركة نَسْخ الذاكرة؟"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 4842e7e..f0253a2 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Tətbiqlər başladılır."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Yükləmə başa çatır."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> çalışır"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tətbiqə keçmək üçün tıklayın"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Tətbiqlərə keçilsin?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Bir tətbiq artıq işləyir. Digərini başlatmaq üçün onu dayandırmalısınız."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> bölməsinə qayıdın"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Yeni tətbiqi başlatmayın."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> tətbiqini başladın"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Köhnə tətbiqi yadda saxlamadan dayandırın."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> yaddaş limitini keçdi"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Yığın toplanıb; paylaşmaq üçün tıklayın"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Yığın paylaşılsın?"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 2c81b71..6941579 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1105,13 +1105,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Završavanje pokretanja."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Dodirnite da biste prešli na aplikaciju"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite li da pređete na drugu aplikaciju?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već je pokrenuta druga aplikacija koja mora da bude zaustavljena da biste mogli da pokrenete novu."</string>
- <string name="old_app_action" msgid="493129172238566282">"Vrati se u <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne pokrećite novu aplikaciju."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Zaustavlja staru aplikaciju bez čuvanja."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> premašuje ograničenje memorije"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Snimak dinamičkog dela memorije je napravljen; dodirnite za deljenje"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Želite li da delite snimak dinamičkog dela memorije?"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3af78d3..082a7a6 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -95,8 +95,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS-паведамленні"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Паведамленні галасавой пошты"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-тэлефанія"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Аднарангавая прылада запытала рэжым TTY FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Аднарангавая прылада запытала рэжым TTY НСО"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Аднарангавая прылада запытала рэжым TTY VCO"</string>
@@ -246,8 +245,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Налады"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Дапамога"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Галас. дапамога"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Блакіроўка"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Новае апавяшчэнне"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Віртуальная клавіятура"</string>
@@ -834,8 +832,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Усталяванне аўтазапаўнення"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Аўтазапаўненне"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1128,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Завяршэнне загрузкі."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Прыкладанне \"<xliff:g id="APP">%1$s</xliff:g>\" запушчанае"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Дакраніцеся, каб пераключыцца на праграму"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спынена перад запускам новага."</string>
- <string name="old_app_action" msgid="493129172238566282">"Вярнуцца да <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Не запускайце новыя прыкладанні."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Запусціць <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Спыніць старыя прыкладанні без захавання."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Працэс <xliff:g id="PROC">%1$s</xliff:g> перавысіў ліміт памяці"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Быў сабраны дамп кучы; дакраніцеся, каб абагуліць"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Абагуліць дамп дынамічнай вобласці?"</string>
@@ -1244,12 +1246,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM-карта дадазеная"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Перазагрузіце прыладу, каб атрымаць доступ да мабільнай сеткі."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Перазапусціць"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Уключыць мабільную сувязь"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Спампаваць праграму аператара для актывацыі новай SIM-карты"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Спампаваць праграму"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Устаўлена новая SIM-карта"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Краніце, каб наладзіць"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Задаць час"</string>
@@ -1908,10 +1907,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"Выяўлена шкодная праграма"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"Праграма <xliff:g id="APP_0">%1$s</xliff:g> запытвае дазвол на паказ зрэзаў праграмы <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Рэдагаваць"</string>
- <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
- <skip />
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"Сістэмныя змены"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Зменены налады рэжыму \"Не турбаваць\""</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Націсніце, каб праверыць налады апавяшчэнняў"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 66fb2a8..4319081 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS съобщения"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Съобщения в гласовата поща"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Обаждания през Wi-Fi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Състояние на SIM картата"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Отсрещният потребител заяви пълен TTY режим (FULL)"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Отсрещният потребител заяви TTY режим с пренос на слух (HCO)"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Отсрещният потребител заяви TTY режим с пренос на глас (VCО)"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Помощ"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласова помощ"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Заключване"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Ново известие"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Виртуална клавиатура"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Съвет: Докоснете двукратно, за да увеличите или намалите мащаба."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Автопоп."</string>
<string name="setup_autofill" msgid="7103495070180590814">"Автопоп.: Настройка"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Автоматично попълване"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Приложенията се стартират."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Зареждането завършва."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> се изпълнява"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Докоснете за превключване към приложението"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Да се превключат ли приложенията?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Вече се изпълнява друго приложение, което трябва да бъде спряно, преди да можете да стартирате ново."</string>
- <string name="old_app_action" msgid="493129172238566282">"Назад към <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Новото приложение да не се стартира."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Стартиране на <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Спиране на старото приложение без запазване."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> надхвърли ограничението за памет"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Извлечена е моментна снимка на паметта. Докоснете, за да я споделите"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Да се сподели ли моментната снимка на паметта?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM картата е добавена"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Рестартирайте устройството си, за да осъществите достъп до мобилната мрежа."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Рестартиране"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Активиране на мобилната услуга"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Изтеглете приложението на оператора, за да активирате новата си SIM карта"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Изтегляне на приложението"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Поставена е нова SIM карта"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Докоснете, за да я настроите"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Задаване на часа"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c7116c2..7052e48 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"এসএমএস মেসেজ"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভয়েসমেল মেসেজ"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"ওয়াই-ফাই কলিং"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"সিম কার্ডের স্টাটাস"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"পির TTY মোড FULL অনুরোধ করেছে"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"পির TTY মোড HCO অনুরোধ করেছে"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"পির TTY মোড VCO অনুরোধ করেছে"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"সেটিংস"</string>
<string name="global_action_assist" msgid="3892832961594295030">"সহযোগিতা"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"ভয়েস সহায়তা"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"লকডাউন"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"নতুন বিজ্ঞপ্তি"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ভার্চুয়াল কীবোর্ড"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"টিপ: জুম বাড়ানো ও কমানোর জন্য দুইবার আলতো চাপুন৷"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"স্বতঃপূর্ণ"</string>
<string name="setup_autofill" msgid="7103495070180590814">"স্বতঃপূর্ণ সেট করুন"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"আপনাআপনি পূরণ করুন"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$১$২$৩"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"অ্যাপ্লিকেশানগুলি শুরু করা হচ্ছে৷"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"চালু করা সম্পূর্ণ হচ্ছে৷"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> চলছে"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"অ্যাপ্লিকেশান পাল্টাতে আলতো চাপুন"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"একটি থেকে অন্য অ্যাপ্লিকেশানগুলিতে পরিবর্তন করবেন?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"অন্য একটি অ্যাপ্লিকেশান ইতিমধ্যেই চলছে, নতুন একটি চালু করতে আপনাকে অবশ্যই সেটি বন্ধ করতে হবে৷"</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> এ ফিরুন"</string>
- <string name="old_app_description" msgid="2082094275580358049">"নতুন অ্যাপ্লিকেশান চালু করবেন না৷"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> শুরু করুন"</string>
- <string name="new_app_description" msgid="1932143598371537340">"সংরক্ষণ না করেই পুরোনো অ্যাপ্লিকেশানটি বন্ধ করুন৷"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> মেমরি সীমা অতিক্রম করেছে"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"অনেক ডেটা সংগ্রহ করা হয়েছে; শেয়ার করার জন্য ট্যাপ করুন"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"হিপ ডাম্প শেয়ার করবেন?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"সিম কার্ড যোগ করা হয়েছে"</string>
<string name="sim_added_message" msgid="6599945301141050216">"মোবাইল নেটওয়ার্ক অ্যাক্সেস করতে আপনার ডিভাইসটি পুনর্সূচনা করুন৷"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"রিস্টার্ট করুন"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"মোবাইল পরিষেবা চালু করুন"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"আপনার নতুন সিম কার্ড চালু করতে পরিষেবা প্রদানকারীর অ্যাপটি ডাউনলোড করুন"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"অ্যাপ ডাউনলোড করুন"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন সিম ঢোকানো হয়েছে"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"এটিকে সেট আপ করতে আলতো চাপুন"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"সময় সেট করুন"</string>
@@ -1839,10 +1838,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"ক্ষতিকর অ্যাপ শনাক্ত করা হয়েছে"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"এডিট করুন"</string>
- <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
- <skip />
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"সিস্টেমে হয়ে থাকা পরিবর্তন"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\'বিরক্ত করবেন না\' মোডের সেটিং বদলে গেছে"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"বিজ্ঞপ্তির উপর ট্যাপ করে জানুন আপনি বাধার জন্য কোন সেটিংস সেট করেছেন"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 1d1a36c..da059ad 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1107,13 +1107,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Pokretanje pri kraju."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Dodirnite da biste se prebacili na aplikaciju"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite se prebaciti na drugu aplikaciju?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već je pokrenuta jedna aplikacija koju morate zaustaviti prije pokretanja nove."</string>
- <string name="old_app_action" msgid="493129172238566282">"Vrati se na aplikaciju <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne pokretati novu aplikaciju."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Zaustaviti staru aplikaciju bez spašavanja podataka."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> premašuje ograničenje memorije"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Snimak dinamičkog stanja memorije je napravljen; dodirnite da biste dijelili"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Želite li dijeliti snimak dinamičkog dijela memorije?"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a58339c..e5f208d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"S\'estan iniciant les aplicacions."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"S\'està finalitzant l\'actualització."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Toca per anar a l\'aplicació"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Vols canviar aplicacions?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ja s\'està executant una altra aplicació que s\'ha d\'aturar abans de poder iniciar-ne una de nova."</string>
- <string name="old_app_action" msgid="493129172238566282">"Torna a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"No iniciïs l\'aplicació nova."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Inicia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Atura l\'aplicació antiga sense desar."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de memòria"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"S\'ha recopilat un procés \"heap dump\"; toca per compartir-lo"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Vols compartir el \"heap dump\"?"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d17a488..d9e15b2 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1125,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Spouštění aplikací."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončování inicializace."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Klepnutím přepnete do aplikace"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Přepnout aplikace?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Než spustíte novou aplikaci, je třeba zastavit jinou spuštěnou aplikaci."</string>
- <string name="old_app_action" msgid="493129172238566282">"Návrat do aplikace <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Nespouštět novou aplikaci."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Do aplikace <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Zastavit starou aplikaci bez uložení."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Proces <xliff:g id="PROC">%1$s</xliff:g> překročil limit paměti"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Byl shromážděn výpis haldy, klepnutím jej můžete sdílet"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Sdílet výpis haldy?"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 861ace0..47cf038 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Åbner dine apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Gennemfører start."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tryk for at skifte til appen"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Vil du skifte apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Der kører allerede en anden app, der skal stoppes, før du kan starte en ny."</string>
- <string name="old_app_action" msgid="493129172238566282">"Tilbage til <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Åbn ikke den nye app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop den gamle app uden at gemme."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> har overskredet sin hukommelsesgrænse"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"En heap dump er blevet indsamlet. Tryk for at dele"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Vil du dele en heap dump?"</string>
@@ -1834,5 +1839,5 @@
<string name="screenshot_edit" msgid="7867478911006447565">"Rediger"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"Systemændringer"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Tilstanden Forstyr ikke blev ændret"</string>
- <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Tryk for at tjekke indstillingerne for adfærd ved afbrydelser"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Tryk for at tjekke indstillingerne for adfærd ved underretninger"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f291f62..aab6858 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Apps werden gestartet..."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Start wird abgeschlossen..."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Zum Wechseln der App tippen"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Apps wechseln?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Es wird bereits eine andere App ausgeführt, die vor dem Start einer neuen beendet werden muss."</string>
- <string name="old_app_action" msgid="493129172238566282">"Zu <xliff:g id="OLD_APP">%1$s</xliff:g> zurückkehren"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Neue App nicht starten"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Alte App beenden, ohne zu speichern"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Speicherlimit für \"<xliff:g id="PROC">%1$s</xliff:g>\" überschritten"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap-Dump wurde erfasst. Zum Teilen tippen"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Heap-Dump teilen?"</string>
@@ -1198,7 +1203,7 @@
<string name="sim_added_message" msgid="6599945301141050216">"Starte zur Nutzung des Mobilfunknetzes dein Gerät neu."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Neu starten"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Mobilfunkdienst aktivieren"</string>
- <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Mobilfunkanbieter-App herunterladen, um deine neue SIM-Karte zu aktivieren"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Mobilfunkanbieter-App herunterladen, um meine neue SIM-Karte zu aktivieren"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"App herunterladen"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Neue SIM-Karte eingelegt"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Zum Einrichten tippen"</string>
@@ -1834,5 +1839,5 @@
<string name="screenshot_edit" msgid="7867478911006447565">"Bearbeiten"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"Systemänderungen"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\"Bitte nicht stören\" wurde geändert"</string>
- <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Zum Prüfen der Verhaltenseinstellungen für Unterbrechungen hier tippen"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Tippen, um Einstellungen für den Modus \"Bitte nicht stören\" zu überprüfen"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 5e657c8..1371000 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Έναρξη εφαρμογών."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Ολοκλήρωση εκκίνησης."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Πατήστε για εναλλαγή στην εφαρμογή"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Να γίνει εναλλαγή μεταξύ εφαρμογών;"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Εκτελείται ήδη άλλη εφαρμογή την οποία πρέπει να διακόψετε για να είναι δυνατή η εκτέλεση της νέας."</string>
- <string name="old_app_action" msgid="493129172238566282">"Επιστροφή σε <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Μην εκκινήσετε τη νέα εφαρμογή."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Εκκίνηση της εφαρμογής <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Διακοπή της παλιάς εφαρμογής χωρίς αποθήκευση."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Η διαδικασία <xliff:g id="PROC">%1$s</xliff:g> υπερβαίνει το όριο μνήμης"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Έγινε λήψη του στιγμιότυπου μνήμης, πατήστε για κοινή χρήση"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Κοινή χρήση στιγμιότυπου μνήμης;"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 87a410e..0fddeac 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -305,7 +305,7 @@
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the device\'s fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tap to switch to app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Switch apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Another app is already running that must be stopped before you can start a new one."</string>
- <string name="old_app_action" msgid="493129172238566282">"Return to <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> exceeded memory limit"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump has been collected; tap to share"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Share heap dump?"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 87a410e..0fddeac 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -305,7 +305,7 @@
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the device\'s fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tap to switch to app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Switch apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Another app is already running that must be stopped before you can start a new one."</string>
- <string name="old_app_action" msgid="493129172238566282">"Return to <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> exceeded memory limit"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump has been collected; tap to share"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Share heap dump?"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 87a410e..0fddeac 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -305,7 +305,7 @@
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the device\'s fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tap to switch to app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Switch apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Another app is already running that must be stopped before you can start a new one."</string>
- <string name="old_app_action" msgid="493129172238566282">"Return to <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> exceeded memory limit"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump has been collected; tap to share"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Share heap dump?"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 87a410e..0fddeac 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -305,7 +305,7 @@
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerprint gestures"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the devices fingerprint sensor."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Can capture gestures performed on the device\'s fingerprint sensor."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tap to switch to app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Switch apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Another app is already running that must be stopped before you can start a new one."</string>
- <string name="old_app_action" msgid="493129172238566282">"Return to <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> exceeded memory limit"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump has been collected; tap to share"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Share heap dump?"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index f9aa02c..04e776d 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tap to switch to app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Switch apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Another app is already running that must be stopped before you can start a new one."</string>
- <string name="old_app_action" msgid="493129172238566282">"Return to <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> exceeded memory limit"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump has been collected; tap to share"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Share heap dump?"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c92db3d..950b977 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicaciones"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando el inicio"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Presiona para cambiar a la app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"¿Deseas cambiar aplicaciones?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ya se está ejecutando una aplicación que debe detenerse antes de iniciar una nueva."</string>
- <string name="old_app_action" msgid="493129172238566282">"Regresar a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Inicio <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Interrumpe la aplicación anterior sin guardar los cambios."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> superó el límite de memoria."</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Se recopiló el volcado de pila. Presiona para compartir."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"¿Compartir volcado de pila?"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cb74241..0893201 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicaciones"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando inicio..."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Toca para cambiar a la aplicación"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"¿Cambiar aplicaciones?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Se está ejecutando otra aplicación. Para iniciar una aplicación nueva, debes detenerla."</string>
- <string name="old_app_action" msgid="493129172238566282">"Volver a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación"</string>
- <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Detener la aplicación anterior sin guardar"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ha superado el límite de memoria"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Se ha recopilado un volcado de pila. Toca para compartirlo"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"¿Compartir volcado de pila?"</string>
@@ -1198,7 +1203,7 @@
<string name="sim_added_message" msgid="6599945301141050216">"Reinicia el dispositivo para acceder a la red móvil."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Activar servicio móvil"</string>
- <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Descara la aplicación del operador para activar tu nueva tarjeta SIM"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Descarga la aplicación del operador para activar tu nueva tarjeta SIM"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Descargar aplicación"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Nueva SIM insertada"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Toca para configurar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index de44b89..3f99415 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS-sõnumid"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Kõnepostisõnumid"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"WiFi-kõned"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kaardi olek"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Partner taotles TTY-režiimi TÄIELIK"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Partner taotles TTY-režiimi HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Partner taotles TTY-režiimi VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Seaded"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Abi"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Häälabi"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Lukustamine"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Uus märguanne"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuaalne klaviatuur"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Automaatse täitmise seadistamine"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Automaattäide"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Rakenduste käivitamine."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Käivitamise lõpuleviimine."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> töötab"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Puudutage rakendusele lülitumiseks"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Kas lülituda teisele rakendusele?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Teine rakendus juba töötab ja see tuleb peatada, et saaksite uue käivitada."</string>
- <string name="old_app_action" msgid="493129172238566282">"Tagasi rakendusse <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ärge käivitage uut rakendust."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Käivitage rakendus <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Peatage vana rakendus salvestamata."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Protsess <xliff:g id="PROC">%1$s</xliff:g> ületas mälupiirangu"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Mälutõmmis salvestati; puudutage jagamiseks"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Kas jagada mälutõmmist?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM-kaart lisatud"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Mobiilsidevõrku pääsemiseks taaskäivitage seade."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Taaskäivita"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Mobiilsideteenuse aktiveerimine"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Laadige alla operaatori rakendus, et aktiveerida oma uus SIM-kaart"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Laadi alla rakendus"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Uus SIM-kaart on sisestatud"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Puudutage seadistamiseks"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Kellaaja määramine"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 55b48a6..0bf4802 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Aplikazioak abiarazten."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Bertsio-berritzea amaitzen."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Sakatu aplikaziora joateko"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Aplikazioz aldatu?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Beste aplikazio bat exekutatzen ari da eta gelditu egin behar duzu beste bat abiarazi aurretik."</string>
- <string name="old_app_action" msgid="493129172238566282">"Itzuli <xliff:g id="OLD_APP">%1$s</xliff:g> aplikaziora"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ez abiarazi aplikazio berria."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Hasi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Gelditu aplikazio zaharra ezer gorde gabe."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> prozesuak memoria-muga gainditu du"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Uneko memoria-prozesuaren txostena sortu da; sakatu partekatzeko"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Uneko memoria-prozesuaren txostena partekatu nahi duzu?"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 8be3480..52e986a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"در حال آغاز برنامهها."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"در حال اتمام راهاندازی."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"برای رفتن به برنامه ضربه بزنید"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"برنامه عوض شود؟"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"برنامه دیگری از قبل در حال اجراست که باید متوقف شود تا بتوانید برنامه جدید را شروع کنید."</string>
- <string name="old_app_action" msgid="493129172238566282">"بازگشت به <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"برنامه جدید شروع نشود."</string>
- <string name="new_app_action" msgid="5472756926945440706">"شروع <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"برنامه قدیمی را بدون ذخیره متوقف کنید."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> از حد مجاز حافظه فراتر رفت"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"رون حافظه آزاد جمعآوری شد؛ برای اشتراکگذاری، ضربه بزنید"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"رونوشت حافظه آزاد به اشتراک گذاشته شود؟"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 98b667f..9dc6e95 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Käynnistetään sovelluksia."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Viimeistellään päivitystä."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> käynnissä"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Vaihda sovellukseen napauttamalla."</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Vaihdetaanko sovellusta?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Toinen sovellus on jo käynnissä. Sulje kyseinen sovellus, niin voit käynnistää uuden."</string>
- <string name="old_app_action" msgid="493129172238566282">"Palaa kohteeseen <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Älä käynnistä uutta sovellusta."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Käynnistä <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Pysäytä vanha sovellus tallentamatta."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ylitti muistirajan."</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Keon vedos on kerätty, jaa se napauttamalla."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Jaetaanko keon vedos?"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index c989856..faa8598 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Lancement des applications…"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finalisation de la mise à jour."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Touchez pour passer à l\'application"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Changer d\'application?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Une autre application est déjà en cours d\'exécution. Arrêtez-la avant d\'en lancer une nouvelle."</string>
- <string name="old_app_action" msgid="493129172238566282">"Revenir à <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string>
- <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> a dépassé la limite de mémoire"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"L\'empreinte de mémoire a été recueillie. Touchez pour la partager."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Partager l\'empreinte de mémoire?"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 924a9a3..f840922 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Lancement des applications…"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Finalisation de la mise à jour."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Appuyez ici pour changer d\'application."</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Changer d\'application ?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Une autre application est déjà en cours d\'exécution. Arrêtez-la avant d\'en lancer une nouvelle."</string>
- <string name="old_app_action" msgid="493129172238566282">"Revenir à <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string>
- <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Le processus \"<xliff:g id="PROC">%1$s</xliff:g>\" a dépassé la limite de mémoire"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Une empreinte de la mémoire a bien été générée. Appuyez pour partager."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Partager l\'empreinte de la mémoire ?"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index d36e4a6..5114ba0 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Mensaxes SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensaxes de correo de voz"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por wifi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Estado da SIM"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Outro dispositivo solicitou o modo TTY COMPLETO"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Outro dispositivo solicitou o modo TTY HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Outro dispositivo solicitou o modo TTY VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Asistencia"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Bloquear"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Notificación nova"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Teclado virtual"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Consello: Toca dúas veces para achegar e afastar o zoom."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Encher"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Conf. autocompletar"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Autocompletar"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicacións."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Está finalizando o arranque"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> está en execución"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Toca para cambiar á aplicación"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Queres cambiar as aplicacións?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Xa hai unha aplicación executándose que debe deterse para que poidas iniciar outra nova."</string>
- <string name="old_app_action" msgid="493129172238566282">"Volver a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Non inicies a aplicación nova."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Deter a aplicación antiga sen gardar."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> superou o límite de memoria"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Recompilouse o baleirado de montóns. Toca para compartir"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Queres compartir o baleirado de montóns?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"Engadiuse unha tarxeta SIM"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Reinicia o dispositivo para acceder á rede móbil."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Activar o servizo móbil"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Descarga a aplicación do operador para activar a túa nova SIM"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Descargar aplicación"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Introduciuse unha nova SIM"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Tocar para configurar"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Configurar hora"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index bb6ac6d..bf48ded 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS સંદેશા"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"વૉઇસમેઇલ સંદેશા"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"વાઇ-ફાઇ કૉલિંગ"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"સિમનું સ્ટેટસ"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"પીઅરે TTY મોડ પૂર્ણની વિનંતી કરી"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"પીઅરે TTY મોડ HCO ની વિનંતી કરી"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"પીઅરે TTY મોડ VCO ની વિનંતી કરી"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"સેટિંગ્સ"</string>
<string name="global_action_assist" msgid="3892832961594295030">"સહાય"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"વૉઇસ સહાય"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"લૉકડાઉન"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"નવું નોટિફિકેશન"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"વર્ચ્યુઅલ કીબોર્ડ"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"ટિપ: ઝૂમ વધારવા અને ઘટાડવા માટે બે વાર ટેપ કરો."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"સ્વતઃભરણ"</string>
<string name="setup_autofill" msgid="7103495070180590814">"સ્વતઃભરણ સેટ કરો"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"આપમેળે ભરાઈ જશે"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ઍપ્લિકેશનો શરૂ કરી રહ્યાં છે."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"બૂટ સમાપ્ત કરી રહ્યાં છે."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ચાલુ છે"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ઍપ્લિકેશન પર સ્વિચ કરવા માટે ટૅપ કરો"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"એપ્લિકેશન્સને સ્વિચ કરીએ?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"પહેલાંથી ચાલી રહેલ બીજી એપ્લિકેશનને તમે નવી પ્રારંભ કરો તે પહેલાં બંધ કરવી આવશ્યક છે."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> પર પાછા ફરો"</string>
- <string name="old_app_description" msgid="2082094275580358049">"નવી ઍપ્લિકેશન પ્રારંભ કરશો નહીં."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ને પ્રારંભ કરો"</string>
- <string name="new_app_description" msgid="1932143598371537340">"જૂની એપ્લિકેશનને સાચવ્યાં વગર રોકો."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> એ મેમરી સીમા વટાવી"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"હીપ ડમ્પ ભેગો કરવામાં આવ્યો છે; શેર કરવા માટે ટૅપ કરો"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"હીપ ડમ્પ શેર કરીએ?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"સિમ કાર્ડ ઉમેર્યો"</string>
<string name="sim_added_message" msgid="6599945301141050216">"મોબાઇલ નેટવર્કને ઍક્સેસ કરવા માટે તમારા ઉપકરણને પુનઃપ્રારંભ કરો."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"રિસ્ટાર્ટ કરો"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"મોબાઇલ સેવાને સક્રિય કરો"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"તમારું નવું સિમ સક્રિય કરવા માટે કૅરિઅર ઍપ ડાઉનલોડ કરો"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"ઍપ ડાઉનલોડ કરો"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"નવું સિમ દાખલ કર્યું"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"તેને સેટ કરવા માટે ટૅપ કરો"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"સમય સેટ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5b81d3e..bb1af18 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"मैसेज (एसएमएस)"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"वॉइसमेल संदेश"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"वाई-फ़ाई कॉलिंग"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"सिम की स्थिति"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"पीयर ने टेलीटाइपराइटर (TTY) मोड फ़ुल का अनुरोध किया"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"पीयर ने टेलीटाइपराइटर (TTY) मोड एचसीओ (HCO) का अनुरोध किया"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"पीयर ने टेलीटाइपराइटर (TTY) मोड वीसीअो (VCO) का अनुरोध किया"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"सेटिंग"</string>
<string name="global_action_assist" msgid="3892832961594295030">"सहायता"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज़ से डिवाइस का इस्तेमाल"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"फ़ाेन लॉक करें"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"नई सूचना"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"वर्चुअल कीबोर्ड"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"सलाह: ज़ूम इन और आउट करने के लिए दो बार छूएं."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"स्वत: भरण"</string>
<string name="setup_autofill" msgid="7103495070180590814">"स्वत: भरण सेट करें"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"अपने आप जानकारी भरने की सुविधा"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ऐप्स प्रारंभ होने वाले हैं"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त हो रहा है."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चल रही है"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ऐप्लिकेशन पर स्विच करने के लिए टैप करें"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"ऐप्स स्विच करें?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"दूसरा ऐप्स पहले से चल रहा है जिसे किसी नए ऐप्स को प्रारंभ करने के पहले बंद किया जाना आवश्यक है."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> पर वापस लौटें"</string>
- <string name="old_app_description" msgid="2082094275580358049">"नया ऐप्स प्रारंभ न करें."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> शुरू करें"</string>
- <string name="new_app_description" msgid="1932143598371537340">"पुराने ऐप्स को बिना सहेजे बंद करें."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> मेमोरी सीमा को पार कर गई है"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"हीप डंप का संग्रह कर लिया गया है; शेयर करने के लिए टैप करें"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप शेयर करें?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"सिम कार्ड जोड़ा गया"</string>
<string name="sim_added_message" msgid="6599945301141050216">"मोबाइल नेटवर्क की पहुंच पाने लिए अपना डिवाइस फिर से चालू करें."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"फिर से शुरू करें"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"माेबाइल सेवा चालू करें"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"अपने नए सिम काे चालू करने के लिए इंटरनेट सेवा देने वाली कंपनी का एेप्लिकेशन डाउनलोड करें"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"ऐप्लिकेशन डाउनलोड करें"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"नई SIM डाली गई"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"इसे सेट करने के लिए टैप करें"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"समय सेट करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 857ef36..f740d74 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1105,13 +1105,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Završetak inicijalizacije."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Izvodi se <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Dodirnite da biste prešli na aplikaciju"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Izmijeniti aplikacije?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već se izvodi neka druga aplikacija koja se mora zaustaviti prije pokretanja nove."</string>
- <string name="old_app_action" msgid="493129172238566282">"Natrag na <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne pokreći novu aplikaciju."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Zaustavi staru aplikaciju bez spremanja."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Proces <xliff:g id="PROC">%1$s</xliff:g> premašio je ograničenje memorije"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Generirana je snimka memorije procesa. Dodirnite za dijeljenje."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Žalite li dijeliti snimku memorije procesa?"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 41d9355..1fb05b2 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Kezdő alkalmazások."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Rendszerindítás befejezése."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> fut"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Koppintson az alkalmazásra váltáshoz"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Átvált az alkalmazások között?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Már fut egy másik alkalmazás, amelyet le kell állítania, mielőtt egy újat indíthatna el."</string>
- <string name="old_app_action" msgid="493129172238566282">"Visszatérés a(z) <xliff:g id="OLD_APP">%1$s</xliff:g> alkalmazáshoz"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne indítsa el az új alkalmazást."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> indítása"</string>
- <string name="new_app_description" msgid="1932143598371537340">"A régi alkalmazás leállítása mentés nélkül."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"A(z) <xliff:g id="PROC">%1$s</xliff:g> túllépte a memóriakorlátot"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Elkészült a memória-pillanatfelvétel (heap dump); a megosztáshoz koppintson rá"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Megosztja a memória-pillanatfelvételt?"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ca46497..b299ecf 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Հավելվածները մեկնարկում են:"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Բեռնումն ավարտվում է:"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>-ն աշխատում է"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Հպեք՝ հավելվածին անցնելու համար"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Փոխարկե՞լ հավելվածները:"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Մեկ այլ ծրագիր արդեն աշխատում է, որը պետք է դադարեցնել, նախքան դուք կկարողանաք սկսել նորը:"</string>
- <string name="old_app_action" msgid="493129172238566282">"Վերադառնալ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Չսկսել նոր հավելված:"</string>
- <string name="new_app_action" msgid="5472756926945440706">"Սկիզբ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Դադարեցնել նախկին ծրագիրն առանց պահպանման:"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> գործընթացը գերազանցել է հիշողության սահմանաչափը"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Օգտագործվող օբյեկտների վերաբերյալ տվյալները հավաքվել են: Հպեք՝ դրանք տրամադրելու համար"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Տրամադրե՞լ օգտագործվող օբյեկտների վերաբերյալ տվյալները:"</string>
@@ -1834,5 +1839,5 @@
<string name="screenshot_edit" msgid="7867478911006447565">"Փոփոխել"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"Համակարգի փոփոխություններ"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"«Չանհանգստացնել» ռեժիմի կարգավորումները փոխվել են"</string>
- <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Հպեք՝ ծանուցման կարգավորումները ստուգելու համար"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Հպեք՝ կարգավորումները ստուգելու համար"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 1717814..6ac404c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulai aplikasi."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Menyelesaikan boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Ketuk untuk beralih ke aplikasi"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Beralih aplikasi?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Apl lain sudah berjalan dan harus dihentikan agar Anda dapat memulai yang baru."</string>
- <string name="old_app_action" msgid="493129172238566282">"Kembali ke<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai aplikasi baru."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Mulai <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> melampaui batas memori"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Informasi memori elah dikumpulkan; ketuk untuk membagikan"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Share tumpukan membuang?"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index e481900..2281a54 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Ræsir forrit."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Lýkur ræsingu."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Ýttu til að skipta yfir í forrit"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Skipta um forrit?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Annað forrit er þegar í gangi og það þarf að stöðva áður en hægt er að ræsa nýtt."</string>
- <string name="old_app_action" msgid="493129172238566282">"Til baka í <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ekki ræsa nýja forritið."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Ræsa <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stöðva gamla forritið án þess að vista."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> er yfir minnishámarki"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Minnisgögnum hefur verið safnað, ýttu til að deila"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Deila minnisgögnum?"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c950f3b..9c782bc 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Avvio applicazioni."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Conclusione dell\'avvio."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tocca per passare all\'app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Cambiare applicazione?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Un\'altra applicazione già in esecuzione deve essere chiusa prima di poterne avviare un\'altra."</string>
- <string name="old_app_action" msgid="493129172238566282">"Torna a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Non avviare la nuova applicazione."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Avvia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Interrompi la vecchia applicazione senza salvare."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ha superato il limite di memoria"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Dump dell\'heap raccolto; tocca per condividere"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Condividere il dump dell\'heap?"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5702ee5..56cafa9 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -95,8 +95,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"הודעות SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"הודעות קוליות"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"שיחות Wi-Fi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"סטטוס SIM"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"העמית ביקש TTY במצב FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"העמית ביקש TTY במצב HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"העמית ביקש TTY במצב VCO"</string>
@@ -246,8 +245,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"הגדרות"</string>
<string name="global_action_assist" msgid="3892832961594295030">"סיוע"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"נעילה"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"הודעה חדשה"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"מקלדת וירטואלית"</string>
@@ -834,8 +832,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"טיפ: הקש פעמיים כדי להגדיל ולהקטין."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"מילוי אוטומטי"</string>
<string name="setup_autofill" msgid="7103495070180590814">"הגדר מילוי אוטומטי"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"מילוי אוטומטי"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1128,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"מפעיל אפליקציות."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"מסיים אתחול."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> פועל"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"הקש כדי לעבור לאפליקציה"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"להחליף אפליקציות?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"אפליקציה אחרת כבר פועלת ועליך לעצור אותה לפני שתוכל להפעיל אפליקציה חדשה."</string>
- <string name="old_app_action" msgid="493129172238566282">"חזור אל <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"אל תפעיל את האפליקציה החדש."</string>
- <string name="new_app_action" msgid="5472756926945440706">"הפעל את <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"עצור את האפליקציה הישן ללא שמירה."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> חורג מהגבלת הזיכרון"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Dump של ערימה נאסף. הקש כדי לשתף"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"האם לשתף את נתוני ה-Dump של הערימה?"</string>
@@ -1244,12 +1246,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"כרטיס ה-SIM נוסף"</string>
<string name="sim_added_message" msgid="6599945301141050216">"הפעל מחדש את המכשיר כדי לגשת אל הרשת הסלולרית."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"הפעלה מחדש"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"הפעלה של השירות הסלולרי"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"הורדה של אפליקציית הספק כדי להפעיל את כרטיס ה-SIM החדש"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"הורדת אפליקציה"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"ה-SIM החדש הוכנס"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"הקש כדי להגדיר"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"הגדרת שעה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 00aeab9..15fa7dc 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS メッセージ"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"ボイスメール メッセージ"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM のステータス"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"ピアから、TTY モードを FULL にするようリクエストされました"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"ピアから、TTYモードをHCOにするようリクエストされました"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"ピアから、TTYモードをVCOにするようリクエストされました"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="global_action_assist" msgid="3892832961594295030">"サポート"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"ロックダウン"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"新しい通知"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"仮想キーボード"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"ヒント: ダブルタップで拡大/縮小できます。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自動入力"</string>
<string name="setup_autofill" msgid="7103495070180590814">"自動入力を設定"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"自動入力"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$3$2$1"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"、 "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"アプリを起動しています。"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ブートを終了しています。"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>を実行中"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"タップしてアプリを切り替えます"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"アプリを切り替えますか?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"別のアプリが既に実行中です。新しいアプリを起動する前に実行中のアプリを停止してください。"</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>に戻る"</string>
- <string name="old_app_description" msgid="2082094275580358049">"新しいアプリを起動しません。"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>を起動"</string>
- <string name="new_app_description" msgid="1932143598371537340">"古いアプリを保存せずに停止します。"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g>はメモリの上限を超えました"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ヒープダンプが収集されました。タップして共有できます"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ヒープダンプを共有しますか?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIMカードが追加されました"</string>
<string name="sim_added_message" msgid="6599945301141050216">"モバイルネットワークにアクセスするには端末を再起動してください。"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"再起動"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"モバイル サービスを有効にする"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"新しい SIM を有効にするには携帯通信会社のアプリをダウンロードします"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"アプリをダウンロード"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"新しい SIM が挿入されました"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"タップして設定"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"時刻設定"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 174a770..a0ff3b8 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS შეტყობინებები"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"ხმოვანი ფოსტის შეტყობინებები"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"დარეკვა Wi-Fi-ს მეშვეობით"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM სტატუსი"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"მოთხოვნილია კვანძი TTY რეჟიმი FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"მოთხოვნილია კვანძი TTY რეჟიმი HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"მოთხოვნილია კვანძი TTY რეჟიმი VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"პარამეტრები"</string>
<string name="global_action_assist" msgid="3892832961594295030">"დახმარება"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"ხმოვანი ასისტ."</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"დაბლოკვა"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"ახალი შეტყობინება"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ვირტუალური კლავიატურა"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"რჩევა: მასშტაბის შესაცვლელად გამოიყენეთ ორმაგი შეხება."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ავტოშევსება"</string>
<string name="setup_autofill" msgid="7103495070180590814">"ავტოშევსების დაყენება"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"ავტომატური შევსება"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"აპების ჩართვა"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ჩატვირთვის დასასრული."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"შეეხეთ აპზე გადასართველად"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"გსურთ, აპების გადართვა?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"სხვა აპი არის უკვე გაშვებული, რომელიც უნდა შეჩერდეს ახლის დაწყებამდე."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>-თან დაბრუნება"</string>
- <string name="old_app_description" msgid="2082094275580358049">"არ ჩართოთ ახალი აპი."</string>
- <string name="new_app_action" msgid="5472756926945440706">"დასაწყისი <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"შეაჩერე ძველი აპი ცვლილებების შენახვის გარეშე."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g>-მა გადააჭარბა მეხსიერების ლიმიტს"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"გროვის ამონაწერი მომზადდა; შეეხეთ გასაზიარებლად"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"გავაზიაროთ გროვის ამონაწერი?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM ბარათი დაემატა"</string>
<string name="sim_added_message" msgid="6599945301141050216">"გადატვირთეთ თქვენი მოწყობილობა მობილურ ქსელზე წვდომისთვის."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"გადატვირთვა"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"გაააქტიურეთ მობილური სერვისი"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"ჩამოტვირთეთ ოპერატორის აპი, რათა თქვენი ახალი SIM გაააქტიუროთ"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"აპის ჩამოტვირთვა"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"მოთავსებულია ახალი SIM ბარათი"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"შეეხეთ პარამეტრების დასაყენებლად"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"დროის დაყენება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d4f3e7d..4b106a2 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS хабарлары"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дауыстық пошта хабарлары"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi қоңыраулары"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM күйі"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Пир TTY режимі ТОЛЫҚ сұрады"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Пир TTY режимінің HCO сұрады"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Пир TTY режимінің VCO сұрады"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Параметрлер"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Көмек"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Дауыс көмекшісі"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Құлыптау"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Жаңа хабарландыру"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Виртуалды пернетақта"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Кеңес: Ұлғайту немесе кішірейту үшін екі рет түртіңіз."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Aвто толтыру"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Автотолтыруды орнату"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Aвтотолтыру"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Қолданбалар іске қосылуда."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Қосуды аяқтауда."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> қосылған"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Қолданбаға ауысу үшін түртіңіз"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Қолданбаларды ауыстыру керек пе?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Жаңасын іске қосу алдында тоқтату керек басқа қолданба әлдеқашан жұмыс істеп жатыр."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> қолданбасына оралу"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Жаңа қолданбаны іске қоспау."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> қолданбасын қосу"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Ескі қолданбаны сақтаусыз тоқтату."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> жад шегінен асты"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Үйінді дамп жиналды; бөлісу үшін түртіңіз"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Үйінді дамппен бөлісу қажет пе?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM картасы қосылды"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Ұялы желіге кіру үшін құрылғыны қайта бастаңыз."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Қайта бастау"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Мобильдік қызметті іске қосыңыз"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Жаңа SIM картасын іске қосу үшін оператор қолданбасын жүктеп алыңыз"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Қолданбаны жүктеп алу"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Жаңа SIM салынды"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Оны орнату үшін түртіңіз"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Уақытты реттеу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index a78d527..1e65a76 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1087,13 +1087,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ចាប់ផ្ដើមកម្មវិធី។"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"បញ្ចប់ការចាប់ផ្ដើម។"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការ"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ប៉ះដើម្បីប្តូរកម្មវិធី"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"ប្ដូរកម្មវិធី?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"កម្មវិធីផ្សេងកំពុងដំណើរការរួចហើយ ដែលតម្រូវឲ្យបញ្ឈប់មុនពេលអ្នកអាចចាប់ផ្ដើមថ្មី។"</string>
- <string name="old_app_action" msgid="493129172238566282">"ត្រឡប់ទៅ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"កុំចាប់ផ្ដើមកម្មវិធីថ្មី។"</string>
- <string name="new_app_action" msgid="5472756926945440706">"ចាប់ផ្ដើម <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"បញ្ឈប់កម្មវិធីចាស់ដោយមិនរក្សាទុក"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> លើសពីកម្រិតកំណត់មេម៉ូរី"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump ត្រូវបានប្រមូល សូមប៉ះដើម្បីចែករំលែក"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ចែករំលែក heap dump?"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index adf234b..1adc210 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"ಎಸ್ಎಂಎಸ್ ಸಂದೇಶಗಳು"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"ಧ್ವನಿಮೇಲ್ ಸಂದೇಶಗಳು"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"ಸಿಮ್ ಸ್ಥಿತಿ"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="global_action_assist" msgid="3892832961594295030">"ಸಹಾಯ ಮಾಡು"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"ಲಾಕ್ಡೌನ್"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"ಹೊಸ ಅಧಿಸೂಚನೆ"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ವರ್ಚುಯಲ್ ಕೀಬೋರ್ಡ್"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"ಸಲಹೆ: ಝೂಮ್ ಇನ್ ಮತ್ತು ಝೂಮ್ ಔಟ್ ಮಾಡಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ಸ್ವಯಂತುಂಬುವಿಕೆ"</string>
<string name="setup_autofill" msgid="7103495070180590814">"ಸ್ವಯಂತುಂಬುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"ಸ್ವಯಂತುಂಬುವಿಕೆ"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ಬೂಟ್ ಪೂರ್ಣಗೊಳಿಸಲಾಗುತ್ತಿದೆ."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ರನ್ ಆಗುತ್ತಿದೆ"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ಅಪ್ಲಿಕೇಶನ್ ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಾಯಿಸುವುದೇ?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"ಮತ್ತೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಈಗಾಗಲೇ ಚಾಲ್ತಿಯಲ್ಲಿದೆ ನೀವು ಹೊಸದೊಂದು ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು ಅದನ್ನು ನಿಲ್ಲಿಸಬೇಕು."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> ಗೆ ಹಿಂತಿರುಗಿ"</string>
- <string name="old_app_description" msgid="2082094275580358049">"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರಾರಂಭಿಸಬೇಡಿ."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ಪ್ರಾರಂಭಿಸಿ"</string>
- <string name="new_app_description" msgid="1932143598371537340">"ಉಳಿಸದೇ ಹಳೆಯ ಅಪ್ಲಿಕೇಶನ್ ನಿಲ್ಲಿಸಿ."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ಮೆಮೊರಿ ಮಿತಿಯನ್ನು ಮೀರಿದೆ"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ಹೀಪ್ ಡಂಪ್ ಅನ್ನು ಸಂಗ್ರಹಿಸಲಾಗಿದೆ; ಹಂಚಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ಹೀಪ್ ಡಂಪ್ ಹಂಚಿಕೊಳ್ಳುವುದೇ?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"ಸಿಮ್ ಕಾರ್ಡ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="sim_added_message" msgid="6599945301141050216">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"ಮರುಪ್ರಾರಂಭಿಸು"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"ಮೊಬೈಲ್ ಸೇವೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"ನಿಮ್ಮ ಹೊಸ ಸಿಮ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ವಾಹಕ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಬಳಸಿ"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"ಅಪ್ಲಿಕೇಶನ್ ಡೌನ್ಲೋಡ್ ಮಾಡಿ"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"ಹೊಸ ಸಿಮ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"ಇದನ್ನು ಸ್ಥಾಪಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"ಸಮಯವನ್ನು ಹೊಂದಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 77e6971..2eb5bcf 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS 메시지"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"음성사서함 메시지"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 통화"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 상태"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"피어가 TTY 모드 FULL을 요청했습니다."</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"피어가 TTY 모드 HCO를 요청했습니다."</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"피어가 TTY 모드 VCO를 요청했습니다."</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"설정"</string>
<string name="global_action_assist" msgid="3892832961594295030">"지원"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"음성 지원"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"잠금"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"새 알림"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"가상 키보드"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"도움말: 확대/축소하려면 두 번 탭합니다."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"자동완성"</string>
<string name="setup_autofill" msgid="7103495070180590814">"자동완성 설정..."</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"자동 완성"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$3$2$1"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"앱을 시작하는 중입니다."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"부팅 완료"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"앱을 전환하려면 탭하세요."</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"앱을 전환하시겠습니까?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"다른 앱이 이미 실행 중입니다. 새 앱을 시작하려면 실행 중인 앱을 중단해야 합니다."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>(으)로 돌아가기"</string>
- <string name="old_app_description" msgid="2082094275580358049">"새 앱을 시작하지 마세요."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> 시작"</string>
- <string name="new_app_description" msgid="1932143598371537340">"저장하지 않고 이전 앱을 중단합니다."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g>에서 메모리 제한을 초과했습니다."</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"힙 덤프가 수집되었습니다. 공유하려면 탭하세요."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"힙 덤프를 공유할까요?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM 카드 추가됨"</string>
<string name="sim_added_message" msgid="6599945301141050216">"모바일 네트워크에 액세스하려면 기기를 다시 시작하세요."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"다시 시작"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"모바일 서비스 활성화"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"이동통신사 앱을 다운로드하여 새로운 SIM 활성화"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"앱 다운로드"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"새 SIM이 삽입됨"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"탭하여 설정"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"시간 설정"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ef40d0e..84abf19 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS билдирүүлөрү"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Үн почтасынын билдирүүлөрү"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi аркылуу чалуу"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-картанын абалы"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Peer TTY режимин FULL кылууну суранды"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Peer TTY режимин HCO кылууну суранды"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Peer TTY режимин VCO кылууну суранды"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Жөндөөлөр"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Жардам"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Үн жардамчысы"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Бекем кулпулоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Жаңы эскертме"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Виртуалдык баскычтоп"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Кыйытма: Чоңойтуп-кичирейтиш үчүн эки жолу басыңыз."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Авто-толтуруу"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Автотолтурууну тууралоо"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Автотолтуруу"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Колдонмолорду иштетип баштоо"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Жүктөө аякталууда."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> иштеп жатат"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Колдонмого которулуу үчүн таптап коюңуз"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Колдонмолор которуштурулсунбу?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Жаңы колдонмону иштетээрден мурун, учурда иштеп жатканын өчүрүшүңүз керек."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> колдонмосуна кайтуу"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Жаңы колдонмо башталбасын"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> колдонмосун жүргүзүү"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Эски колдонмону сактабастан токтотуу."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> эстутум чегинен ашып кетти"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Үймө дамп топтолду; бөлүшүү үчүн таптап коюңуз"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Үймө дамп бөлүшүлсүнбү?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM-карта кошулду"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Мобилдик түйүнкгө жетки алуу үчүн, түзмөгүңүздү өчүрүп кайра жандырыңыз."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Кайра баштоо"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Мобилдик кызматты жандыруу"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Жаңы SIM-картаны жандыруу үчүн байланыш операторунун колдонмосун жүктөп алыңыз"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Колдонмону жүктөп алуу"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Жаңы SIM карта салынды"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Аны жөндөө үчүн таптап коюңуз"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Убакытты коюу"</string>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 4f0c0fb..265eaaf 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -27,6 +27,9 @@
<dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen>
<dimen name="preference_widget_width">72dp</dimen>
+ <!-- Height of the status bar -->
+ <dimen name="status_bar_height">@dimen/status_bar_height_landscape</dimen>
+
<!-- Default height of an action bar. -->
<dimen name="action_bar_default_height">40dip</dimen>
<!-- Vertical padding around action bar icons. -->
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index c75b1ff..86c317d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ກຳລັງເປີດແອັບຯ."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ກຳລັງສຳເລັດການເປີດລະບົບ."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກ"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ແຕະເພື່ອສະລັບໄປຫາແອັບ"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"ສະລັບແອັບຯບໍ່?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"ທ່ານຈະຕ້ອງຢຸດນຳໃຊ້ແອັບຯໂຕອື່ນກ່ອນ ກ່ອນທີ່ທ່ານຈະເປີດໃຊ້ແອັບຯໃໝ່ໄດ້."</string>
- <string name="old_app_action" msgid="493129172238566282">"ກັບໄປ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"ຫ້າມເປີດແອັບຯໃໝ່."</string>
- <string name="new_app_action" msgid="5472756926945440706">"ເລີ່ມຕົ້ນ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"ຢຸດແອັບຯເກົ່າໂດຍບໍ່ຕ້ອງບັນທຶກ."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ເກີນຂີດຄວາມຈຳແລ້ວ"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ເກັບກຳຂໍ້ມູນ Head dump ແລ້ວ; ແຕະເພື່ອແບ່ງປັນ"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ແບ່ງປັນການເທກອງບໍ?"</string>
@@ -1832,7 +1837,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"ກວດສອບແອັບທີ່ເປັນອັນຕະລາຍ"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"ແກ້ໄຂ"</string>
- <string name="notification_channel_system_changes" msgid="5072715579030948646">"System changes"</string>
- <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Do Not Disturb has changed"</string>
- <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Tap to check your behavior settings for interruptions"</string>
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"ການປ່ຽນແປງລະບົບ"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"ປ່ຽນໂໝດຫ້າມລົບກວນແລ້ວ"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"ແຕະເພື່ອກວດສອບການຕັ້ງຄ່າພຶດຕິກຳສຳລັບການລົບກວນ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 72ef6ffe..d419a2d 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1125,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Paleidžiamos programos."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Užbaigiamas paleidimas."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Vykdoma „<xliff:g id="APP">%1$s</xliff:g>“"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Palieskite, kad perjungtumėte į programą"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Perjungti programas?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Jau vykdoma kita programa, kurią reikia sustabdyti prieš paleidžiant naują."</string>
- <string name="old_app_action" msgid="493129172238566282">"Grįžti į <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Nepaleiskite naujos programos."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Paleisti „<xliff:g id="OLD_APP">%1$s</xliff:g>“"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Sustabdyti seną programą jos neišsaugant."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"„<xliff:g id="PROC">%1$s</xliff:g>“ viršijo atminties limitą"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Atminties išklotinės duomenys surinkti; palieskite, kad bendrintumėte"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Bendrinti atminties išklotinę?"</string>
@@ -1902,10 +1907,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"Aptikta žalinga programa"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"„<xliff:g id="APP_0">%1$s</xliff:g>“ nori rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Redaguoti"</string>
- <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
- <skip />
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"Sistemos pakeitimai"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Netrukdymo režimas pakeistas"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Palieskite, kad patikrintumėte pertraukčių elgsenos nustatymus"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d63558f..696fce6 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -94,8 +94,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Īsziņas"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balss pasta ziņojumi"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zvani"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM kartes statuss"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu VCO"</string>
@@ -243,8 +242,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Iestatījumi"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Palīdzība"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Balss palīgs"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Bloķēšana"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Jauns paziņojums"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuālā tastatūra"</string>
@@ -831,8 +829,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Padoms. Divreiz pieskarieties, lai tuvinātu un tālinātu."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automātiskā aizpilde"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Iest. aut. aizp."</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Automātiskā aizpilde"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1108,13 +1105,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Notiek lietotņu palaišana."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Tiek pabeigta sāknēšana."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> darbojas"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Pieskarieties, lai pārslēgtos uz lietotni."</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Vai pārslēgt lietotnes?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Jau darbojas cita lietotne. Tās darbība ir jāaptur, lai varētu startēt jaunu lietotni."</string>
- <string name="old_app_action" msgid="493129172238566282">"Atgriezties: <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Nestartējiet jauno lietotni."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Startēt: <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Aptur vecās lietotnes darbību, neko nesaglabājot."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Process <xliff:g id="PROC">%1$s</xliff:g> pārsniedza atmiņas ierobežojumu."</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Tika apkopots kaudzes izraksts. Pieskarieties, lai to kopīgotu."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Vai kopīgot kaudzes izrakstu?"</string>
@@ -1222,12 +1224,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM karte ir pievienota."</string>
<string name="sim_added_message" msgid="6599945301141050216">"Ierīces restartēšana, lai piekļūtu mobilo sakaru tīklam."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Restartēt"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Aktivizējiet mobilo ierīci."</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Lejupielādējiet mobilo sakaru operatora lietotni, lai aktivizētu jauno SIM karti."</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Lejupielādēt lietotni"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Ievietota jauna SIM karte"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Pieskarieties, lai to iestatītu."</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Iestatīt laiku"</string>
@@ -1873,10 +1872,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"Konstatēta kaitīga lietotne"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"Lietotne <xliff:g id="APP_0">%1$s</xliff:g> vēlas rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Rediģēt"</string>
- <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
- <skip />
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"Sistēmas izmaiņas"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Režīms “Netraucēt” ir mainīts"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Pieskarieties, lai pārbaudītu rīcības iestatījumu paziņojumus"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8bfe424..2bd910f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS-пораки"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Пораки од говорна пошта"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Повикување преку Wi-Fi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Статус на SIM-картичка"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Рамноправен уред го побара режимот на TTY „FULL“"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Рамноправен уред го побара режимот на TTY „HCO“"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Рамноправен уред го побара режимот на TTY „VCO“"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Поставки"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Асистенција"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помош"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Заклучување"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Ново известување"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Виртуелна тастатура"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Совет: допри двапати за да зумираш и да одзумираш."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Автоматско пополнување"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Постави „Автоматско пополнување“"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Автоматско пополнување"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Се стартуваат апликациите."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Подигањето завршува."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> работи"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Допрете за да се префрли на апликација"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Промени апликации?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Веќе работи една апликација што треба да ја запрете пред да стартувате нова."</string>
- <string name="old_app_action" msgid="493129172238566282">"Врати се на <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Не стартувајте ја новата апликација."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Вклучи <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Запрете ја старата апликација без зачувување."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> го надмина ограничувањето на меморијата"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Сликата од меморијата е собрана. Допрете за споделување"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Сподели слика од меморија?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"Додадена е SIM картичка"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Рестартирај го својот уред за да пристапиш на мобилната мрежа."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Рестартирај"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Активирајте мобилна услуга"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Преземете ја апликацијата на операторот за да ја активирате новата SIM-картичка"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Преземете апликација"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Вметната е нова SIM-картичка"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Допрете за да поставите"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Постави време"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index c0bc727..340d7f9 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS സന്ദേശങ്ങൾ"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"വോയ്സ്മെയിൽ സന്ദേശങ്ങൾ"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"വൈഫൈ കോളിംഗ്"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"സിം നില"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഫുൾ\'"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"ക്രമീകരണം"</string>
<string name="global_action_assist" msgid="3892832961594295030">"അസിസ്റ്റ്"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"വോയ്സ് സഹായം"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"ലോക്ക്ഡൗൺ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"പുതിയ അറിയിപ്പ്"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"വെർച്വൽ കീബോർഡ്"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"നുറുങ്ങ്: സൂം ഇൻ ചെയ്യാനും സൂം ഔട്ട് ചെയ്യാനും ഇരട്ട-ടാപ്പുചെയ്യുക."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ഓട്ടോഫിൽ"</string>
<string name="setup_autofill" msgid="7103495070180590814">"ഓട്ടോഫിൽ സജ്ജീകരിക്കുക"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"സ്വമേധയാ പൂരിപ്പിക്കൽ"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"അപ്ലിക്കേഷനുകൾ ആരംഭിക്കുന്നു."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ബൂട്ട് ചെയ്യൽ പൂർത്തിയാകുന്നു."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> പ്രവർത്തിക്കുന്നു"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ആപ്പിലേക്ക് മാറുന്നതിന് ടാപ്പുചെയ്യുക"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"അപ്ലിക്കേഷനുകൾ മാറണോ?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"നിങ്ങൾക്ക് പുതിയ ഒരു അപ്ലിക്കേഷൻ ആരംഭിക്കാനാവുന്നതിന് മുമ്പ്, ഇതിനകം പ്രവർത്തിക്കുന്ന മറ്റ് അപ്ലിക്കേഷൻ നിർത്തണം."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> എന്നതിലേക്ക് മടങ്ങുക"</string>
- <string name="old_app_description" msgid="2082094275580358049">"പുതിയ അപ്ലിക്കേഷൻ ആരംഭിക്കരുത്."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ആരംഭിക്കുക"</string>
- <string name="new_app_description" msgid="1932143598371537340">"സംരക്ഷിക്കാതെ തന്നെ പഴയ അപ്ലിക്കേഷൻ നിർത്തുക."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> മെമ്മറി പരിധി കവിഞ്ഞു"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ഹീപ്പ് ഡംപ് ശേഖരിച്ചു; പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ഹീപ്പ് ഡംപ് പങ്കിടണോ?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"സിം കാർഡ് ചേർത്തു"</string>
<string name="sim_added_message" msgid="6599945301141050216">"മൊബൈൽ നെറ്റ്വർക്ക് ആക്സസ്സുചെയ്യാൻ നിങ്ങളുടെ ഉപകരണം പുനരാരംഭിക്കുക."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"പുനരാരംഭിക്കുക"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"മൊബൈൽ സേവനം സജീവമാക്കുക"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"പുതിയ സിം സജീവമാക്കാൻ കാരിയർ ആപ്പ് ഡൗൺലോഡ് ചെയ്യുക"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"ആപ്പ് ഡൗൺലോഡ് ചെയ്യുക"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"പുതിയ സിം ഇട്ടു"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"ഇത് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"സമയം സജ്ജീകരിക്കുക"</string>
@@ -1841,5 +1840,5 @@
<string name="screenshot_edit" msgid="7867478911006447565">"എഡിറ്റ് ചെയ്യുക"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"സിസ്റ്റത്തിലെ മാറ്റങ്ങൾ"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\'ശല്യപ്പെടുത്തരുത്\' മാറ്റി"</string>
- <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"തടസ്സങ്ങൾക്കായുള്ള പ്രവർത്തന ക്രമീകരണം പരിശോധിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"തടസ്സങ്ങൾക്കായി ക്രമീകരിച്ചിട്ടുള്ളത് എന്താണെന്ന് പരിശോധിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 5d6a1eb..a5e6860 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Апп-г эхлүүлж байна."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Эхлэлийг дуусгаж байна."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ажиллаж байна"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Апп руу шилжүүлэх бол товшино уу"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Апп сэлгэх үү?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Та шинэ апп-г ажиллуулахын өмнө зогсоох ёстой өөр апп ажиллаж байна."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>-руу буцах"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Шинэ апп-г эхлүүлж болохгүй."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> эхлүүлэх"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Хуучин апп-г хадгалахгүйгээр зогсооно уу."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> санах ойн хязгаараас давсан"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Хэт их мэдээлэл цуглуулсан байна. Хуваалцахын тулд товшино уу"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Хэт их хуримтлагдсан мэдээллийг хуваалцах уу?"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a7d07f6..00eb8fd 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS संदेश"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"व्हॉइसमेल संदेश"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"वाय-फाय कॉलिंग"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"सिम स्थिती"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"समवयस्क व्यक्तीने TTY मोड पूर्ण ची विनंती केली"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"सेटिंग्ज"</string>
<string name="global_action_assist" msgid="3892832961594295030">"सहाय्यता"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"व्हॉइस सहाय्य"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"लॉकडाउन"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"नवीन सूचना"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"व्हर्च्युअल कीबोर्ड"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"टीप: झूम कमी करण्यासाठी आणि वाढवण्यासाठी दोनदा-टॅप करा."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"स्वयं-भरण"</string>
<string name="setup_autofill" msgid="7103495070180590814">"स्वयं-भरण सेट करा"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"अॉटोफिल"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"अॅप्स प्रारंभ करत आहे."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त होत आहे."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चालत आहे"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"अॅपवर स्विच करण्यासाठी टॅप करा"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"अॅप्स स्विच करायचे?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"आपण एक नवीन प्रारंभ करण्यापूर्वी आधीपासून चालणारा दुसरा अॅप थांबविणे आवश्यक आहे."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> कडे परत"</string>
- <string name="old_app_description" msgid="2082094275580358049">"नवीन अॅप प्रारंभ करू नका."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> सुरू करा"</string>
- <string name="new_app_description" msgid="1932143598371537340">"जतन न करता जुना अॅप थांबवा."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ने मेमेरी मर्यादा वाढविली"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"हीप डंप संकलित केला गेला आहे; सामायिक करण्यासाठी टॅप करा"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप सामायिक करायचे?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"सिम कार्ड जोडले"</string>
<string name="sim_added_message" msgid="6599945301141050216">"मोबाईल नेटवर्कवर अॅक्सेस करण्यासाठी तुमचे डिव्हाइस रीस्टार्ट करा."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"रीस्टार्ट"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"मोबाइल सेवा अॅक्टिव्हेट करा"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"तुमचे नवीन सिम अॅक्टिव्हेट करण्यासाठी वाहकाचे अॅप डाउनलोड करा"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"अॅप डाउनलोड करा"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"नवीन सिम घाला"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"ते सेट करण्यासाठी टॅप करा"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"वेळ सेट करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 5536229..5108c91 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Mesej SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesej mel suara"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Rakan meminta Mod TTY PENUH"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Rakan meminta Mod TTY HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Rakan meminta Mod TTY VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Tetapan"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Bantu"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Kunci semua"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Pemberitahuan baharu"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Papan kekunci maya"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Petua: Ketik dua kali untuk mengezum masuk dan keluar."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Auto isi"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Sediakan Autoisi"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Autolengkap"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulakan apl."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"But akhir."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> dijalankan"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Ketik untuk beralih ke apl"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Tukar apl?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Apl lain sudah pun dijalankan yang mesti dihentikan sebelum anda boleh memulakan yang baharu."</string>
- <string name="old_app_action" msgid="493129172238566282">"Kembali ke <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Jangan mulakan apl baharu."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Mulakan <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> melebihi had memori"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Longgokan timbunan telah dikumpulkan; ketik untuk berkongsi"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Kongsikan longgokan timbunan?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"Kad SIM ditambah"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Mulakan semula peranti anda untuk mengakses rangkaian mudah alih."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Mulakan semula"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Aktifkan perkhidmatan mudah alih"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Muat turun apl pembawa untuk mengaktifkan SIM baharu"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Muat turun apl"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"SIM baharu dimasukkan"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Ketik untuk menyediakannya"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Tetapkan masa"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 77b83cc..176ecff 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -93,7 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS မက်ဆေ့ဂျ်များ"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"အသံမေးလ် မက်ဆေ့ဂျ်များ"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ခေါ်ဆိုမှု"</string>
- <string name="notification_channel_sim" msgid="4052095493875188564">"ဆင်းမ် အခြေအနေ"</string>
+ <string name="notification_channel_sim" msgid="4052095493875188564">"ဆင်းမ်ကဒ် အခြေအနေ"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"အခြားစက်မှ TTY မုဒ် FULL ပြုရန် တောင်းဆို၏"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"အခြားစက်မှ TTY မုဒ် HCO ပြုရန် တောင်းဆို၏"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"TTY မုဒ် VCO ပြုရန် အခြားစက်မှ တောင်းဆို၏"</string>
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"အက်ပ်များကို စတင်နေ"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"လုပ်ငန်းစနစ်ထည့်သွင်း၍ ပြန်လည်စတင်ရန် ပြီးပါပြီ"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> က အလုပ်လုပ်နေသည်"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"အက်ပ်သို့ပြောင်းရန် တို့ပါ"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"အက်ပ်များကို ပြောင်းမလား?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"အခြား အက်ပ်တစ်ခု အလုပ်လုပ်နေ၍ သင်က အသစ် တစ်ခုကို မစမီ ၎င်းကို ရပ်ပစ်ရမည်။"</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>သို့ပြန်သွားရန်"</string>
- <string name="old_app_description" msgid="2082094275580358049">"pp အသစ်ကို မစတင်ပါနှင့်။"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>စတင်ပါ"</string>
- <string name="new_app_description" msgid="1932143598371537340">"အက်ပ်အဟောင်းကို မသိမ်းဆည်းဘဲ ရပ်လိုက်ပါ။"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> သိမ်းထားနိုင်မှု အကန့်အသတ် ကျော်လွန်နေ"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"သိမ်းဆည်းနိုင်မှု ပမာဏကျော်လွန်သွားပါပြီ။ မျှဝေရန် တို့ပါ"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"အရေးပေါ် သိမ်းထားပေးမှု ကို မျှဝေမလား။"</string>
@@ -1199,7 +1204,7 @@
<string name="sim_added_message" msgid="6599945301141050216">"မိုးဘိုင်းကွန်ရက်ကို ဆက်သွယ်ရန် စက်ကို ပြန် စ ပါ"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"အစက ပြန်စရန်"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"မိုဘိုင်းဝန်ဆောင်မှု စတင်ဖွင့်လှစ်ရန်"</string>
- <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"သင့်ဆင်းမ် အသစ်ကို စတင်အသုံးပြုရန် ဝန်ဆောင်မှုပေးသူအက်ပ်ကို ဒေါင်းလုဒ်လုပ်ပါ"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"သင့်ဆင်းမ်ကဒ်အသစ်ကို စတင်အသုံးပြုရန် ဝန်ဆောင်မှုပေးသူအက်ပ်ကို ဒေါင်းလုဒ်လုပ်ပါ"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"အက်ပ် ဒေါင်းလုဒ်လုပ်ရန်"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"SIM အသစ်ထည့်သွင်းလိုက်ပါသည်"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"၎င်းကိုတပ်ဆင်ရန် တို့ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 59b4ffa..b1a254f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS-meldinger"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talepostmeldinger"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-anrop"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Motpart ba om TTY-modus FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Motpart ba om TTY-modus HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Motpart ba om TTY-modus VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Innstillinger"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Hjelp"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Talehjelp"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Låsing"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Nytt varsel"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuelt tastatur"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Tips: Dobbelttrykk for å zoome inn og ut."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Konfig. autofyll"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Autofyll"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starter apper."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Ferdigstiller oppstart."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Trykk for å bytte til appen"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Vil du bytte app?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"En annen app kjører og må stoppes før du kan starte en ny app."</string>
- <string name="old_app_action" msgid="493129172238566282">"Gå tilbake til <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ikke start den nye appen."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Stopp den gamle appen uten å lagre."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> er over minnegrensen"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Minnedumpen («heap dump») er samlet inn – trykk for å dele"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Vil du dele minnedumpen («heap dump»)?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM-kort er lagt til"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Start enheten på nytt for å få tilgang til det mobile nettverket."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Start på nytt"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Aktiver mobiltjeneste"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Last ned operatørappen for å aktivere det nye SIM-kortet ditt"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Last ned appen"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Et nytt SIM-kort er satt inn"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Trykk for å konfigurere"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Stille klokken"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 7685084..1eb0028 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS सन्देशहरू"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"भ्वाइस मेल सन्देशहरू"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi कल"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM को स्थिति"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"सहकर्मी अनुरोध गरियो। TTY मोड पूर्ण"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"सहकर्मी अनुरोध गरियो। TTY मोड HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"सहकर्मी अनुरोध गरियो। TTY मोड VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"सेटिङहरू"</string>
<string name="global_action_assist" msgid="3892832961594295030">"सहायता दिनुहोस्"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज सहायता"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"लकडाउन गर्नु…"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"नयाँ सूचना"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"भर्चुअल किबोर्ड"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"जुक्ति: जुमलाई ठूलो र सानो पार्न दुई पटक हान्नुहोस्।"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"स्वतः भर्ने"</string>
<string name="setup_autofill" msgid="7103495070180590814">"अटोफिल सेटअप गर्नुहोस्"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"स्वतः भरण"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$१$२$३"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1094,13 +1091,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"सुरुवात अनुप्रयोगहरू।"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बुट पुरा हुँदै।"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"अनुप्रयोगमा स्विच गर्न ट्याप गर्नुहोस्"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"अनुप्रयोगहरू स्विच गर्ने हो?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"अर्को अनुप्रयोग पहिले नै चालु छ जुन तपाईंले एउटा नयाँ सुरु गर्नु अघि बन्द गर्नुपर्ने हुन्छ।"</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> मा फर्कनुहोस्"</string>
- <string name="old_app_description" msgid="2082094275580358049">"नयाँ अनुप्रयोग सुरु नगर्नुहोस्।"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> सुरु गर्नुहोस्"</string>
- <string name="new_app_description" msgid="1932143598371537340">"बचत नगरी पुरानो अनुप्रयोग रोक्नुहोस्।"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ले मेमोरी सीमा नाघ्यो"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"हिप डम्पलाई संग्रह गरिएको छ, साझेदारी गर्न छुनुहोस्"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"हिप डम्प साझेदारी गर्नुहुन्छ?"</string>
@@ -1206,12 +1208,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM कार्ड थप गरियो"</string>
<string name="sim_added_message" msgid="6599945301141050216">"मोबाइल नेटवर्क पहुँच गर्न तपाईँको उपकरण पुनःस्टार्ट गर्नुहोस्।"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"पुनः सुरु गर्नुहोस्"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"मोबाइल सेवा सक्रिय गर्नुहोस्"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"आफ्नो नयाँ SIM सक्रिय गर्न सेवा प्रदायकको अनुप्रयोग डाउनलोड गर्नुहोस्"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"अनुप्रयोग डाउनलोड गर्नुहोस्"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"नयाँ SIM घुसाइयो"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"यसलाई सेटअप गर्न ट्याप गर्नुहोस्"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"समय मिलाउनुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 87be867..c0965e5 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Apps starten."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Opstarten afronden."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tik om over te schakelen naar de app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Schakelen tussen apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Er wordt al een andere app uitgevoerd die moet worden gestopt voordat u een nieuwe app kunt starten."</string>
- <string name="old_app_action" msgid="493129172238566282">"Terug naar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"De nieuwe app niet starten."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
- <string name="new_app_description" msgid="1932143598371537340">"De oude app stoppen zonder opslaan."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> heeft geheugenlimiet overschreden"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Heap dump is verzameld. Tik om te delen."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Heap dump delen?"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c4f068b..5672d48 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS ਸੁਨੇਹੇ"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"ਵੌਇਸਮੇਲ ਸੁਨੇਹੇ"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"ਸਿਮ ਅਵਸਥਾ"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"ਪੀਅਰ ਨੇ TTY Mode FULL ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"ਪੀਅਰ ਨੇ TTY Mode HCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"ਪੀਅਰ ਨੇ TTY Mode VCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"ਸੈਟਿੰਗਾਂ"</string>
<string name="global_action_assist" msgid="3892832961594295030">"ਸਹਾਇਤਾ ਕਰੋ"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"ਲਾਕਡਾਊਨ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"ਨਵੀਂ ਸੂਚਨਾ"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ਆਭਾਸੀ ਕੀ-ਬੋਰਡ"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"ਨੁਕਤਾ: ਜ਼ੂਮ ਵਧਾਉਣ ਅਤੇ ਘਟਾਉਣ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ।"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ਆਟੋਫਿਲ"</string>
<string name="setup_autofill" msgid="7103495070180590814">"ਆਟੋਫਿਲ ਸੈਟ ਅਪ ਕਰੋ"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"ਆਟੋਫਿਲ"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ਐਪਸ ਚਾਲੂ ਕਰ ਰਿਹਾ ਹੈ।"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ਬੂਟ ਪੂਰਾ ਕਰ ਰਿਹਾ ਹੈ।"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ਵਾਪਸ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"ਕੀ ਐਪਾਂ \'ਤੇ ਸਵਿੱਚ ਕਰਨਾ ਹੈ?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"ਦੂਜਾ ਐਪ ਪਹਿਲਾਂ ਹੀ ਚੱਲ ਰਿਹਾ ਹੈ, ਜਿਸਨੂੰ ਤੁਹਾਡੇ ਵੱਲੋਂ ਇੱਕ ਨਵਾਂ ਐਪ ਚਾਲੂ ਕਰ ਸਕਣ ਤੋਂ ਪਹਿਲਾਂ ਹੀ ਰੋਕਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ।"</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> ਤੇ ਵਾਪਸ ਜਾਓ"</string>
- <string name="old_app_description" msgid="2082094275580358049">"ਨਵਾਂ ਐਪ ਚਾਲੂ ਨਾ ਕਰੋ।"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
- <string name="new_app_description" msgid="1932143598371537340">"ਸੁਰੱਖਿਅਤ ਕੀਤੇ ਬਿਨਾਂ ਪੁਰਾਣਾ ਐਪ ਬੰਦ ਕਰੋ।"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ਦੀ ਮੈਮਰੀ ਸੀਮਾ ਵਧ ਗਈ ਹੈ"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ਹੀਪ ਡੰਪ ਇਕੱਤਰ ਕੀਤਾ ਗਿਆ; ਸਾਂਝਾ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ਕੀ ਹੀਪ ਡੰਪ ਸ਼ੇਅਰ ਕਰਨਾ ਹੈ?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM ਕਾਰਡ ਜੋੜਿਆ ਗਿਆ"</string>
<string name="sim_added_message" msgid="6599945301141050216">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਤੱਕ ਪਹੁੰਚ ਲਈ ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮੁੜ-ਚਾਲੂ ਕਰੋ।"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"ਰੀਸਟਾਰਟ ਕਰੋ"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"ਮੋਬਾਈਲ ਸੇਵਾ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"ਆਪਣੇ ਨਵੇਂ ਸਿਮ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰਨ ਲਈ ਕੈਰੀਅਰ ਐਪ ਡਾਊਨਲੋਡ ਕਰੋ"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"ਐਪ ਡਾਊਨਲੋਡ ਕਰੋ"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"ਨਵੀਂ SIM ਦਾਖਲ ਕੀਤੀ ਗਈ"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"ਇਸ ਨੂੰ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"ਸਮਾਂ ਸੈੱਟ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f7ba675..2172aae 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1125,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Uruchamianie aplikacji."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Kończenie uruchamiania."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Działa <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Kliknij, by przełączyć na aplikację"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Czy przełączyć aplikacje?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Działa już inna aplikacja, którą trzeba zatrzymać, aby możliwe było uruchomienie nowej."</string>
- <string name="old_app_action" msgid="493129172238566282">"Powrót do aplikacji <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Nie uruchamiaj nowej aplikacji."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Uruchom <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Zatrzymaj starą aplikację bez zapisywania."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Proces <xliff:g id="PROC">%1$s</xliff:g> przekroczył limit pamięci"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Pobrano zrzut sterty – kliknij, by go udostępnić"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Udostępnić zrzut stosu?"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 4c88bc6..45512a5 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Concluindo a inicialização."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Toque para alternar para o app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Alternar entre apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Outro app já está em execução e deve ser interrompido antes que você inicie um novo app."</string>
- <string name="old_app_action" msgid="493129172238566282">"Voltar para <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Não inicie o novo app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Parar o app antigo sem salvar."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> excedeu o limite de memória"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"O despejo de heap foi coletado. Toque para compartilhar"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Compartilhar despejo de heap?"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c9e0a60..a3c8087 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"A iniciar aplicações"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"A concluir o arranque."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Toque para mudar para a aplicação"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Mudar de aplicação?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Já está em execução outra aplicação, que terá de ser parada para que possa iniciar uma nova."</string>
- <string name="old_app_action" msgid="493129172238566282">"Regressar a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Não iniciar a nova aplicação."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Parar a aplicação antiga sem guardar."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> excedeu o limite da memória"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Foi recolhida a captura da área dinâmica para dados. Toque para partilhar."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Pretende partilhar a captura da área dinâmica para dados?"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4c88bc6..45512a5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Concluindo a inicialização."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Toque para alternar para o app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Alternar entre apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Outro app já está em execução e deve ser interrompido antes que você inicie um novo app."</string>
- <string name="old_app_action" msgid="493129172238566282">"Voltar para <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Não inicie o novo app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Parar o app antigo sem salvar."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> excedeu o limite de memória"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"O despejo de heap foi coletado. Toque para compartilhar"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Compartilhar despejo de heap?"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 792e7e2..0e25356 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1105,13 +1105,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Se pornesc aplicațiile."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Se finalizează pornirea."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Atingeți ca să comutați la aplicație"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Comutați între aplicații?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"O altă aplicație rulează deja și trebuie oprită înainte a putea porni o aplicație nouă."</string>
- <string name="old_app_action" msgid="493129172238566282">"Reveniți la <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Nu porniți aplicația nouă."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Porniți <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Opriți vechea aplicație fără să salvați."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> a depășit limita de memorie"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Datele privind memoria au fost culese; atingeți pentru a trimite"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Trimiteți datele privind memoria?"</string>
@@ -1867,7 +1872,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"Aplicație dăunătoare detectată"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Editați"</string>
- <string name="notification_channel_system_changes" msgid="5072715579030948646">"Modificări ale Sistem"</string>
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"Modificări de sistem"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Funcția Nu deranja s-a schimbat"</string>
<string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Atingeți pentru a verifica setările de comportament pentru întreruperi"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0689833..bea3f8b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1125,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск приложений."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Окончание загрузки..."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Приложение <xliff:g id="APP">%1$s</xliff:g> запущено"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Нажмите, чтобы перейти в приложение."</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Переключение приложений"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Выполняется другое приложение, которое необходимо остановить перед запуском нового."</string>
- <string name="old_app_action" msgid="493129172238566282">"Вернуться к приложению <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Не запускать новое приложение."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Запустить приложение <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Остановить старое приложение без сохранения изменений."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Объем памяти процесса \"<xliff:g id="PROC">%1$s</xliff:g>\" превышен"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Создан дамп кучи. Нажмите, чтобы отправить его."</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Отправить дамп кучи?"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 5db0730..7106d9d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1087,13 +1087,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"යෙදුම් ආරම්භ කරමින්."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ඇරඹුම අවසාන කරමින්."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"යෙදුමට මාරු වීමට තට්ටු කරන්න"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"යෙදුම් මාරු වනවාද?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"අලුත් යෙදුමක් ආරම්භ කිරීමට පෙර තවමත් ක්රියාවෙහි යෙදෙමින් පවතින යෙදුම නැවැත්විය යුතුයි."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> වෙත ආපසු යන්න"</string>
- <string name="old_app_description" msgid="2082094275580358049">"නව යෙදුම ආරම්භ නොකරන්න."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> අරඹන්න"</string>
- <string name="new_app_description" msgid="1932143598371537340">"සුරැකීමකින් තොරව පරණ යෙදුම නවත්වන්න."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> මතකයේ සීමාව ඉක්මවා ඇත"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ඉවත දැමීම් ගොඩ රැස් කර ඇත. බෙදා ගැනීමට තට්ටු කරන්න"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"සංච නික්ෂේපය බෙදාගන්න ද?"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4f7f599..8317c75 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1125,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Prebieha spúšťanie aplikácií."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Prebieha dokončovanie spúšťania."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Spustená aplikácia: <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Klepnutím prepnite na aplikáciu"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Prepnúť aplikácie?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Pred spustením novej aplikácie treba zastaviť inú spustenú aplikáciu."</string>
- <string name="old_app_action" msgid="493129172238566282">"Návrat k <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Nespúšťať novú aplikáciu."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Spustiť <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Zastaviť starú aplikáciu bez uloženia."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Proces <xliff:g id="PROC">%1$s</xliff:g> prekročil limit pamäte"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Boli zhromaždené zálohy údajov; zdieľajte ich klepnutím"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Chcete zdieľať zálohy údajov?"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index dacff53..7642544 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -95,8 +95,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Sporočila SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sporočila v odzivniku"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Klicanje prek Wi-Fi-ja"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Stanje kartice SIM"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Enakovredna naprava je zahtevala način TTY FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Enakovredna naprava je zahtevala način TTY HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Enakovredna naprava je zahtevala način TTY VCO"</string>
@@ -246,8 +245,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Nastavitve"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Pomoč"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glas. pomočnik"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Zakleni"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Novo obvestilo"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Navidezna tipkovnica"</string>
@@ -834,8 +832,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Nasvet: Tapnite dvakrat, če želite povečati ali pomanjšati."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Samoizp."</string>
<string name="setup_autofill" msgid="7103495070180590814">"Nastavi samoizp."</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Samodejno izpolnjevanje"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1128,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Zagon aplikacij."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončevanje zagona."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> se izvaja"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Dotaknite se, če želite preklopiti na aplikacijo"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite preklopiti aplikacije?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Preden zaženete novo aplikacijo, ustavite izvajano."</string>
- <string name="old_app_action" msgid="493129172238566282">"Vrni se na <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ne zaženite nove aplikacije."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Začni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Ustavi prejšnjo aplikacijo brez shranjevanja."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Proces <xliff:g id="PROC">%1$s</xliff:g> je presegel omejitev pomnilnika"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Izvoz kopice je zbran; dotaknite se za deljenje z drugimi"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Deljenje izvoza kopice z drugimi?"</string>
@@ -1244,12 +1246,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"Kartica SIM dodana"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Za dostop do mobilnega omrežja znova zaženite napravo."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Vnovičen zagon"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Aktivirajte mobilno storitev"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Prenesite aplikacijo operaterja, da boste lahko aktivirali novo kartico SIM"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Prenos aplikacije"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Nova kartica SIM je vstavljena"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Dotaknite se za nastavitev"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Nastavi uro"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index f3b912d..a981222 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Mesazhet SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesazhet e postës zanore"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Telefonata me Wi-Fi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Statusi i kartës SIM"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Homologu yt kërkoi modalitet \"TTY\" të plotë"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Homologu kërkoi modalitet \"TTY\" të llojit \"HCO\""</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Homologu yt kërkoi modalitet \"TTY\" të llojit \"VCO\""</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Cilësimet"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Ndihma"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ndihma zanore"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Blloko"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Njoftim i ri"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Tastiera virtuale"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Këshillë! Trokit dy herë për të zmadhuar dhe zvogëluar."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Plotësim automatik"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Konfiguro plotësuesin automatik"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Plotësim automatik"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Aplikacionet e fillimit."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Po përfundon nisjen."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> është në punë"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Trokit për të kaluar tek aplikacioni"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Të ndryshohen aplikacionet?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Një tjetër aplikacion është në punë dhe duhet ndaluar përpara se të nisësh një tjetër."</string>
- <string name="old_app_action" msgid="493129172238566282">"Kthehu në <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Mos e fillo aplikacion të ri."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Fillo <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Ndalo aplikacionin e vjetër pa e ruajtur."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> e ka kaluar kufirin e memories"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Stiva e skedarëve fiktivë është mbledhur; trokit për t\'i ndarë"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Të ndahet stiva e skedarëve fiktivë?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"Karta SIM u shtua"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Rinise pajisjen për të pasur qasje në rrjetin celular."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Rifillo"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Aktivizo shërbimin celular"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Shkarko aplikacionin e operatorit celular për të aktivizuar kartën e re SIM"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Shkarko aplikacionin"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Është futur kartë e re SIM"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Trokit për ta konfiguruar"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Cakto kohën"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ced2b51..aa5226b 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1105,13 +1105,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Покретање апликација."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Завршавање покретања."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Додирните да бисте прешли на апликацију"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Желите ли да пређете на другу апликацију?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Већ је покренута друга апликација која мора да буде заустављена да бисте могли да покренете нову."</string>
- <string name="old_app_action" msgid="493129172238566282">"Врати се у <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Не покрећите нову апликацију."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Покрени <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Зауставља стару апликацију без чувања."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> премашује ограничење меморије"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Снимак динамичког дела меморије је направљен; додирните за дељење"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Желите ли да делите снимак динамичког дела меморије?"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index be9e3dd..e713c30 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Sms"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Röstmeddelanden"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-samtal"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Status för SIM-kort"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Peer-enheten begärde texttelefonläget FULL"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Peer-enheten begärde texttelefonläget HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Peer-enheten begärde texttelefonläget VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Inställningar"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Hjälp"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Låsning"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Ny avisering"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuellt tangentbord"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Tips! Dubbelknacka om du vill zooma in eller ut."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Ange Autofyll"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Autofyll"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Appar startas."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Uppgraderingen är klar."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Tryck om du vill byta till appen"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Vill du byta app?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"En annan app som körs måste avslutas innan du kan starta en ny."</string>
- <string name="old_app_action" msgid="493129172238566282">"Gå tillbaka till <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Starta inte den nya appen."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Starta <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Avbryt den gamla appen utan att spara."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Minnesgränsen har överskridits för <xliff:g id="PROC">%1$s</xliff:g>"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"En minnesdump har skapats – tryck här om du vill dela den"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Vill du dela minnesdumpen?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM-kort lades till"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Du måste starta om enheten för att ansluta till det mobila nätverket."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Starta om"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Aktivera mobiltjänst"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Ladda ned operatörens app och aktivera det nya SIM-kortet"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Ladda ned appen"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Nytt SIM-kort har satts in"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Tryck om du vill konfigurera"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Ange tid"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1c9ae55..3eeed7f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1083,13 +1083,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Programu zinaanza"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Inamaliza kuwasha."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> inaendelea"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Gusa ili uende kwenye programu"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Badilisha programu?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Programmu nyingine tayari inaendeshwa na lazima hiyo ikomeshwe kabla ya kuanza nyingine mpya."</string>
- <string name="old_app_action" msgid="493129172238566282">"Rejea katika <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Usianzishe programu mpya."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Anza <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Komesha programu ya zamani bila kuhifadhi."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> imezidi kiwango cha hifadhi kinachotakikana"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Imezidi kikomo cha hifadhi; gusa ili uishiriki"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Ungependa kushiriki picha ya binafsi?"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f912b6d..e251ca4 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS செய்திகள்"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"குரலஞ்சல் செய்திகள்"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"வைஃபை அழைப்பு"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"சிம் நிலை"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"TTY Mode FULLஐ இணைச் செயல்பாடு கோரியது"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"TTY Mode HCOஐ இணைச் செயல்பாடு கோரியது"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"TTY Mode VCOஐ இணைச் செயல்பாடு கோரியது"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"அமைப்பு"</string>
<string name="global_action_assist" msgid="3892832961594295030">"உதவி"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"குரல் உதவி"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"பூட்டு"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"புதிய அறிவிப்பு"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"விர்ச்சுவல் விசைப்பலகை"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"உதவிக்குறிப்பு: அளவைப் பெரிதாக்க மற்றும் குறைக்க இருமுறைத் தட்டவும்."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"தன்னிரப்பி"</string>
<string name="setup_autofill" msgid="7103495070180590814">"தன்னிரப்பியை அமை"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"தன்னிரப்பி"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"பயன்பாடுகள் தொடங்கப்படுகின்றன."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"துவக்குதலை முடிக்கிறது."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> இயங்குகிறது"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"பயன்பாட்டிற்கு மாற, தட்டவும்"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"பயன்பாடுகளை மாற்றவா?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"ஏற்கனவே ஒரு பயன்பாடு இயக்கத்தில் உள்ளது, புதிய ஒன்றைத் தொடங்கும்போது முன்பு இதை நிறுத்த வேண்டும்."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> க்குத் திரும்பு"</string>
- <string name="old_app_description" msgid="2082094275580358049">"புதிய பயன்பாட்டைத் தொடங்க வேண்டாம்."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ஐத் தொடங்கு"</string>
- <string name="new_app_description" msgid="1932143598371537340">"சேமிக்காமல், பழைய பயன்பாட்டை நிறுத்தவும்."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"நினைவக வரம்பை <xliff:g id="PROC">%1$s</xliff:g> மீறியது"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ஹீப் டம்ப் சேகரிக்கப்பட்டது; பகிர, தட்டவும்"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ஹீப் டம்பைப் பகிரவா?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"சிம் கார்டு சேர்க்கப்பட்டது"</string>
<string name="sim_added_message" msgid="6599945301141050216">"மொபைல் நெட்வொர்க்கை அணுக உங்கள் சாதனத்தை மறுதொடக்கம் செய்யவும்."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"மீண்டும் தொடங்கு"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"மொபைல் சேவையை இயக்கு"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"உங்கள் புதிய சிம்மை இயக்க, தொலைத்தொடர்பு நிறுவனத்தின் பயன்பாட்டைப் பதிவிறக்கவும்"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"பயன்பாட்டைப் பதிவிறக்கு"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"புதிய சிம் செருகப்பட்டது"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"அமைக்க, தட்டவும்"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"நேரத்தை அமை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index b123224..b05ce97 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS సందేశాలు"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"వాయిస్ మెయిల్ సందేశాలు"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi కాలింగ్"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM స్థితి"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"అవతలి వారు FULL TTY మోడ్ని అభ్యర్థించారు"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"అవతలి వారు HCO TTY మోడ్ని అభ్యర్థించారు"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"అవతలి వారు VCO TTY మోడ్ని అభ్యర్థించారు"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"సెట్టింగ్లు"</string>
<string name="global_action_assist" msgid="3892832961594295030">"సహాయం"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"వాయిస్ అసిస్టెంట్"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"లాక్ చేయి"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"కొత్త నోటిఫికేషన్"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"వర్చువల్ కీబోర్డ్"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"చిట్కా: దగ్గరకు మరియు దూరానికి జూమ్ చేయడానికి రెండు సార్లు నొక్కండి."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"స్వీయ పూరింపు"</string>
<string name="setup_autofill" msgid="7103495070180590814">"స్వీయ పూరణను సెటప్ చేయండి"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"స్వీయ పూరింపు"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"అనువర్తనాలను ప్రారంభిస్తోంది."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"బూట్ను ముగిస్తోంది."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> అమలవుతోంది"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"అనువర్తనానికి మారడానికి నొక్కండి"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"అనువర్తనాలను మార్చాలా?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"మరో యాప్ ఇప్పటికే అమలవుతోంది, మీరు మరోదాన్ని ప్రారంభించడానికి ముందు అది తప్పనిసరిగా ఆపివేయబడాలి."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>కు తిరిగి వెళ్లండి"</string>
- <string name="old_app_description" msgid="2082094275580358049">"కొత్త యాప్ను ప్రారంభించవద్దు."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ని ప్రారంభించండి"</string>
- <string name="new_app_description" msgid="1932143598371537340">"పాత యాప్ను సేవ్ చేయకుండానే ఆపివేయండి."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> మెమరీ పరిమితిని మించిపోయింది"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"కుప్పలు తెప్పలుగా సేకరించబడింది; షేర్ చేయడానికి నొక్కండి"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"హీప్ డంప్ను భాగస్వామ్యం చేయాలా?"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"సిమ్ కార్డు జోడించబడింది"</string>
<string name="sim_added_message" msgid="6599945301141050216">"మొబైల్ నెట్వర్క్ను యాక్సెస్ చేయడానికి మీ పరికరాన్ని పునఃప్రారంభించండి."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"పునఃప్రారంభించు"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"మొబైల్ సేవను సక్రియం చేయండి"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"మీ కొత్త SIMని సక్రియం చేయడానికి క్యారియర్ యాప్ను డౌన్లోడ్ చేయండి"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"యాప్ని డౌన్లోడ్ చేయి"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"కొత్త SIM చొప్పించారు"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"దీన్ని సెటప్ చేయడానికి నొక్కండి"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"సమయాన్ని సెట్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8444ff0..7aa594a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"กำลังเริ่มต้นแอปพลิเคชัน"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"เสร็จสิ้นการบูต"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงาน"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"แตะเพื่อสลับไปยังแอป"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"สลับแอปพลิเคชันหรือไม่"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"มีแอปพลิเคชันอื่นที่กำลังทำงานอยู่แล้ว ซึ่งต้องหยุดทำงานก่อนที่คุณจะเริ่มแอปพลิเคชันใหม่ได้"</string>
- <string name="old_app_action" msgid="493129172238566282">"กลับสู่ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"อย่าเริ่มแอปพลิเคชันใหม่"</string>
- <string name="new_app_action" msgid="5472756926945440706">"เริ่มต้น <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"หยุดการทำงานของแอปพลิเคชันเก่าโดยไม่บันทึก"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> เกินขีดจำกัดของหน่วยความจำ"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"รวบรวมฮีพดัมพ์แล้ว แตะเพื่อแชร์"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"แชร์ฮีพดัมพ์ไหม"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6c8e47d..9bb64e0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Sinisimulan ang apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Pagtatapos ng pag-boot."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"I-tap upang lumipat sa app"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Lumipat ng apps?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"May tumatakbo nang isa pang app na dapat na ihinto bago ka makapagsimula ng bago."</string>
- <string name="old_app_action" msgid="493129172238566282">"Bumalik sa <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Huwag simulan ang bagong app."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Simulan ang <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Ihinto ang lumang app nang hindi nagse-save."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Lumampas ang <xliff:g id="PROC">%1$s</xliff:g> sa limitasyon ng memory"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Nakolekta na ang heap dump; i-tap upang ibahagi"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Ibahagi ang heap dump?"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8858388..e63e319 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS mesajları"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sesli mesajlar"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Kablosuz çağrı"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM durumu"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"Karşı taraf TTY Modunu TAM yaptı"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"Karşı taraf TTY Modunu HCO yaptı"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Karşı taraf TTY Modunu VCO yaptı"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Asist"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Sesli Yardım"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Tam gizlilik"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Yeni bildirim"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Sanal klavye"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez dokunun."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Otomatik doldurma ayarla"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Otomatik doldur"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1072,7 +1069,7 @@
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunu Sistem ayarları > Uygulamalar > İndirilenler bölümünden yeniden etkinleştirin."</string>
<string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> geçerli Ekran boyutu ayarını desteklemiyor ve beklenmedik bir şekilde davranabilir."</string>
<string name="unsupported_display_size_show" msgid="7969129195360353041">"Her zaman göster"</string>
- <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması Android OS\'un uyumlu olmayan önceki bir sürümü için geliştirilmiştir ve beklenmedik şekilde davranabilir. Uygulamanın güncellenmiş bir sürümü mevcut olabilir."</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması Android OS\'in uyumlu olmayan önceki bir sürümü için geliştirilmiştir ve beklenmedik şekilde davranabilir. Uygulamanın güncellenmiş bir sürümü mevcut olabilir."</string>
<string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"Her zaman göster"</string>
<string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Güncellemeleri denetle"</string>
<string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Uygulamalar başlatılıyor"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Açılış tamamlanıyor."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Uygulamaya geçmek için dokunun"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Uygulama değiştirilsin mi?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Başka bir uygulama zaten çalışıyor. Yeni bir uygulama başlatmadan bu uygulama durdurulmalıdır."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> öğesine geri dön"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Yeni uygulamayı başlatmayın."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> uygulamasını başlat"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Kaydetmeden eski uygulamayı durdurun."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> bellek sınırını aştı"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Yığın dökümü toplandı. Paylaşmak için dokunun"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Yığın dökümü paylaşılsın mı?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM kart eklendi"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Mobil ağa erişmek için cihazınızı yeniden başlatın."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Yeniden başlat"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Mobil hizmeti etkinleştirin"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Yeni SIM\'inizi etkinleştirmek için operatörün uygulamasını indirin"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Uygulama indir"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Yeni SIM kart takıldı"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Kurmak için dokunun"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarlayın"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b9fba79..61f74bf 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1125,13 +1125,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск програм."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Завершення завантаження."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Працює <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Торкніться, щоб відкрити додаток"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Переключитися між програмами?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Уже працює інша програма, яку потрібно зупинити перед тим, як запускати нову програму."</string>
- <string name="old_app_action" msgid="493129172238566282">"Поверн. до <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Не запускати нову програму."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Запуст. <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Зупинити попередню програму без збереження."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"Процес <xliff:g id="PROC">%1$s</xliff:g> перевищив ліміт пам’яті"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Дані динамічної пам’яті зібрано. Торкніться, щоб поділитися"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Поділитися даними динамічної пам’яті?"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index f9e26ca..73a1146 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS پیغامات"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"صوتی میل پیغامات"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi کالنگ"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM کا اسٹیٹس"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"ہمسر نے TTY وضع مکمل کی درخواست کی"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"ہمسر نے TTY وضع HCO کی درخواست کی"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"ہمسر نے TTY وضع VCO کی درخواست کی"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"ترتیبات"</string>
<string name="global_action_assist" msgid="3892832961594295030">"اسسٹ"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"مقفل"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"نئی اطلاع"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ورچوئل کی بورڈ"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"تجویز: زوم ان اور آؤٹ کیلئے دو بار تھپتھپائیں۔"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"آٹوفل"</string>
<string name="setup_autofill" msgid="7103495070180590814">"آٹوفل مقرر کریں"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"آٹو فل"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"، "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"ایپس شروع ہو رہی ہیں۔"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"بوٹ مکمل ہو رہا ہے۔"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> چل رہی ہے"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"ایپ پر سوئچ کرنے کیلئے تھپتھپائیں"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"ایپس سوئچ کریں؟"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"ایک دوسری ایپ پہلے سے چل رہی ہے، جس کا بند ہونا ضروری ہے تاکہ آپ ایک نئی ایپ شروع کر سکیں۔"</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> پر واپس جائیں"</string>
- <string name="old_app_description" msgid="2082094275580358049">"نئی ایپ شروع نہ کریں۔"</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> شروع کریں"</string>
- <string name="new_app_description" msgid="1932143598371537340">"محفوظ کیے بغیر پرانی ایپ بند کریں۔"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> میموری کی حد سے تجاوز کرگئی"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"ہیپ ڈمپ جمع ہو گیا ہے، اشتراک کرنے کیلئے تھپتھپائیں"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"ہیپ ڈمپ کا اشتراک کریں؟"</string>
@@ -1201,12 +1203,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM شامل کیا گیا"</string>
<string name="sim_added_message" msgid="6599945301141050216">"موبائل نیٹ ورک تک رسائی کیلئے اپنا آلہ دوبارہ سٹارٹ کریں۔"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"دوبارہ شروع کریں"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"موبائل سروس فعال کریں"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"اپنا نیا SIM فعال کرنے کیلئے کیریئر ایپ ڈاؤن لوڈ کریں"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"ایپ ڈاؤن لوڈ کریں"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"نئی SIM داخل ہو گئی"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"اسے سیٹ اپ کرنے کیلئے تھپتھپائیں"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"وقت سیٹ کریں"</string>
@@ -1840,6 +1839,6 @@
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانا چاہتی ہے"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"ترمیم کریں"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"سسٹم کی تبدیلیاں"</string>
- <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\'ڈسٹرب نہ کریں\' تبدیل ہو گيا"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\'ڈسٹرب نہ کریں\' تبدیل ہو گيا ہے"</string>
<string name="zen_upgrade_notification_content" msgid="6603123479476554768">"مداخلتوں کے مد نظر اپنے برتاؤ کی ترتیبات چیک کرنے کیلئے تھپتھپائیں"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 735a66c..3d48f84 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Ilovalar ishga tushirilmoqda."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Tizimni yuklashni tugatish."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ishlamoqda"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Ilovaga o‘tish uchun bosing"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Ilovalar almashtirilsinmi?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Boshqa ilova ishlab turibdi. Yangisini ishga tushirishdan oldin avvalgisini yoping."</string>
- <string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g>ga qaytish"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Yangi ilova ishga tushirilmasin."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ni ishga tushirish"</string>
- <string name="new_app_description" msgid="1932143598371537340">"O‘zgarishlarni saqlamasdan, eski ilova yopilsin"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> foydalanish uchun ajratilgan xotira chegarasidan o‘tib ketdi"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Hip-damp yaratildi; uni yuborish uchun bosing"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Hip-damp ma’lumotlari bilan ulashasizmi?"</string>
@@ -1833,7 +1838,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"Zararli ilova aniqlandi"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasi <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatish uchun ruxsat so‘ramoqda"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Tahrirlash"</string>
- <string name="notification_channel_system_changes" msgid="5072715579030948646">"Tizimda o‘zgartirishlar"</string>
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"Tizimga oid o‘zgarishlar"</string>
<string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Bezovta qilinmasin rejimi sozlamalari o‘zgartirildi"</string>
<string name="zen_upgrade_notification_content" msgid="6603123479476554768">"Ularni tekshirish uchun bosing."</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 303ef78..1671cd6 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Tin nhắn SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Thư thoại"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Gọi qua Wi-Fi"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Trạng thái SIM"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ ĐẦY ĐỦ"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ HCO"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ VCO"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"Cài đặt"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Hỗ trợ"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Trợ lý thoại"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"Khóa"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"Thông báo mới"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Bàn phím ảo"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"Mẹo: Nhấn đúp để phóng to và thu nhỏ."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Tự động điền"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Thiết lập Tự động điền"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"Tự động điền"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Khởi động ứng dụng."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Hoàn tất khởi động."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> đang hoạt động"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Nhấn để chuyển sang ứng dụng"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Chuyển đổi ứng dụng?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Bạn phải dừng một ứng dụng khác hiện đang chạy trước khi khởi động một ứng dụng mới."</string>
- <string name="old_app_action" msgid="493129172238566282">"Quay lại <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Không khởi động ứng dụng mới."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Bắt đầu <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Dừng ứng dụng cũ mà không lưu."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> đã vượt quá giới hạn bộ nhớ"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Tệp báo lỗi đã được thu thập; nhấn để chia sẻ"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Chia sẻ tệp báo lỗi?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"Đã thêm thẻ SIM"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Khởi động lại thiết bị của bạn để truy cập mạng di động."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Khởi động lại"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Kích hoạt dịch vụ di động"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Tải xuống ứng dụng của nhà cung cấp dịch vụ để kích hoạt SIM mới"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Tải xuống ứng dụng"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Đã lắp SIM mới"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Nhấn để thiết lập"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Đặt giờ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 2c43023..ff11ef5 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"短信"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"语音邮件"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN 通话"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡状态"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"对方请求使用“TTY 完整”模式"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"对方请求使用“TTY HCO”模式"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"对方请求使用“TTY VCO”模式"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
<string name="global_action_assist" msgid="3892832961594295030">"助理"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"新通知"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"虚拟键盘"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"提示:点按两次可放大或缩小。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自动填充"</string>
<string name="setup_autofill" msgid="7103495070180590814">"设置自动填充"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"自动填充"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在启动应用。"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"即将完成启动。"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>正在运行"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"点按即可切换到应用"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"切换应用吗?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"已有一个应用正在运行,要启动新的应用,您必须先停止该应用。"</string>
- <string name="old_app_action" msgid="493129172238566282">"返回至<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"不启动新的应用。"</string>
- <string name="new_app_action" msgid="5472756926945440706">"启动<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"停止旧的应用,但不保存。"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g>占用的内存已超出限制"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"已收集堆转储数据;点按即可共享"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"要共享堆转储数据吗?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"已添加SIM卡"</string>
<string name="sim_added_message" msgid="6599945301141050216">"请重新启动您的设备,以便访问移动网络。"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"重新启动"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"激活移动网络服务"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"下载运营商应用即可激活您的新 SIM 卡"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"下载应用"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"已插入新 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"点按即可进行设置"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"设置时间"</string>
@@ -1838,7 +1837,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"检测到有害应用"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"“<xliff:g id="APP_0">%1$s</xliff:g>”想要显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"编辑"</string>
- <string name="notification_channel_system_changes" msgid="5072715579030948646">"系统更改"</string>
- <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"“勿扰”设置已更改"</string>
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"系统变更"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"“勿扰”设置有变更"</string>
<string name="zen_upgrade_notification_content" msgid="6603123479476554768">"点按即可查看您的干扰行为设置"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e837ae7..5bf1a37 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"短訊"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"留言訊息"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"對方曾要求 TTY 完整模式"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"對方曾要求 TTY 模式 (HCO)"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"對方曾要求 TTY 模式 (VCO)"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="global_action_assist" msgid="3892832961594295030">"協助"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"語音助手"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"新通知"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"虛擬鍵盤"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"提示:輕按兩下即可放大縮小。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自動填入"</string>
<string name="setup_autofill" msgid="7103495070180590814">"設定自動填入功能"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"自動填入"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在啟動應用程式。"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"啟動完成。"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"正在執行 <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"輕按即可切換至應用程式"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"切換應用程式?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"另一個應用程式已在執行,您必須停止執行該應用程式,才能啟動新的應用程式。"</string>
- <string name="old_app_action" msgid="493129172238566282">"返回 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string>
- <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式,且不儲存。"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> 的記憶體用量已超過限額"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"已收集堆轉儲;輕按即可分享"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"分享堆轉儲?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM 卡已新增"</string>
<string name="sim_added_message" msgid="6599945301141050216">"重新啟動裝置,才能使用流動網絡。"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"重新啟動"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"啟動流動服務"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"下載流動網絡供應商應用程式,即可啟用新 SIM 卡"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"下載應用程式"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"已插入新的 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"輕按即可設定"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"設定時間"</string>
@@ -1838,10 +1837,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"偵測到有害的應用程式"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"「<xliff:g id="APP_0">%1$s</xliff:g>」想顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"編輯"</string>
- <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
- <skip />
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"系統變更"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"請勿騷擾已變更"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"輕按即可查看您的干擾行為設定"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 2bff388..ed24a35 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -93,8 +93,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"簡訊"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"語音留言"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string>
- <!-- no translation found for notification_channel_sim (4052095493875188564) -->
- <skip />
+ <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"通訊對象要求使用 TTY 的 FULL 模式"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"通訊對象要求使用 TTY 的 HCO 模式"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"通訊對象要求使用 TTY 的 VCO 模式"</string>
@@ -240,8 +239,7 @@
<string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="global_action_assist" msgid="3892832961594295030">"協助"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
- <!-- no translation found for global_action_lockdown (1099326950891078929) -->
- <skip />
+ <string name="global_action_lockdown" msgid="1099326950891078929">"鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
<string name="notification_hidden_text" msgid="6351207030447943784">"新通知"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"虛擬鍵盤"</string>
@@ -828,8 +826,7 @@
<string name="double_tap_toast" msgid="4595046515400268881">"提示:輕觸兩下即可縮放。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自動填入功能"</string>
<string name="setup_autofill" msgid="7103495070180590814">"設定自動填入功能"</string>
- <!-- no translation found for autofill_window_title (921006636895825007) -->
- <skip />
+ <string name="autofill_window_title" msgid="921006636895825007">"自動填入"</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" //*** Empty segment here as a separator ***//"</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -1088,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在啟動應用程式。"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"啟動完成。"</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 執行中"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"輕觸即可切換至應用程式"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"切換應用程式?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"其他應用程式已在執行中,你必須停止執行該應用程式,才能啟動新的應用程式。"</string>
- <string name="old_app_action" msgid="493129172238566282">"返回 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string>
- <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式且不儲存。"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> 已超出記憶體上限"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"已取得記憶體快照資料;輕觸即可分享"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"分享記憶體快照資料?"</string>
@@ -1200,12 +1202,9 @@
<string name="sim_added_title" msgid="3719670512889674693">"SIM 卡已新增"</string>
<string name="sim_added_message" msgid="6599945301141050216">"請重新啟動裝置,才能使用行動網路。"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"重新啟動"</string>
- <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
- <skip />
- <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
- <skip />
+ <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"啟用行動服務"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"下載電信業者應用程式以啟用你的新 SIM 卡"</string>
+ <string name="install_carrier_app_notification_button" msgid="3094206295081900849">"下載應用程式"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"已插入新的 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"輕觸這裡即可進行設定"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"設定時間"</string>
@@ -1838,10 +1837,7 @@
<string name="harmful_app_warning_title" msgid="8982527462829423432">"偵測到有害應用程式"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"「<xliff:g id="APP_0">%1$s</xliff:g>」想要顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"編輯"</string>
- <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
- <skip />
- <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
- <skip />
+ <string name="notification_channel_system_changes" msgid="5072715579030948646">"系統變更"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"「零打擾」設定已變更"</string>
+ <string name="zen_upgrade_notification_content" msgid="6603123479476554768">"輕觸即可查看你的干擾行為設定"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e292e3a..74bca25 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1085,13 +1085,18 @@
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinhlelo zokusebenza."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Qedela ukuqala kabusha."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> iyasebenza"</string>
- <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Thepha ukuze ushintshele kuhlelo lokusebenza"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Shintsha izinhlelo zokusebenza?"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Olunye uhlelo lokusebenza luvele luyasebenza lokho kumele kumiswe ngaphambi kokuba uqalise olusha."</string>
- <string name="old_app_action" msgid="493129172238566282">"Buyisela ku:<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali uhlelo lokusebenza entsha."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Qala <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Misa uhlelo lokusebenza endala ngaphandle kokulondoloza."</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
<string name="dump_heap_notification" msgid="2618183274836056542">"I-<xliff:g id="PROC">%1$s</xliff:g> idlule umkhawulo wememori"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Ukulahlwa kwehipu kuqoqiwe; thepha ukuze wabelane"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Yabelana ngokulahlwa kwehipu?"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 96a83f8..ffabdab 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1019,6 +1019,9 @@
<!-- Corner radius of buttons. -->
<attr name="buttonCornerRadius" format="dimension" />
+ <!-- Corner radius of progress bars. -->
+ <attr name="progressBarCornerRadius" format="dimension" />
+
<!-- Style for the search query widget. -->
<attr name="searchViewStyle" format="reference" />
@@ -2113,6 +2116,45 @@
Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR} on
the decor view. -->
<attr name="windowLightNavigationBar" format="boolean" />
+
+ <!-- Controls how the window is laid out if there is a {@code DisplayCutout}.
+ <p>
+ Defaults to {@code default}.
+
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+ @see android.view.DisplayCutout
+ @see android.R.attr#layoutInDisplayCutoutMode -->
+ <attr name="windowLayoutInDisplayCutoutMode">
+ <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the
+ {@code DisplayCutout} is fully contained within the status bar. Otherwise, the window is
+ laid out such that it does not overlap with the {@code DisplayCutout} area.
+
+ @see android.view.DisplayCutout
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ -->
+ <enum name="default" value="0" />
+ <!-- The window is always allowed to extend into the {@code DisplayCutout} area,
+ even if fullscreen or in landscape.
+ <p>
+ The window must make sure that no important content overlaps with the
+ {@link DisplayCutout}.
+
+ @see android.view.DisplayCutout
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ -->
+ <enum name="always" value="1" />
+ <!-- The window is never allowed to overlap with the DisplayCutout area.
+ <p>
+ This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN}
+ to avoid a relayout of the window when the flag is set or cleared.
+
+ @see android.view.DisplayCutout
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+ -->
+ <enum name="never" value="2" />
+ </attr>
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -4472,6 +4514,8 @@
<attr name="textSize" />
<!-- Style (normal, bold, italic, bold|italic) for the text. -->
<attr name="textStyle" />
+ <!-- Weight for the font used in the TextView. -->
+ <attr name="textFontWeight" />
<!-- Typeface (normal, sans, serif, monospace) for the text. -->
<attr name="typeface" />
<!-- Font family (named by string or as a font resource reference) for the text. -->
@@ -4561,6 +4605,8 @@
<attr name="typeface" />
<!-- Style (normal, bold, italic, bold|italic) for the text. -->
<attr name="textStyle" />
+ <!-- Weight for the font used in the TextView. -->
+ <attr name="textFontWeight" />
<!-- Font family (named by string or as a font resource reference) for the text. -->
<attr name="fontFamily" />
<!-- Text color for links. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cfb5784..c4fa190 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2348,6 +2348,16 @@
<attr name="logo" />
<attr name="priority" />
<attr name="autoVerify" />
+ <!-- Within an application, multiple intent filters may match a particular
+ intent. This allows the app author to specify the order filters should
+ be considered. We don't want to use priority because that is global
+ across applications.
+ <p>Only use if you really need to forcibly set the order in which
+ filters are evaluated. It is preferred to target an activity with a
+ directed intent instead.
+ <p>The value is a single integer, with higher numbers considered to
+ be better. If not specified, the default order is 0. -->
+ <attr name="order" />
</declare-styleable>
<!-- Attributes that can be supplied in an AndroidManifest.xml
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index a078d8b..722102e 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -167,8 +167,8 @@
<color name="user_icon_default_white">#ffffffff</color><!-- white -->
<!-- Default profile badge colors -->
- <color name="profile_badge_1">#ffff6d00</color><!-- Orange -->
- <color name="profile_badge_2">#ff000000</color><!-- Black -->
+ <color name="profile_badge_1">#ff1A73E8</color><!-- Blue -->
+ <color name="profile_badge_2">#ffff6d00</color><!-- Orange -->
<color name="profile_badge_3">#ff22f033</color><!-- Green -->
<!-- Default instant app badge color -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3b963d1..f3aa054 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1636,6 +1636,9 @@
<!-- Operating volatage for bluetooth controller. 0 by default-->
<integer translatable="false" name="config_bluetooth_operating_voltage_mv">0</integer>
+ <!-- Max number of connected audio devices supported by Bluetooth stack -->
+ <integer name="config_bluetooth_max_connected_audio_devices">1</integer>
+
<!-- Whether supported profiles should be reloaded upon enabling bluetooth -->
<bool name="config_bluetooth_reload_supported_profiles_when_enabled">false</bool>
@@ -3328,6 +3331,8 @@
<dimen name="config_dialogCornerRadius">2dp</dimen>
<!-- Corner radius of system buttons -->
<dimen name="config_buttonCornerRadius">@dimen/control_corner_material</dimen>
+ <!-- Corner radius of system progress bars -->
+ <dimen name="config_progressBarCornerRadius">@dimen/progress_bar_corner_material</dimen>
<!-- Controls whether system buttons use all caps for text -->
<bool name="config_buttonTextAllCaps">true</bool>
<!-- Name of the font family used for system surfaces where the font should use medium weight -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2ce08eb..7ff96fa 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -32,7 +32,11 @@
<dimen name="toast_y_offset">24dp</dimen>
<!-- Height of the status bar -->
- <dimen name="status_bar_height">24dp</dimen>
+ <dimen name="status_bar_height">@dimen/status_bar_height_portrait</dimen>
+ <!-- Height of the status bar in portrait -->
+ <dimen name="status_bar_height_portrait">24dp</dimen>
+ <!-- Height of the status bar in landscape -->
+ <dimen name="status_bar_height_landscape">@dimen/status_bar_height_portrait</dimen>
<!-- Height of area above QQS where battery/time go -->
<dimen name="quick_qs_offset_height">48dp</dimen>
<!-- Total height of QQS (quick_qs_offset_height + 128) -->
@@ -541,7 +545,7 @@
<!-- Magnifier dimensions -->
<dimen name="magnifier_width">100dp</dimen>
<dimen name="magnifier_height">48dp</dimen>
- <dimen name="magnifier_elevation">2dp</dimen>
+ <dimen name="magnifier_elevation">4dp</dimen>
<dimen name="magnifier_offset">42dp</dimen>
<item type="dimen" format="float" name="magnifier_zoom_scale">1.25</item>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index e3fdcec..210f30e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -135,6 +135,7 @@
<dimen name="seekbar_track_progress_height_material">2dp</dimen>
<dimen name="progress_bar_height_material">4dp</dimen>
+ <dimen name="progress_bar_corner_material">0dp</dimen>
<!-- Material time picker dimensions. -->
<!-- Text size for the time picker header HH:MM label. This value is large
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a5ba4c6..7d5d1ba 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2872,6 +2872,8 @@
<public name="urlBarResourceId" />
<!-- @hide @SystemApi -->
<public name="userRestriction" />
+ <public name="textFontWeight" />
+ <public name="windowLayoutInDisplayCutoutMode" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5c9f863..f38dcea 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -379,7 +379,7 @@
<!-- Text message in the factory reset warning dialog. This says that the the device admin app
is missing or corrupted. As a result the device will be erased. [CHAR LIMIT=NONE]-->
<string name="factory_reset_message">The admin app can\'t be used. Your device will now be
- erased.\n\nIf you have questions, contact your organization's admin.</string>
+ erased.\n\nIf you have questions, contact your organization\'s admin.</string>
<!-- A toast message displayed when printing is attempted but disabled by policy. -->
<string name="printing_disabled_by">Printing disabled by <xliff:g id="owner_app">%s</xliff:g>.</string>
@@ -764,7 +764,7 @@
<string name="capability_title_canCaptureFingerprintGestures">Fingerprint gestures</string>
<!-- Description for the capability of an accessibility service to perform gestures. -->
<string name="capability_desc_canCaptureFingerprintGestures">Can capture gestures performed on
- the device's fingerprint sensor.</string>
+ the device\'s fingerprint sensor.</string>
<!-- Permissions -->
@@ -3320,8 +3320,7 @@
[CHAR LIMIT=NONE] -->
<string name="alert_windows_notification_message">If you don’t want <xliff:g id="name" example="Google Maps">%s</xliff:g> to use this feature, tap to open settings and turn it off.</string>
<!-- Notification action to turn-off app displaying on-top of other apps. [CHAR LIMIT=20] -->
- <string name="alert_windows_notification_turn_off_action">TURN OFF</string>
-
+ <string name="alert_windows_notification_turn_off_action">Turn off</string>
<!-- External media notification strings -->
<skip />
@@ -3775,7 +3774,7 @@
<!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
<string name="data_usage_warning_title">Data warning</string>
<!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_warning_body">You've used <xliff:g id="app" example="3.8GB">%s</xliff:g> of data</string>
+ <string name="data_usage_warning_body">You\'ve used <xliff:g id="app" example="3.8GB">%s</xliff:g> of data</string>
<!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=50] -->
<string name="data_usage_mobile_limit_title">Mobile data limit reached</string>
@@ -3789,7 +3788,7 @@
<!-- Notification title when Wi-Fi data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
<string name="data_usage_wifi_limit_snoozed_title">Over your Wi-Fi data limit</string>
<!-- Notification body when data usage has exceeded limit threshold. -->
- <string name="data_usage_limit_snoozed_body">You've gone <xliff:g id="size" example="3.8GB">%s</xliff:g> over your set limit</string>
+ <string name="data_usage_limit_snoozed_body">You\'ve gone <xliff:g id="size" example="3.8GB">%s</xliff:g> over your set limit</string>
<!-- Notification title when background data usage is limited. [CHAR LIMIT=32] -->
<string name="data_usage_restricted_title">Background data restricted</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a6a3663..3b96861 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -218,6 +218,10 @@
<java-symbol type="id" name="selection_end_handle" />
<java-symbol type="id" name="insertion_handle" />
<java-symbol type="id" name="accessibilityActionClickOnClickableSpan" />
+ <java-symbol type="id" name="camera" />
+ <java-symbol type="id" name="mic" />
+ <java-symbol type="id" name="overlay" />
+ <java-symbol type="id" name="app_ops" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -405,6 +409,7 @@
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+ <java-symbol type="integer" name="config_bluetooth_max_connected_audio_devices" />
<java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
@@ -808,7 +813,6 @@
<java-symbol type="string" name="number_picker_increment_scroll_action" />
<java-symbol type="string" name="number_picker_increment_scroll_mode" />
<java-symbol type="string" name="old_app_action" />
- <java-symbol type="string" name="old_app_description" />
<java-symbol type="string" name="older" />
<java-symbol type="string" name="open_permission_deny" />
<java-symbol type="string" name="orgTypeCustom" />
@@ -1389,6 +1393,9 @@
<java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
<java-symbol type="drawable" name="autofilled_highlight"/>
+ <java-symbol type="drawable" name="ic_camera" />
+ <java-symbol type="drawable" name="ic_mic" />
+ <java-symbol type="drawable" name="ic_alert_window_layer" />
<java-symbol type="drawable" name="ic_account_circle" />
<java-symbol type="color" name="user_icon_1" />
@@ -3238,6 +3245,9 @@
<java-symbol type="string" name="keyguard_accessibility_sim_puk_unlock" />
<java-symbol type="string" name="keyguard_accessibility_password_unlock" />
+ <java-symbol type="dimen" name="status_bar_height_portrait" />
+ <java-symbol type="dimen" name="status_bar_height_landscape" />
+
<java-symbol type="string" name="global_action_logout" />
<java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
<java-symbol type="drawable" name="messaging_user" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 39310a8..cb11d8d 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -126,6 +126,7 @@
<item name="progressBarStyleInverse">@style/Widget.DeviceDefault.ProgressBar.Inverse</item>
<item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
<item name="seekBarStyle">@style/Widget.DeviceDefault.SeekBar</item>
<item name="ratingBarStyle">@style/Widget.DeviceDefault.RatingBar</item>
<item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.RatingBar.Indicator</item>
@@ -227,6 +228,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -247,6 +251,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -269,6 +276,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -290,6 +300,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -319,6 +332,9 @@
<!-- Dialog attributes -->
<item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -339,6 +355,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -358,6 +377,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -378,6 +400,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -414,6 +439,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -435,6 +463,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -454,6 +485,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -475,6 +509,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -495,6 +532,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -515,6 +555,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -535,6 +578,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -555,6 +601,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -575,6 +624,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
@@ -593,6 +645,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -611,6 +666,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -689,6 +747,7 @@
<item name="progressBarStyleInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
<item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
<item name="seekBarStyle">@style/Widget.DeviceDefault.Light.SeekBar</item>
<item name="ratingBarStyle">@style/Widget.DeviceDefault.Light.RatingBar</item>
<item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
@@ -785,6 +844,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -804,6 +866,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -824,6 +889,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -846,6 +914,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -867,6 +938,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -894,6 +968,9 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
@@ -914,6 +991,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -933,6 +1013,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -953,6 +1036,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -999,6 +1085,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -1020,6 +1109,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -1039,6 +1131,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -1060,6 +1155,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -1080,6 +1178,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -1098,6 +1199,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -1116,6 +1220,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
@@ -1147,6 +1254,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -1166,6 +1276,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -1175,6 +1288,9 @@
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -1195,6 +1311,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -1214,6 +1333,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -1233,6 +1355,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -1252,6 +1377,9 @@
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
@@ -1278,6 +1406,9 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
<!-- DeviceDefault theme for the default system theme. -->
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 6ae0ef3..76d9ea6 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -259,6 +259,7 @@
<item name="progressBarStyleInverse">@style/Widget.Material.ProgressBar.Inverse</item>
<item name="progressBarStyleSmallInverse">@style/Widget.Material.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@style/Widget.Material.ProgressBar.Large.Inverse</item>
+ <item name="progressBarCornerRadius">@dimen/progress_bar_corner_material</item>
<item name="seekBarStyle">@style/Widget.Material.SeekBar</item>
<item name="ratingBarStyle">@style/Widget.Material.RatingBar</item>
<item name="ratingBarStyleIndicator">@style/Widget.Material.RatingBar.Indicator</item>
@@ -631,6 +632,7 @@
<item name="progressBarStyleInverse">@style/Widget.Material.Light.ProgressBar.Inverse</item>
<item name="progressBarStyleSmallInverse">@style/Widget.Material.Light.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@style/Widget.Material.Light.ProgressBar.Large.Inverse</item>
+ <item name="progressBarCornerRadius">@dimen/progress_bar_corner_material</item>
<item name="seekBarStyle">@style/Widget.Material.Light.SeekBar</item>
<item name="ratingBarStyle">@style/Widget.Material.Light.RatingBar</item>
<item name="ratingBarStyleIndicator">@style/Widget.Material.Light.RatingBar.Indicator</item>
diff --git a/core/tests/BTtraffic/Android.mk b/core/tests/BTtraffic/Android.mk
index 7d83527..f826ae9 100644
--- a/core/tests/BTtraffic/Android.mk
+++ b/core/tests/BTtraffic/Android.mk
@@ -9,6 +9,7 @@
$(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := bttraffic
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk
index 5ed93f3..8c0a330 100644
--- a/core/tests/ConnectivityManagerTest/Android.mk
+++ b/core/tests/ConnectivityManagerTest/Android.mk
@@ -25,6 +25,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ConnectivityManagerTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/SvcMonitor/Android.mk b/core/tests/SvcMonitor/Android.mk
index 2b80455..94ddccb 100644
--- a/core/tests/SvcMonitor/Android.mk
+++ b/core/tests/SvcMonitor/Android.mk
@@ -9,6 +9,7 @@
$(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := svcmonitor
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
index ff9a0fe..dc80d00 100644
--- a/core/tests/bandwidthtests/Android.mk
+++ b/core/tests/bandwidthtests/Android.mk
@@ -29,6 +29,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := BandwidthTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk
index 744e5b0..bb4e302 100644
--- a/core/tests/bluetoothtests/Android.mk
+++ b/core/tests/bluetoothtests/Android.mk
@@ -11,6 +11,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := BluetoothTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 2ea1b46..2d25c78 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -56,6 +56,7 @@
framework-atb-backward-compatibility \
LOCAL_PACKAGE_NAME := FrameworksCoreTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
index e31d50f..c3af6bd 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
+++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
@@ -21,6 +21,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
index a63cf0e..34016ed 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk
+++ b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
@@ -21,6 +21,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := BinderProxyCountingTestService
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
index 6280257..e04536b 100644
--- a/core/tests/coretests/BstatsTestApp/Android.mk
+++ b/core/tests/coretests/BstatsTestApp/Android.mk
@@ -25,6 +25,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := BstatsTestApp
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/core/tests/coretests/DisabledTestApp/Android.mk b/core/tests/coretests/DisabledTestApp/Android.mk
index a5daedf..e4304f7 100644
--- a/core/tests/coretests/DisabledTestApp/Android.mk
+++ b/core/tests/coretests/DisabledTestApp/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := DisabledTestApp
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/EnabledTestApp/Android.mk b/core/tests/coretests/EnabledTestApp/Android.mk
index 4b986d3..cd37f08 100644
--- a/core/tests/coretests/EnabledTestApp/Android.mk
+++ b/core/tests/coretests/EnabledTestApp/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := EnabledTestApp
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
index 1e03270..8a7d72a5 100644
--- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
+++ b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
@@ -6,6 +6,7 @@
# Make sure every package name gets the FrameworkCoreTests_ prefix.
LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME)
+LOCAL_SDK_VERSION := current
# Every package should have a native library
LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni
diff --git a/core/tests/coretests/assets/fonts/ascent10em-descent10em.ttf b/core/tests/coretests/assets/fonts/ascent10em-descent10em.ttf
new file mode 100644
index 0000000..47ab623
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/ascent10em-descent10em.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/ascent10em-descent10em.ttx b/core/tests/coretests/assets/fonts/ascent10em-descent10em.ttx
new file mode 100644
index 0000000..5540277
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/ascent10em-descent10em.ttx
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="1em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x10000"/>
+ <ascent value="10000"/>
+ <descent value="-10000"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1000" lsb="0"/>
+ <mtx name="1em" width="1000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x000A" name="1em" /> <!-- LINE FEED -->
+ <map code="0x000D" name="1em" /> <!-- CARRIAGE RETURN -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml
index 7a90197..ef3a481 100644
--- a/core/tests/coretests/res/values/styles.xml
+++ b/core/tests/coretests/res/values/styles.xml
@@ -19,4 +19,16 @@
<item name="android:taskToBackEnterAnimation">@null</item>
<item name="android:taskToBackExitAnimation">@null</item>
</style>
+
+ <style name="LayoutInDisplayCutoutModeUnset">
+ </style>
+ <style name="LayoutInDisplayCutoutModeDefault">
+ <item name="android:windowLayoutInDisplayCutoutMode">default</item>
+ </style>
+ <style name="LayoutInDisplayCutoutModeAlways">
+ <item name="android:windowLayoutInDisplayCutoutMode">always</item>
+ </style>
+ <style name="LayoutInDisplayCutoutModeNever">
+ <item name="android:windowLayoutInDisplayCutoutMode">never</item>
+ </style>
</resources>
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index e575650..3eefc36 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -24,6 +24,9 @@
import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+
+import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -48,6 +51,10 @@
import org.mockito.InOrder;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
/** Test {@link TransactionExecutor} logic. */
@RunWith(AndroidJUnit4.class)
@@ -56,6 +63,7 @@
public class TransactionExecutorTests {
private TransactionExecutor mExecutor;
+ private TransactionExecutorHelper mExecutorHelper;
private ClientTransactionHandler mTransactionHandler;
private ActivityClientRecord mClientRecord;
@@ -67,6 +75,7 @@
when(mTransactionHandler.getActivityClient(any())).thenReturn(mClientRecord);
mExecutor = spy(new TransactionExecutor(mTransactionHandler));
+ mExecutorHelper = new TransactionExecutorHelper();
}
@Test
@@ -166,10 +175,42 @@
pathExcludeLast(ON_DESTROY));
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testLifecycleUndefinedStartState() {
+ mClientRecord.setState(UNDEFINED);
+ path(ON_CREATE);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testLifecycleUndefinedFinishState() {
+ mClientRecord.setState(PRE_ON_CREATE);
+ path(UNDEFINED);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testLifecycleInvalidPreOnCreateFinishState() {
+ mClientRecord.setState(ON_CREATE);
+ path(PRE_ON_CREATE);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testLifecycleInvalidOnRestartStartState() {
+ mClientRecord.setState(ON_RESTART);
+ path(ON_RESUME);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testLifecycleInvalidOnRestartFinishState() {
+ mClientRecord.setState(ON_CREATE);
+ path(ON_RESTART);
+ }
+
@Test
public void testTransactionResolution() {
ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
+ when(callback1.getPostExecutionState()).thenReturn(UNDEFINED);
ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
+ when(callback2.getPostExecutionState()).thenReturn(UNDEFINED);
ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
IBinder token = mock(IBinder.class);
@@ -189,7 +230,7 @@
}
@Test
- public void testRequiredStateResolution() {
+ public void testActivityResultRequiredStateResolution() {
ActivityResultItem activityResultItem = ActivityResultItem.obtain(new ArrayList<>());
IBinder token = mock(IBinder.class);
@@ -197,20 +238,161 @@
token /* activityToken */);
transaction.addCallback(activityResultItem);
+ // Verify resolution that should get to onPause
+ mClientRecord.setState(ON_RESUME);
mExecutor.executeCallbacks(transaction);
-
verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_PAUSE));
+
+ // Verify resolution that should get to onStart
+ mClientRecord.setState(ON_STOP);
+ mExecutor.executeCallbacks(transaction);
+ verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_START));
+ }
+
+ @Test
+ public void testClosestStateResolutionForSameState() {
+ final int[] allStates = new int[] {
+ ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY};
+
+ mClientRecord.setState(ON_CREATE);
+ assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord,
+ shuffledArray(allStates)));
+
+ mClientRecord.setState(ON_START);
+ assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord,
+ shuffledArray(allStates)));
+
+ mClientRecord.setState(ON_RESUME);
+ assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord,
+ shuffledArray(allStates)));
+
+ mClientRecord.setState(ON_PAUSE);
+ assertEquals(ON_PAUSE, mExecutorHelper.getClosestOfStates(mClientRecord,
+ shuffledArray(allStates)));
+
+ mClientRecord.setState(ON_STOP);
+ assertEquals(ON_STOP, mExecutorHelper.getClosestOfStates(mClientRecord,
+ shuffledArray(allStates)));
+
+ mClientRecord.setState(ON_DESTROY);
+ assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord,
+ shuffledArray(allStates)));
+
+ mClientRecord.setState(PRE_ON_CREATE);
+ assertEquals(PRE_ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord,
+ new int[] {PRE_ON_CREATE}));
+ }
+
+ @Test
+ public void testClosestStateResolution() {
+ mClientRecord.setState(PRE_ON_CREATE);
+ assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_PAUSE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_PAUSE, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_STOP, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_STOP, ON_DESTROY})));
+ assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_DESTROY})));
+ }
+
+ @Test
+ public void testClosestStateResolutionFromOnCreate() {
+ mClientRecord.setState(ON_CREATE);
+ assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY})));
+ }
+
+ @Test
+ public void testClosestStateResolutionFromOnStart() {
+ mClientRecord.setState(ON_START);
+ assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE})));
+ }
+
+ @Test
+ public void testClosestStateResolutionFromOnResume() {
+ mClientRecord.setState(ON_RESUME);
+ assertEquals(ON_PAUSE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START, ON_PAUSE, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_DESTROY})));
+ assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START})));
+ assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE})));
+ }
+
+ @Test
+ public void testClosestStateResolutionFromOnPause() {
+ mClientRecord.setState(ON_PAUSE);
+ assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START, ON_RESUME, ON_DESTROY})));
+ assertEquals(ON_STOP, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START, ON_STOP, ON_DESTROY})));
+ assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START})));
+ assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE})));
+ }
+
+ @Test
+ public void testClosestStateResolutionFromOnStop() {
+ mClientRecord.setState(ON_STOP);
+ assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_RESUME, ON_PAUSE, ON_DESTROY})));
+ assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_DESTROY})));
+ assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE})));
+ }
+
+ @Test
+ public void testClosestStateResolutionFromOnDestroy() {
+ mClientRecord.setState(ON_DESTROY);
+ assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray(
+ new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP})));
+ }
+
+ @Test
+ public void testClosestStateResolutionToUndefined() {
+ mClientRecord.setState(ON_CREATE);
+ assertEquals(UNDEFINED,
+ mExecutorHelper.getClosestPreExecutionState(mClientRecord, UNDEFINED));
+ }
+
+ @Test
+ public void testClosestStateResolutionToOnResume() {
+ mClientRecord.setState(ON_DESTROY);
+ assertEquals(ON_START,
+ mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME));
+ mClientRecord.setState(ON_START);
+ assertEquals(ON_START,
+ mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME));
+ mClientRecord.setState(ON_PAUSE);
+ assertEquals(ON_PAUSE,
+ mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME));
+ }
+
+ private static int[] shuffledArray(int[] inputArray) {
+ final List<Integer> list = Arrays.stream(inputArray).boxed().collect(Collectors.toList());
+ Collections.shuffle(list);
+ return list.stream().mapToInt(Integer::intValue).toArray();
}
private int[] path(int finish) {
- mExecutor.initLifecyclePath(mClientRecord.getLifecycleState(), finish,
- false /* excludeLastState */);
- return mExecutor.getLifecycleSequence();
+ return mExecutorHelper.getLifecyclePath(mClientRecord.getLifecycleState(), finish,
+ false /* excludeLastState */).toArray();
}
private int[] pathExcludeLast(int finish) {
- mExecutor.initLifecyclePath(mClientRecord.getLifecycleState(), finish,
- true /* excludeLastState */);
- return mExecutor.getLifecycleSequence();
+ return mExecutorHelper.getLifecyclePath(mClientRecord.getLifecycleState(), finish,
+ true /* excludeLastState */).toArray();
}
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index be2c235..d6580d6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -314,6 +314,8 @@
Settings.Global.NTP_SERVER,
Settings.Global.NTP_TIMEOUT,
Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
+ Settings.Global.OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED,
+ Settings.Global.OFF_BODY_RADIOS_OFF_DELAY_MS,
Settings.Global.OVERLAY_DISPLAY_DEVICES,
Settings.Global.PAC_CHANGE_DELAY,
Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
@@ -524,6 +526,7 @@
Settings.Secure.NFC_PAYMENT_FOREGROUND,
Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
Settings.Secure.PACKAGE_VERIFIER_STATE,
Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index d817278..2521712 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -822,6 +822,9 @@
+ " <family>"
+ " <font weight='400' style='normal'>ascent3em-descent4em.ttf</font>"
+ " </family>"
+ + " <family>"
+ + " <font weight='400' style='normal'>ascent10em-descent10em.ttf</font>"
+ + " </family>"
+ "</familyset>";
try (FontFallbackSetup setup =
@@ -833,7 +836,7 @@
assertEquals(2 * textSize, paint.descent(), 0.0f);
final int paraWidth = 5 * textSize;
- final String text = "aaaaa aabaa aaaaa"; // This should result in three lines.
+ final String text = "aaaaa\naabaa\naaaaa\n"; // This should result in three lines.
// Old line spacing. All lines should get their ascent and descents from the first font.
StaticLayout layout = StaticLayout.Builder
@@ -841,13 +844,17 @@
.setIncludePad(false)
.setUseLineSpacingFromFallbacks(false)
.build();
- assertEquals(3, layout.getLineCount());
+ assertEquals(4, layout.getLineCount());
assertEquals(-textSize, layout.getLineAscent(0));
assertEquals(2 * textSize, layout.getLineDescent(0));
assertEquals(-textSize, layout.getLineAscent(1));
assertEquals(2 * textSize, layout.getLineDescent(1));
assertEquals(-textSize, layout.getLineAscent(2));
assertEquals(2 * textSize, layout.getLineDescent(2));
+ // The last empty line spacing should be the default line spacing.
+ // Maybe good to be a previous line spacing?
+ assertEquals(-textSize, layout.getLineAscent(3));
+ assertEquals(2 * textSize, layout.getLineDescent(3));
// New line spacing. The second line has a 'b', so it needs more ascent and descent.
layout = StaticLayout.Builder
@@ -855,26 +862,52 @@
.setIncludePad(false)
.setUseLineSpacingFromFallbacks(true)
.build();
- assertEquals(3, layout.getLineCount());
+ assertEquals(4, layout.getLineCount());
assertEquals(-textSize, layout.getLineAscent(0));
assertEquals(2 * textSize, layout.getLineDescent(0));
assertEquals(-3 * textSize, layout.getLineAscent(1));
assertEquals(4 * textSize, layout.getLineDescent(1));
assertEquals(-textSize, layout.getLineAscent(2));
assertEquals(2 * textSize, layout.getLineDescent(2));
+ assertEquals(-textSize, layout.getLineAscent(3));
+ assertEquals(2 * textSize, layout.getLineDescent(3));
// The default is the old line spacing, for backward compatibility.
layout = StaticLayout.Builder
.obtain(text, 0, text.length(), paint, paraWidth)
.setIncludePad(false)
.build();
- assertEquals(3, layout.getLineCount());
+ assertEquals(4, layout.getLineCount());
assertEquals(-textSize, layout.getLineAscent(0));
assertEquals(2 * textSize, layout.getLineDescent(0));
assertEquals(-textSize, layout.getLineAscent(1));
assertEquals(2 * textSize, layout.getLineDescent(1));
assertEquals(-textSize, layout.getLineAscent(2));
assertEquals(2 * textSize, layout.getLineDescent(2));
+ assertEquals(-textSize, layout.getLineAscent(3));
+ assertEquals(2 * textSize, layout.getLineDescent(3));
+
+ layout = StaticLayout.Builder
+ .obtain("\n", 0, 1, paint, textSize)
+ .setIncludePad(false)
+ .setUseLineSpacingFromFallbacks(false)
+ .build();
+ assertEquals(2, layout.getLineCount());
+ assertEquals(-textSize, layout.getLineAscent(0));
+ assertEquals(2 * textSize, layout.getLineDescent(0));
+ assertEquals(-textSize, layout.getLineAscent(1));
+ assertEquals(2 * textSize, layout.getLineDescent(1));
+
+ layout = StaticLayout.Builder
+ .obtain("\n", 0, 1, paint, textSize)
+ .setIncludePad(false)
+ .setUseLineSpacingFromFallbacks(true)
+ .build();
+ assertEquals(2, layout.getLineCount());
+ assertEquals(-textSize, layout.getLineAscent(0));
+ assertEquals(2 * textSize, layout.getLineDescent(0));
+ assertEquals(-textSize, layout.getLineAscent(1));
+ assertEquals(2 * textSize, layout.getLineDescent(1));
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
new file mode 100644
index 0000000..54007fb
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextClassificationConstantsTest {
+
+ @Test
+ public void testLoadFromString() {
+ final String s = "local_textclassifier_enabled=true,"
+ + "system_textclassifier_enabled=true,"
+ + "model_dark_launch_enabled=true,"
+ + "smart_selection_enabled=true,"
+ + "smart_text_share_enabled=true,"
+ + "smart_linkify_enabled=true,"
+ + "smart_select_animation_enabled=true,"
+ + "suggest_selection_max_range_length=10,"
+ + "classify_text_max_range_length=11,"
+ + "generate_links_max_text_length=12,"
+ + "generate_links_log_sample_rate=13";
+ final TextClassificationConstants constants =
+ TextClassificationConstants.loadFromString(s);
+ assertTrue("local_textclassifier_enabled",
+ constants.isLocalTextClassifierEnabled());
+ assertTrue("system_textclassifier_enabled",
+ constants.isSystemTextClassifierEnabled());
+ assertTrue("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
+ assertTrue("smart_selection_enabled", constants.isSmartSelectionEnabled());
+ assertTrue("smart_text_share_enabled", constants.isSmartTextShareEnabled());
+ assertTrue("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
+ assertTrue("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled());
+ assertEquals("suggest_selection_max_range_length",
+ 10, constants.getSuggestSelectionMaxRangeLength());
+ assertEquals("classify_text_max_range_length",
+ 11, constants.getClassifyTextMaxRangeLength());
+ assertEquals("generate_links_max_text_length",
+ 12, constants.getGenerateLinksMaxTextLength());
+ assertEquals("generate_links_log_sample_rate",
+ 13, constants.getGenerateLinksLogSampleRate());
+ }
+
+ @Test
+ public void testLoadFromString_differentValues() {
+ final String s = "local_textclassifier_enabled=false,"
+ + "system_textclassifier_enabled=false,"
+ + "model_dark_launch_enabled=false,"
+ + "smart_selection_enabled=false,"
+ + "smart_text_share_enabled=false,"
+ + "smart_linkify_enabled=false,"
+ + "smart_select_animation_enabled=false,"
+ + "suggest_selection_max_range_length=8,"
+ + "classify_text_max_range_length=7,"
+ + "generate_links_max_text_length=6,"
+ + "generate_links_log_sample_rate=5";
+ final TextClassificationConstants constants =
+ TextClassificationConstants.loadFromString(s);
+ assertFalse("local_textclassifier_enabled",
+ constants.isLocalTextClassifierEnabled());
+ assertFalse("system_textclassifier_enabled",
+ constants.isSystemTextClassifierEnabled());
+ assertFalse("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
+ assertFalse("smart_selection_enabled", constants.isSmartSelectionEnabled());
+ assertFalse("smart_text_share_enabled", constants.isSmartTextShareEnabled());
+ assertFalse("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
+ assertFalse("smart_select_animation_enabled",
+ constants.isSmartSelectionAnimationEnabled());
+ assertEquals("suggest_selection_max_range_length",
+ 8, constants.getSuggestSelectionMaxRangeLength());
+ assertEquals("classify_text_max_range_length",
+ 7, constants.getClassifyTextMaxRangeLength());
+ assertEquals("generate_links_max_text_length",
+ 6, constants.getGenerateLinksMaxTextLength());
+ assertEquals("generate_links_log_sample_rate",
+ 5, constants.getGenerateLinksLogSampleRate());
+ }
+
+ @Test
+ public void testEntityListParsing() {
+ final TextClassificationConstants constants = TextClassificationConstants.loadFromString(
+ "entity_list_default=phone,"
+ + "entity_list_not_editable=address:flight,"
+ + "entity_list_editable=date:datetime");
+ assertEquals(1, constants.getEntityListDefault().size());
+ assertEquals("phone", constants.getEntityListDefault().get(0));
+ assertEquals(2, constants.getEntityListNotEditable().size());
+ assertEquals("address", constants.getEntityListNotEditable().get(0));
+ assertEquals("flight", constants.getEntityListNotEditable().get(1));
+ assertEquals(2, constants.getEntityListEditable().size());
+ assertEquals("date", constants.getEntityListEditable().get(0));
+ assertEquals("datetime", constants.getEntityListEditable().get(1));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 5407ce6..57db153 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -22,7 +22,9 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import android.content.Context;
import android.os.LocaleList;
+import android.service.textclassifier.TextClassifierService;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -44,6 +46,7 @@
private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
private static final String NO_TYPE = null;
+ private Context mContext;
private TextClassificationManager mTcm;
private TextClassifier mClassifier;
private TextSelection.Options mSelectionOptions;
@@ -52,8 +55,8 @@
@Before
public void setup() {
- mTcm = InstrumentationRegistry.getTargetContext()
- .getSystemService(TextClassificationManager.class);
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTcm = mContext.getSystemService(TextClassificationManager.class);
mTcm.setTextClassifier(null);
mClassifier = mTcm.getTextClassifier();
mSelectionOptions = new TextSelection.Options().setDefaultLocales(LOCALES);
@@ -282,6 +285,18 @@
assertEquals(classifier, mTcm.getTextClassifier());
}
+ @Test
+ public void testGetLocalTextClassifier() {
+ assertTrue(mTcm.getTextClassifier(TextClassifier.LOCAL) instanceof TextClassifierImpl);
+ }
+
+ @Test
+ public void testGetSystemTextClassifier() {
+ assertTrue(
+ TextClassifierService.getServiceComponentName(mContext) == null
+ || mTcm.getTextClassifier(TextClassifier.SYSTEM) instanceof SystemTextClassifier);
+ }
+
private boolean isTextClassifierDisabled() {
return mClassifier == TextClassifier.NO_OP;
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java
deleted file mode 100644
index 984eede..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 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.view.textclassifier;
-
-import static org.junit.Assert.assertEquals;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TextClassifierConstantsTest {
-
- @Test
- public void testEntityListParsing() {
- final TextClassifierConstants constants = TextClassifierConstants.loadFromString(
- "entity_list_default=phone,"
- + "entity_list_not_editable=address:flight,"
- + "entity_list_editable=date:datetime");
- assertEquals(1, constants.getEntityListDefault().size());
- assertEquals("phone", constants.getEntityListDefault().get(0));
- assertEquals(2, constants.getEntityListNotEditable().size());
- assertEquals("address", constants.getEntityListNotEditable().get(0));
- assertEquals("flight", constants.getEntityListNotEditable().get(1));
- assertEquals(2, constants.getEntityListEditable().size());
- assertEquals("date", constants.getEntityListEditable().get(0));
- assertEquals("datetime", constants.getEntityListEditable().get(1));
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 449e374..a15d337 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -398,6 +398,17 @@
}
@Test
+ public void testOnAccessibilityShortcut_forServiceWithNoSummary_doesNotCrash()
+ throws Exception {
+ configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+ configureValidShortcutService();
+ when(mServiceInfo.loadSummary(any())).thenReturn(null);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ getController().performAccessibilityShortcut();
+ verify(mAccessibilityManagerService).performAccessibilityShortcut();
+ }
+
+ @Test
public void testOnAccessibilityShortcut_forFrameworkFeature_callsServiceWithNoToast()
throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
new file mode 100644
index 0000000..c8994dd
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 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.internal.policy;
+
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ActionMode;
+import android.view.ContextThemeWrapper;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
+ */
+@SmallTest
+@Presubmit
+@FlakyTest(detail = "Promote to presubmit once monitored to be stable.")
+@RunWith(AndroidJUnit4.class)
+public final class PhoneWindowTest {
+
+ private PhoneWindow mPhoneWindow;
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @Test
+ public void layoutInDisplayCutoutMode_unset() throws Exception {
+ createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeUnset);
+ installDecor();
+
+ assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+ is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT));
+ }
+
+ @Test
+ public void layoutInDisplayCutoutMode_default() throws Exception {
+ createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeDefault);
+ installDecor();
+
+ assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+ is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT));
+ }
+
+ @Test
+ public void layoutInDisplayCutoutMode_always() throws Exception {
+ createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeAlways);
+ installDecor();
+
+ assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+ is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS));
+ }
+
+ @Test
+ public void layoutInDisplayCutoutMode_never() throws Exception {
+ createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeNever);
+ installDecor();
+
+ assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+ is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER));
+ }
+
+ private void createPhoneWindowWithTheme(int theme) {
+ mPhoneWindow = new PhoneWindow(new ContextThemeWrapper(mContext, theme));
+ }
+
+ private void installDecor() {
+ mPhoneWindow.getDecorView();
+ }
+}
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
index 1d9f624..cba9cbd 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
@@ -24,6 +24,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := DownloadManagerTestApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
ifneq ($(TARGET_BUILD_VARIANT),user)
# Need to run as system app to get access to Settings. This test won't work for user builds.
diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk
index 30c2dca..73ee8b8 100644
--- a/core/tests/notificationtests/Android.mk
+++ b/core/tests/notificationtests/Android.mk
@@ -10,6 +10,9 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := NotificationStressTests
+# Could build against SDK if it wasn't for the @RepetitiveTest annotation.
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
LOCAL_STATIC_JAVA_LIBRARIES := \
junit \
diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk
index 4ca3e4c..680ebeb 100644
--- a/core/tests/overlaytests/device/Android.mk
+++ b/core/tests/overlaytests/device/Android.mk
@@ -18,6 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayDeviceTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_TARGET_REQUIRED_MODULES := \
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
index 17e20ee..edad4b2 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
index c24bea9..3fae8e1 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
index dc811c5..c352c05 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
index 4249549..3d2410d 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_BadSignatureOverlay
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad
include $(BUILD_PACKAGE)
@@ -26,6 +27,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static
@@ -34,6 +36,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index d26425b..ab3faf0 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -18,6 +18,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
include $(BUILD_PACKAGE)
@@ -27,6 +28,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
@@ -38,6 +40,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
@@ -51,6 +54,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
@@ -62,6 +66,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
diff --git a/core/tests/packagemanagertests/Android.mk b/core/tests/packagemanagertests/Android.mk
index 5bfde78..f95231f 100644
--- a/core/tests/packagemanagertests/Android.mk
+++ b/core/tests/packagemanagertests/Android.mk
@@ -15,6 +15,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCorePackageManagerTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/privacytests/Android.mk b/core/tests/privacytests/Android.mk
index 7bba417..374d0d0 100644
--- a/core/tests/privacytests/Android.mk
+++ b/core/tests/privacytests/Android.mk
@@ -12,6 +12,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksPrivacyLibraryTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index 57e2059..3458be0 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -12,6 +12,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index 2dc1059..5c60c81 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -22,6 +22,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
LOCAL_PACKAGE_NAME := FrameworksUtilTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
diff --git a/graphics/java/android/graphics/EmbossMaskFilter.java b/graphics/java/android/graphics/EmbossMaskFilter.java
index a9e180f..003678a 100644
--- a/graphics/java/android/graphics/EmbossMaskFilter.java
+++ b/graphics/java/android/graphics/EmbossMaskFilter.java
@@ -20,12 +20,15 @@
/**
* Create an emboss maskfilter
*
+ * @deprecated This subclass is not supported and should not be instantiated.
+ *
* @param direction array of 3 scalars [x, y, z] specifying the direction of the light source
* @param ambient 0...1 amount of ambient light
* @param specular coefficient for specular highlights (e.g. 8)
* @param blurRadius amount to blur before applying lighting (e.g. 3)
* @return the emboss maskfilter
*/
+ @Deprecated
public EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) {
if (direction.length < 3) {
throw new ArrayIndexOutOfBoundsException();
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 3cca47b..5abd31a 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -19,6 +19,8 @@
import static android.system.OsConstants.SEEK_CUR;
import static android.system.OsConstants.SEEK_SET;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,32 +30,28 @@
import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Resources;
import android.graphics.drawable.AnimatedImageDrawable;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
-import android.util.Size;
import android.system.ErrnoException;
import android.system.Os;
import android.util.DisplayMetrics;
+import android.util.Size;
import android.util.TypedValue;
-import libcore.io.IoUtils;
import dalvik.system.CloseGuard;
-import java.nio.ByteBuffer;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.ArrayIndexOutOfBoundsException;
-import java.lang.AutoCloseable;
-import java.lang.NullPointerException;
-import java.lang.RuntimeException;
import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -494,7 +492,7 @@
private int mAllocator = ALLOCATOR_DEFAULT;
private boolean mRequireUnpremultiplied = false;
private boolean mMutable = false;
- private boolean mPreferRamOverQuality = false;
+ private boolean mConserveMemory = false;
private boolean mAsAlphaMask = false;
private Rect mCropRect;
private Rect mOutPaddingRect;
@@ -623,16 +621,18 @@
/**
* Create a new {@link Source} from a {@link java.nio.ByteBuffer}.
*
- * <p>The returned {@link Source} effectively takes ownership of the
- * {@link java.nio.ByteBuffer}; i.e. no other code should modify it after
- * this call.</p>
+ * <p>Decoding will start from {@link java.nio.ByteBuffer#position()}. The
+ * position of {@code buffer} will not be affected.</p>
*
- * Decoding will start from {@link java.nio.ByteBuffer#position()}. The
- * position after decoding is undefined.
+ * <p>Note: If this {@code Source} is passed to {@link #decodeDrawable}, and
+ * the encoded image is animated, the returned {@link AnimatedImageDrawable}
+ * will continue reading from the {@code buffer}, so its contents must not
+ * be modified, even after the {@code AnimatedImageDrawable} is returned.
+ * {@code buffer}'s contents should never be modified during decode.</p>
*/
@NonNull
public static Source createSource(@NonNull ByteBuffer buffer) {
- return new ByteBufferSource(buffer);
+ return new ByteBufferSource(buffer.slice());
}
/**
@@ -692,8 +692,9 @@
*
* @param width must be greater than 0.
* @param height must be greater than 0.
+ * @return this object for chaining.
*/
- public void setResize(int width, int height) {
+ public ImageDecoder setResize(int width, int height) {
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Dimensions must be positive! "
+ "provided (" + width + ", " + height + ")");
@@ -701,6 +702,7 @@
mDesiredWidth = width;
mDesiredHeight = height;
+ return this;
}
/**
@@ -710,10 +712,11 @@
* {@link #getSampledSize} to {@link #setResize(int, int)}.</p>
*
* @param sampleSize Sampling rate of the encoded image.
+ * @return this object for chaining.
*/
- public void setResize(int sampleSize) {
+ public ImageDecoder setResize(int sampleSize) {
Size size = this.getSampledSize(sampleSize);
- this.setResize(size.getWidth(), size.getHeight());
+ return this.setResize(size.getWidth(), size.getHeight());
}
private boolean requestedResize() {
@@ -758,8 +761,9 @@
/** @hide **/
@Retention(SOURCE)
- @IntDef({ ALLOCATOR_DEFAULT, ALLOCATOR_SOFTWARE, ALLOCATOR_SHARED_MEMORY,
- ALLOCATOR_HARDWARE })
+ @IntDef(value = { ALLOCATOR_DEFAULT, ALLOCATOR_SOFTWARE,
+ ALLOCATOR_SHARED_MEMORY, ALLOCATOR_HARDWARE },
+ prefix = {"ALLOCATOR_"})
public @interface Allocator {};
/**
@@ -768,18 +772,20 @@
* This is ignored for animated drawables.
*
* @param allocator Type of allocator to use.
+ * @return this object for chaining.
*/
- public void setAllocator(@Allocator int allocator) {
+ public ImageDecoder setAllocator(@Allocator int allocator) {
if (allocator < ALLOCATOR_DEFAULT || allocator > ALLOCATOR_HARDWARE) {
throw new IllegalArgumentException("invalid allocator " + allocator);
}
mAllocator = allocator;
+ return this;
}
/**
* Specify whether the {@link Bitmap} should have unpremultiplied pixels.
*
- * By default, ImageDecoder will create a {@link Bitmap} with
+ * <p>By default, ImageDecoder will create a {@link Bitmap} with
* premultiplied pixels, which is required for drawing with the
* {@link android.view.View} system (i.e. to a {@link Canvas}). Calling
* this method with a value of {@code true} will result in
@@ -787,9 +793,13 @@
* pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with
* {@link #decodeDrawable}; attempting to decode an unpremultiplied
* {@link Drawable} will throw an {@link java.lang.IllegalStateException}.
+ * </p>
+ *
+ * @return this object for chaining.
*/
- public void setRequireUnpremultiplied(boolean requireUnpremultiplied) {
+ public ImageDecoder setRequireUnpremultiplied(boolean requireUnpremultiplied) {
mRequireUnpremultiplied = requireUnpremultiplied;
+ return this;
}
/**
@@ -804,19 +814,25 @@
* <p>For an animated image, the drawing commands drawn on the
* {@link Canvas} will be recorded immediately and then applied to each
* frame.</p>
+ *
+ * @return this object for chaining.
*/
- public void setPostProcessor(@Nullable PostProcessor p) {
+ public ImageDecoder setPostProcessor(@Nullable PostProcessor p) {
mPostProcessor = p;
+ return this;
}
/**
* Set (replace) the {@link OnPartialImageListener} on this object.
*
- * Will be called if there is an error in the input. Without one, a
- * partial {@link Bitmap} will be created.
+ * <p>Will be called if there is an error in the input. Without one, an
+ * error will result in an Exception being thrown.</p>
+ *
+ * @return this object for chaining.
*/
- public void setOnPartialImageListener(@Nullable OnPartialImageListener l) {
+ public ImageDecoder setOnPartialImageListener(@Nullable OnPartialImageListener l) {
mOnPartialImageListener = l;
+ return this;
}
/**
@@ -830,9 +846,12 @@
* <p>NOT intended as a replacement for
* {@link BitmapRegionDecoder#decodeRegion}. This supports all formats,
* but merely crops the output.</p>
+ *
+ * @return this object for chaining.
*/
- public void setCrop(@Nullable Rect subset) {
+ public ImageDecoder setCrop(@Nullable Rect subset) {
mCropRect = subset;
+ return this;
}
/**
@@ -841,10 +860,13 @@
* If the image is a nine patch, this Rect will be set to the padding
* rectangle during decode. Otherwise it will not be modified.
*
+ * @return this object for chaining.
+ *
* @hide
*/
- public void setOutPaddingRect(@NonNull Rect outPadding) {
+ public ImageDecoder setOutPaddingRect(@NonNull Rect outPadding) {
mOutPaddingRect = outPadding;
+ return this;
}
/**
@@ -862,21 +884,31 @@
* which would require retrieving the Bitmap from the returned Drawable in
* order to modify. Attempting to decode a mutable {@link Drawable} will
* throw an {@link java.lang.IllegalStateException}.</p>
+ *
+ * @return this object for chaining.
*/
- public void setMutable(boolean mutable) {
+ public ImageDecoder setMutable(boolean mutable) {
mMutable = mutable;
+ return this;
}
/**
* Specify whether to potentially save RAM at the expense of quality.
*
- * Setting this to {@code true} may result in a {@link Bitmap} with a
- * denser {@link Bitmap.Config}, depending on the image. For example, for
- * an opaque {@link Bitmap}, this may result in a {@link Bitmap.Config}
- * with no alpha information.
+ * <p>Setting this to {@code true} may result in a {@link Bitmap} with a
+ * denser {@link Bitmap.Config}, depending on the image. For example, an
+ * opaque {@link Bitmap} with 8 bits or precision for each of its red,
+ * green and blue components would decode to
+ * {@link Bitmap.Config#ARGB_8888} by default, but setting this to
+ * {@code true} will result in decoding to {@link Bitmap.Config#RGB_565}.
+ * This necessarily lowers the quality of the output, but saves half
+ * the memory used.</p>
+ *
+ * @return this object for chaining.
*/
- public void setPreferRamOverQuality(boolean preferRamOverQuality) {
- mPreferRamOverQuality = preferRamOverQuality;
+ public ImageDecoder setConserveMemory(boolean conserveMemory) {
+ mConserveMemory = conserveMemory;
+ return this;
}
/**
@@ -890,9 +922,12 @@
* combine them will result in {@link #decodeDrawable}/
* {@link #decodeBitmap} throwing an
* {@link java.lang.IllegalStateException}.</p>
+ *
+ * @return this object for chaining.
*/
- public void setAsAlphaMask(boolean asAlphaMask) {
+ public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
mAsAlphaMask = asAlphaMask;
+ return this;
}
@Override
@@ -957,7 +992,7 @@
return nDecodeBitmap(mNativePtr, partialImagePtr,
postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
- mPreferRamOverQuality, mAsAlphaMask);
+ mConserveMemory, mAsAlphaMask);
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1171,7 +1206,7 @@
int width, int height,
@Nullable Rect cropRect, boolean mutable,
int allocator, boolean requireUnpremul,
- boolean preferRamOverQuality, boolean asAlphaMask)
+ boolean conserveMemory, boolean asAlphaMask)
throws IOException;
private static native Size nGetSampledSize(long nativePtr,
int sampleSize);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 8595165..38beebd 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -21,6 +21,7 @@
import static android.content.res.FontResourcesParser.FontFileResourceEntry;
import static android.content.res.FontResourcesParser.ProviderResourceEntry;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -49,6 +50,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
@@ -117,6 +120,11 @@
*/
public long native_instance;
+ /** @hide */
+ @IntDef(value = {NORMAL, BOLD, ITALIC, BOLD_ITALIC})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Style {}
+
// Style
public static final int NORMAL = 0;
public static final int BOLD = 1;
@@ -124,8 +132,15 @@
public static final int BOLD_ITALIC = 3;
/** @hide */ public static final int STYLE_MASK = 0x03;
- private int mStyle = 0;
- private int mWeight = 0;
+ private @Style int mStyle = 0;
+
+ /**
+ * A maximum value for the weight value.
+ * @hide
+ */
+ public static final int MAX_WEIGHT = 1000;
+
+ private @IntRange(from = 0, to = MAX_WEIGHT) int mWeight = 0;
// Value for weight and italic. Indicates the value is resolved by font metadata.
// Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -153,7 +168,7 @@
}
/** Returns the typeface's intrinsic style attributes */
- public int getStyle() {
+ public @Style int getStyle() {
return mStyle;
}
@@ -659,7 +674,7 @@
* e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
* @return The best matching typeface.
*/
- public static Typeface create(String familyName, int style) {
+ public static Typeface create(String familyName, @Style int style) {
return create(sSystemFontMap.get(familyName), style);
}
@@ -680,7 +695,7 @@
* e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
* @return The best matching typeface.
*/
- public static Typeface create(Typeface family, int style) {
+ public static Typeface create(Typeface family, @Style int style) {
if ((style & ~STYLE_MASK) != 0) {
style = NORMAL;
}
@@ -776,7 +791,7 @@
*
* @return the default typeface that corresponds to the style
*/
- public static Typeface defaultFromStyle(int style) {
+ public static Typeface defaultFromStyle(@Style int style) {
return sDefaults[style];
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e74dc6d..54358e3 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -201,10 +201,10 @@
* android:drawable="@drawable/vectordrawable" >
* <target
* android:name="rotationGroup"
- * android:animation="@anim/rotation" />
+ * android:animation="@animator/rotation" />
* <target
* android:name="v"
- * android:animation="@anim/path_morph" />
+ * android:animation="@animator/path_morph" />
* </animated-vector>
* </pre>
* </li>
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 749b7594..361fe0b 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -18,11 +18,14 @@
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
-import android.content.res.ColorStateList;
+import android.annotation.IdRes;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -60,17 +63,40 @@
public final class Icon implements Parcelable {
private static final String TAG = "Icon";
- /** @hide */
+ /**
+ * An icon that was created using {@link Icon#createWithBitmap(Bitmap)}.
+ * @see #getType
+ */
public static final int TYPE_BITMAP = 1;
- /** @hide */
+ /**
+ * An icon that was created using {@link Icon#createWithResource}.
+ * @see #getType
+ */
public static final int TYPE_RESOURCE = 2;
- /** @hide */
+ /**
+ * An icon that was created using {@link Icon#createWithData(byte[], int, int)}.
+ * @see #getType
+ */
public static final int TYPE_DATA = 3;
- /** @hide */
+ /**
+ * An icon that was created using {@link Icon#createWithContentUri}
+ * or {@link Icon#createWithFilePath(String)}.
+ * @see #getType
+ */
public static final int TYPE_URI = 4;
- /** @hide */
+ /**
+ * An icon that was created using {@link Icon#createWithAdaptiveBitmap}.
+ * @see #getType
+ */
public static final int TYPE_ADAPTIVE_BITMAP = 5;
+ /**
+ * @hide
+ */
+ @IntDef({TYPE_BITMAP, TYPE_RESOURCE, TYPE_DATA, TYPE_URI, TYPE_ADAPTIVE_BITMAP})
+ public @interface IconType {
+ }
+
private static final int VERSION_STREAM_SERIALIZER = 1;
private final int mType;
@@ -99,14 +125,12 @@
private int mInt2;
/**
- * @return The type of image data held in this Icon. One of
- * {@link #TYPE_BITMAP},
- * {@link #TYPE_RESOURCE},
- * {@link #TYPE_DATA}, or
- * {@link #TYPE_URI}.
- * {@link #TYPE_ADAPTIVE_BITMAP}
- * @hide
+ * Gets the type of the icon provided.
+ * <p>
+ * Note that new types may be added later, so callers should guard against other
+ * types being returned.
*/
+ @IconType
public int getType() {
return mType;
}
@@ -179,9 +203,13 @@
}
/**
- * @return The package containing resources for this {@link #TYPE_RESOURCE} Icon.
- * @hide
+ * Gets the package used to create this icon.
+ * <p>
+ * Only valid for icons of type {@link #TYPE_RESOURCE}.
+ * Note: This package may not be available if referenced in the future, and it is
+ * up to the caller to ensure safety if this package is re-used and/or persisted.
*/
+ @NonNull
public String getResPackage() {
if (mType != TYPE_RESOURCE) {
throw new IllegalStateException("called getResPackage() on " + this);
@@ -190,9 +218,13 @@
}
/**
- * @return The resource ID for this {@link #TYPE_RESOURCE} Icon.
- * @hide
+ * Gets the resource used to create this icon.
+ * <p>
+ * Only valid for icons of type {@link #TYPE_RESOURCE}.
+ * Note: This resource may not be available if the application changes at all, and it is
+ * up to the caller to ensure safety if this resource is re-used and/or persisted.
*/
+ @IdRes
public int getResId() {
if (mType != TYPE_RESOURCE) {
throw new IllegalStateException("called getResId() on " + this);
@@ -212,9 +244,13 @@
}
/**
- * @return The {@link android.net.Uri} for this {@link #TYPE_URI} Icon.
- * @hide
+ * Gets the uri used to create this icon.
+ * <p>
+ * Only valid for icons of type {@link #TYPE_URI}.
+ * Note: This uri may not be available in the future, and it is
+ * up to the caller to ensure safety if this uri is re-used and/or persisted.
*/
+ @NonNull
public Uri getUri() {
return Uri.parse(getUriString());
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ded427e..1924bbe 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -784,6 +784,20 @@
}
/**
+ * Requests keystore to check if the confirmationui HAL is available.
+ *
+ * @return whether the confirmationUI HAL is available.
+ */
+ public boolean isConfirmationPromptSupported() {
+ try {
+ return mBinder.isConfirmationPromptSupported();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+ /**
* Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
* code.
*/
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
index 1167f76..596e5f5 100644
--- a/keystore/tests/Android.mk
+++ b/keystore/tests/Android.mk
@@ -24,6 +24,7 @@
android-support-test
LOCAL_PACKAGE_NAME := KeystoreTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index 247458d..c512a6b 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -26,7 +26,7 @@
#include <androidfw/Util.h>
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
#include <utils/FileMap.h>
#include <utils/Log.h>
#include <utils/threads.h>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index a5698af..fc625bb 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -28,7 +28,7 @@
#include <androidfw/misc.h>
#include <androidfw/ResourceTypes.h>
#include <androidfw/ZipFileRO.h>
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/String8.h>
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 696a00c..6268c40 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -32,7 +32,7 @@
#include <androidfw/ByteBucketArray.h>
#include <androidfw/ResourceTypes.h>
#include <androidfw/TypeWrappers.h>
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
#include <utils/ByteOrder.h>
#include <utils/Debug.h>
#include <utils/Log.h>
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index ab27a0d..cf29e43 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -165,7 +165,7 @@
ALOGI("%s", ss.str().c_str());
// Just so we have something that counts up, the value is largely irrelevant
ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
- android::util::stats_write(android::util::DAVEY_OCCURRED, ns2ms(totalDuration));
+ android::util::stats_write(android::util::DAVEY_OCCURRED, getuid(), ns2ms(totalDuration));
}
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8372331..778e768 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -94,12 +94,20 @@
// Grab a copy of everything we need
CanvasContext* context = mContext;
+ std::function<void(int64_t)> callback = std::move(mFrameCallback);
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
unblockUiThread();
}
+ // Even if we aren't drawing this vsync pulse the next frame number will still be accurate
+ if (CC_UNLIKELY(callback)) {
+ context->enqueueFrameWork([callback, frameNr = context->getFrameNumber()]() {
+ callback(frameNr);
+ });
+ }
+
if (CC_LIKELY(canDrawThisFrame)) {
context->draw();
} else {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index ea51ae4..d8c43e0 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -74,6 +74,10 @@
void run();
+ void setFrameCallback(std::function<void(int64_t)>&& callback) {
+ mFrameCallback = std::move(callback);
+ }
+
private:
void postAndWait();
bool syncFrameState(TreeInfo& info);
@@ -96,6 +100,8 @@
int64_t mSyncQueued;
int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
+
+ std::function<void(int64_t)> mFrameCallback;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 79e46ed..4be7a57 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -270,6 +270,10 @@
mDrawFrameTask.setContentDrawBounds(left, top, right, bottom);
}
+void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
+ mDrawFrameTask.setFrameCallback(std::move(callback));
+}
+
void RenderProxy::serializeDisplayListTree() {
mRenderThread.queue().post([=]() { mContext->serializeDisplayListTree(); });
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index bc57d92..3425c5c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -115,6 +115,7 @@
ANDROID_API void removeRenderNode(RenderNode* node);
ANDROID_API void drawRenderNode(RenderNode* node);
ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
+ ANDROID_API void setFrameCallback(std::function<void(int64_t)>&& callback);
ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
diff --git a/libs/incident/proto/android/section.proto b/libs/incident/proto/android/section.proto
index 49bfe1e..ef6a8ff 100644
--- a/libs/incident/proto/android/section.proto
+++ b/libs/incident/proto/android/section.proto
@@ -40,6 +40,9 @@
// incidentd calls logs for annotated field
SECTION_LOG = 4;
+
+ // incidentd read file and gzip the data in bytes field
+ SECTION_GZIP = 5;
}
message SectionFlags {
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index 0a8a5aa..bf698d4 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -154,7 +154,7 @@
void editRawFixed32(size_t pos, uint32_t val);
/**
- * Copy _size_ bytes of data starting at __srcPos__ to wp.
+ * Copy _size_ bytes of data starting at __srcPos__ to wp, srcPos must be larger than wp.pos().
*/
void copy(size_t srcPos, size_t size);
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
index 44d290e..b2fd8ec 100644
--- a/location/tests/locationtests/Android.mk
+++ b/location/tests/locationtests/Android.mk
@@ -9,6 +9,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := FrameworksLocationTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk
index 99499dc..6fd47c6 100644
--- a/lowpan/tests/Android.mk
+++ b/lowpan/tests/Android.mk
@@ -59,6 +59,7 @@
android.test.base \
LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index 6dff07f..6d58a94 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -74,7 +74,7 @@
private List<HttpCookie> mUriCookies;
private Context mUriContext;
- private long mId = 0;
+ private String mMediaId;
private long mStartPositionMs = 0;
private long mEndPositionMs = LONG_MAX;
@@ -82,11 +82,11 @@
}
/**
- * Return the Id of data source.
- * @return the Id of data source
+ * Return the media Id of data source.
+ * @return the media Id of data source
*/
- public long getId() {
- return mId;
+ public String getMediaId() {
+ return mMediaId;
}
/**
@@ -222,7 +222,7 @@
private List<HttpCookie> mUriCookies;
private Context mUriContext;
- private long mId = 0;
+ private String mMediaId;
private long mStartPositionMs = 0;
private long mEndPositionMs = LONG_MAX;
@@ -248,7 +248,7 @@
mUriCookies = dsd.mUriCookies;
mUriContext = dsd.mUriContext;
- mId = dsd.mId;
+ mMediaId = dsd.mMediaId;
mStartPositionMs = dsd.mStartPositionMs;
mEndPositionMs = dsd.mEndPositionMs;
}
@@ -282,7 +282,7 @@
dsd.mUriCookies = mUriCookies;
dsd.mUriContext = mUriContext;
- dsd.mId = mId;
+ dsd.mMediaId = mMediaId;
dsd.mStartPositionMs = mStartPositionMs;
dsd.mEndPositionMs = mEndPositionMs;
@@ -290,13 +290,13 @@
}
/**
- * Sets the Id of this data source.
+ * Sets the media Id of this data source.
*
- * @param id the Id of this data source
+ * @param mediaId the media Id of this data source
* @return the same Builder instance.
*/
- public Builder setId(long id) {
- mId = id;
+ public Builder setMediaId(String mediaId) {
+ mMediaId = mediaId;
return this;
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 74e7c45..4af8850 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -181,6 +181,10 @@
oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
+ int addMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb);
+
+ int removeMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb);
+
int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
void setVolumePolicy(in VolumePolicy policy);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index fbe5561..6dd4f69 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -19,7 +19,9 @@
import java.nio.ByteBuffer;
import java.lang.AutoCloseable;
+import android.annotation.Nullable;
import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
/**
* <p>A single complete image buffer to use with a media source such as a
@@ -184,6 +186,23 @@
public abstract long getTimestamp();
/**
+ * Get the {@link android.hardware.HardwareBuffer HardwareBuffer} handle of the input image
+ * intended for GPU and/or hardware access.
+ * <p>
+ * The returned {@link android.hardware.HardwareBuffer HardwareBuffer} shall not be used
+ * after {@link Image#close Image.close()} has been called.
+ * </p>
+ * @return the HardwareBuffer associated with this Image or null if this Image doesn't support
+ * this feature (e.g. {@link android.media.ImageWriter ImageWriter} or
+ * {@link android.media.MediaCodec MediaCodec} don't).
+ */
+ @Nullable
+ public HardwareBuffer getHardwareBuffer() {
+ throwISEIfImageIsInvalid();
+ return null;
+ }
+
+ /**
* Set the timestamp associated with this frame.
* <p>
* The timestamp is measured in nanoseconds, and is normally monotonically
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 1019580..fb0de5c 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -876,6 +876,12 @@
}
@Override
+ public HardwareBuffer getHardwareBuffer() {
+ throwISEIfImageIsInvalid();
+ return nativeGetHardwareBuffer();
+ }
+
+ @Override
public void setTimestamp(long timestampNs) {
throwISEIfImageIsInvalid();
mTimestamp = timestampNs;
@@ -1017,6 +1023,7 @@
private synchronized native int nativeGetWidth();
private synchronized native int nativeGetHeight();
private synchronized native int nativeGetFormat(int readerFormat);
+ private synchronized native HardwareBuffer nativeGetHardwareBuffer();
}
private synchronized native void nativeInit(Object weakSelf, int w, int h,
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index 3f9a4ef..dea38a8 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -31,7 +31,6 @@
/**
* Browses media content offered by a {@link MediaLibraryService2}.
- * @hide
*/
public class MediaBrowser2 extends MediaController2 {
// Equals to the ((MediaBrowser2Provider) getProvider())
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 6682e08..38d5000 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -19,13 +19,13 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Context;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.ErrorCode;
import android.media.MediaSession2.PlaylistParams;
import android.media.session.MediaSessionManager;
import android.media.update.ApiLoader;
@@ -64,9 +64,8 @@
* <p>
* @see MediaSession2
* @see MediaSessionService2
- * @hide
*/
-public class MediaController2 implements AutoCloseable {
+public class MediaController2 implements AutoCloseable, MediaPlaylistController {
/**
* Interface for listening to change in activeness of the {@link MediaSession2}. It's
* active if and only if it has set a player.
@@ -126,19 +125,69 @@
/**
* Called when the playlist is changed.
+ * <p>
+ * When it's called, you should invalidate previous playback information such as position,
+ * player state, current item, etc.
*
* @param playlist A new playlist set by the session.
*/
+ // TODO(jaewan): Enhance doc
public void onPlaylistChanged(@NonNull List<MediaItem2> playlist) { }
/**
* Called when the playback state is changed.
*
* @param state latest playback state
+ * @hide
*/
+ // TODo(jaewan): Remove
public void onPlaybackStateChanged(@NonNull PlaybackState2 state) { }
/**
+ * Called when the player state is changed.
+ *
+ * @param state
+ */
+ public void onPlayerStateChanged(int state) { }
+
+ /**
+ * Called when the player's position is changed
+ *
+ * @param updateTimeMs timestamp when the position information is sent from the session
+ * @param positionMs position in millis
+ */
+ public void onPositionChanged(long updateTimeMs, long positionMs) { }
+
+ /**
+ * Called when playback speed is changed.
+ *
+ * @param speed speed
+ */
+ public void onPlaybackSpeedChanged(float speed) { }
+
+ /**
+ * Called when the player's buffering position
+ *
+ * @param positionMs buffering position in millis
+ */
+ public void onBufferedPositionChanged(long positionMs) { }
+
+ /**
+ * Called when a error from
+ *
+ * @param errorCode error code
+ * @param extras extra information
+ */
+ public void onError(@ErrorCode int errorCode, @Nullable Bundle extras) { }
+
+ /**
+ * Called when the player's current playing item is changed
+ *
+ * @param item new item
+ */
+ public void onCurrentPlaylistItemChanged(MediaItem2 item) { }
+
+ /**
* Called when the playlist parameters are changed.
*
* @param params The new play list parameters.
@@ -166,7 +215,6 @@
/**
* @hide
*/
- @SystemApi
public PlaybackInfo(PlaybackInfoProvider provider) {
mProvider = provider;
}
@@ -174,7 +222,6 @@
/**
* @hide
*/
- @SystemApi
public PlaybackInfoProvider getProvider() {
return mProvider;
}
@@ -281,7 +328,6 @@
/**
* @hide
*/
- @SystemApi
public MediaController2Provider getProvider() {
return mProvider;
}
@@ -325,7 +371,7 @@
* Request that the player prepare its playback. In other words, other sessions can continue
* to play during the preparation of this session. This method can be used to speed up the
* start of the playback. Once the preparation is done, the session will change its playback
- * state to {@link PlaybackState2#STATE_PAUSED}. Afterwards, {@link #play} can be called to
+ * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called to
* start playback.
*/
public void prepare() {
@@ -360,12 +406,13 @@
/**
* Sets the index of current DataSourceDesc in the play list to be played.
*
- * @param index the index of DataSourceDesc in the play list you want to play
+ * @param item the index of DataSourceDesc in the play list you want to play
* @throws IllegalArgumentException if the play list is null
* @throws NullPointerException if index is outside play list range
*/
- public void setCurrentPlaylistItem(int index) {
- mProvider.setCurrentPlaylistItem_impl(index);
+ @Override
+ public void skipToPlaylistItem(@NonNull MediaItem2 item) {
+ mProvider.skipToPlaylistItem_impl(item);
}
/**
@@ -375,7 +422,7 @@
* @param params A {@link PlaylistParams} object to set.
* @throws IllegalArgumentException if given {@param param} is null.
*/
- public void setPlaylistParams(PlaylistParams params) {
+ public void setPlaylistParams(@NonNull PlaylistParams params) {
mProvider.setPlaylistParams_impl(params);
}
@@ -428,12 +475,11 @@
mProvider.playFromUri_impl(uri, extras);
}
-
/**
* Request that the player prepare playback for a specific media id. In other words, other
* sessions can continue to play during the preparation of this session. This method can be
* used to speed up the start of the playback. Once the preparation is done, the session
- * will change its playback state to {@link PlaybackState2#STATE_PAUSED}. Afterwards,
+ * will change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards,
* {@link #play} can be called to start playback. If the preparation is not needed,
* {@link #playFromMediaId} can be directly called without this method.
*
@@ -450,7 +496,7 @@
* query should be treated as a request to prepare any music. In other words, other sessions
* can continue to play during the preparation of this session. This method can be used to
* speed up the start of the playback. Once the preparation is done, the session will
- * change its playback state to {@link PlaybackState2#STATE_PAUSED}. Afterwards,
+ * change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards,
* {@link #play} can be called to start playback. If the preparation is not needed,
* {@link #playFromSearch} can be directly called without this method.
*
@@ -466,7 +512,7 @@
* Request that the player prepare playback for a specific {@link Uri}. In other words,
* other sessions can continue to play during the preparation of this session. This method
* can be used to speed up the start of the playback. Once the preparation is done, the
- * session will change its playback state to {@link PlaybackState2#STATE_PAUSED}. Afterwards,
+ * session will change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards,
* {@link #play} can be called to start playback. If the preparation is not needed,
* {@link #playFromUri} can be directly called without this method.
*
@@ -537,12 +583,72 @@
* playback state.
*
* @return a playback state. Can be {@code null}
+ * @hide
*/
public @Nullable PlaybackState2 getPlaybackState() {
return mProvider.getPlaybackState_impl();
}
/**
+ * Get the lastly cached player state from {@link ControllerCallback#onPlayerStateChanged(int)}.
+ *
+ * @return player state
+ */
+ public int getPlayerState() {
+ return mProvider.getPlayerState_impl();
+ }
+
+ /**
+ * Get the lastly cached position from {@link ControllerCallback#onPositionChanged(long, long)}.
+ * <p>
+ * This returns the calculated value of the position, based on the difference between the
+ * update time and current time.
+ *
+ * @return position
+ */
+ public long getPosition() {
+ return mProvider.getPosition_impl();
+ }
+
+ /**
+ * Get the lastly cached playback speed from
+ * {@link ControllerCallback#onPlaybackSpeedChanged(float)}.
+ *
+ * @return speed
+ */
+ public float getPlaybackSpeed() {
+ return mProvider.getPlaybackSpeed_impl();
+ }
+
+ /**
+ * Set the playback speed.
+ */
+ public void setPlaybackSpeed(float speed) {
+ // TODO: implement this
+ }
+
+ /**
+ * Get the lastly cached buffered position from
+ * {@link ControllerCallback#onBufferedPositionChanged(long)}.
+ *
+ * @return buffering position in millis
+ */
+ public long getBufferedPosition() {
+ return mProvider.getBufferedPosition_impl();
+ }
+
+ /**
+ * Get the lastly cached current item from
+ * {@link ControllerCallback#onCurrentPlaylistItemChanged(MediaItem2)}.
+ *
+ * @return index of the current item
+ */
+ @Override
+ public MediaItem2 getCurrentPlaylistItem() {
+ return mProvider.getCurrentPlaylistItem_impl();
+ }
+
+ /**
* Get the current playback info for this session.
*
* @return The current playback info or null.
@@ -584,6 +690,7 @@
*
* @return playlist. Can be {@code null} if the controller doesn't have enough permission.
*/
+ @Override
public @Nullable List<MediaItem2> getPlaylist() {
return mProvider.getPlaylist_impl();
}
@@ -598,34 +705,39 @@
}
/**
- * Removes the media item at index in the play list.
+ * Removes the media item at index in the playlist.
*<p>
- * If index is same as the current index of the playlist, current playback
+ * If the item is the currently playing item of the playlist, current playback
* will be stopped and playback moves to next source in the list.
- *
- * @return the removed DataSourceDesc at index in the play list
- * @throws IllegalArgumentException if the play list is null
- * @throws IndexOutOfBoundsException if index is outside play list range
*/
- // TODO(jaewan): Remove with index was previously rejected by council (b/36524925)
- // TODO(jaewan): Should we also add movePlaylistItem from index to index?
- public void removePlaylistItem(MediaItem2 item) {
+ @Override
+ public void removePlaylistItem(@NonNull MediaItem2 item) {
mProvider.removePlaylistItem_impl(item);
}
/**
+ * Replace the media item at index in the playlist.
+ * @param index the index of the item to replace
+ * @param item the new item
+ */
+ @Override
+ public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
+ mProvider.replacePlaylistItem_impl(index, item);
+ }
+
+ /**
* Inserts the media item to the play list at position index.
* <p>
* This will not change the currently playing media item.
* If index is less than or equal to the current index of the play list,
* the current index of the play list will be incremented correspondingly.
*
- * @param index the index you want to add dsd to the play list
- * @param item the media item you want to add to the play list
+ * @param index the index you want to add
+ * @param item the media item you want to add
* @throws IndexOutOfBoundsException if index is outside play list range
- * @throws NullPointerException if dsd is null
*/
- public void addPlaylistItem(int index, MediaItem2 item) {
+ @Override
+ public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
mProvider.addPlaylistItem_impl(index, item);
}
}
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index 40c837b..99bd254 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -125,6 +125,38 @@
}
/**
+ * Scramble control value indicating that the samples are not scrambled.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0;
+
+ /**
+ * Scramble control value reserved and shouldn't be used currently.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_RESERVED = 1;
+
+ /**
+ * Scramble control value indicating that the even key is used.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2;
+
+ /**
+ * Scramble control value indicating that the odd key is used.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3;
+
+ /**
+ * Scramble flag for a hint indicating that the descrambling request is for
+ * retrieving the PES header info only.
+ *
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_FLAG_PES_HEADER = (1 << 0);
+
+ /**
* Descramble a ByteBuffer of data described by a
* {@link android.media.MediaCodec.CryptoInfo} structure.
*
@@ -133,7 +165,15 @@
* @param dstBuf ByteBuffer to hold the descrambled data, which starts at
* dstBuf.position().
* @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure
- * describing the subsamples contained in src.
+ * describing the subsamples contained in srcBuf. The iv and mode fields in
+ * CryptoInfo are not used. key[0] contains the MPEG2TS scrambling control bits
+ * (as defined in ETSI TS 100 289 (2011): "Digital Video Broadcasting (DVB);
+ * Support for use of the DVB Scrambling Algorithm version 3 within digital
+ * broadcasting systems"), and the value must be one of {@link #SCRAMBLE_CONTROL_UNSCRAMBLED},
+ * {@link #SCRAMBLE_CONTROL_RESERVED}, {@link #SCRAMBLE_CONTROL_EVEN_KEY} or
+ * {@link #SCRAMBLE_CONTROL_ODD_KEY}. key[1] is a set of bit flags, with the
+ * only possible bit being {@link #SCRAMBLE_FLAG_PES_HEADER} currently.
+ * key[2~15] are not used.
*
* @return number of bytes that have been successfully descrambled, with negative
* values indicating errors.
@@ -169,6 +209,7 @@
try {
return native_descramble(
cryptoInfo.key[0],
+ cryptoInfo.key[1],
cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData,
cryptoInfo.numBytesOfEncryptedData,
@@ -204,7 +245,8 @@
private native final void native_setup(@NonNull IHwBinder decramblerBinder);
private native final void native_release();
private native final int native_descramble(
- byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
+ byte key, byte flags, int numSubSamples,
+ int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
@NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit,
ByteBuffer dstBuf, int dstOffset, int dstLimit) throws RemoteException;
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index 667aac1..f9eceab 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -19,7 +19,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.content.Context;
import android.media.update.ApiLoader;
import android.media.update.MediaItem2Provider;
@@ -35,7 +34,6 @@
* When it's sent to a controller or browser, it's anonymized and data descriptor wouldn't be sent.
* <p>
* This object isn't a thread safe.
- * @hide
*/
public class MediaItem2 {
/** @hide */
@@ -59,24 +57,9 @@
private final MediaItem2Provider mProvider;
/**
- * Create a new media item.
- *
- * @param mediaId id of this item. It must be unique whithin this app
- * @param metadata metadata with the media id.
- * @param flags The flags for this item.
- */
- public MediaItem2(@NonNull Context context, @NonNull String mediaId,
- @NonNull DataSourceDesc dsd, @Nullable MediaMetadata2 metadata,
- @Flags int flags) {
- mProvider = ApiLoader.getProvider(context).createMediaItem2(
- context, this, mediaId, dsd, metadata, flags);
- }
-
- /**
* Create a new media item
* @hide
*/
- @SystemApi
public MediaItem2(MediaItem2Provider provider) {
mProvider = provider;
}
@@ -156,4 +139,73 @@
public @Nullable DataSourceDesc getDataSourceDesc() {
return mProvider.getDataSourceDesc_impl();
}
+
+ /**
+ * Build {@link MediaItem2}
+ */
+ public static final class Builder {
+ private final MediaItem2Provider.BuilderProvider mProvider;
+
+ /**
+ * Constructor for {@link Builder}
+ *
+ * @param context
+ * @param flags
+ */
+ public Builder(@NonNull Context context, @Flags int flags) {
+ mProvider = ApiLoader.getProvider(context).createMediaItem2Builder(
+ context, this, flags);
+ }
+
+ /**
+ * Set the media id of this instance. {@code null} for unset.
+ * <p>
+ * Media id is used to identify a media contents between session and controller.
+ * <p>
+ * If the metadata is set with the {@link #setMetadata(MediaMetadata2)} and it has
+ * media id, id from {@link #setMediaId(String)} will be ignored and metadata's id will be
+ * used instead. If the id isn't set neither by {@link #setMediaId(String)} nor
+ * {@link #setMetadata(MediaMetadata2)}, id will be automatically generated.
+ *
+ * @param mediaId media id
+ * @return this instance for chaining
+ */
+ public Builder setMediaId(@Nullable String mediaId) {
+ return mProvider.setMediaId_impl(mediaId);
+ }
+
+ /**
+ * Set the metadata of this instance. {@code null} for unset.
+ * <p>
+ * If the metadata is set with the {@link #setMetadata(MediaMetadata2)} and it has
+ * media id, id from {@link #setMediaId(String)} will be ignored and metadata's id will be
+ * used instead. If the id isn't set neither by {@link #setMediaId(String)} nor
+ * {@link #setMetadata(MediaMetadata2)}, id will be automatically generated.
+ *
+ * @param metadata metadata
+ * @return this instance for chaining
+ */
+ public Builder setMetadata(@Nullable MediaMetadata2 metadata) {
+ return mProvider.setMetadata_impl(metadata);
+ }
+
+ /**
+ * Set the data source descriptor for this instance. Should not be {@code null}.
+ *
+ * @param dataSourceDesc data source descriptor
+ * @return this instance for chaining
+ */
+ public Builder setDataSourceDesc(@NonNull DataSourceDesc dataSourceDesc) {
+ return mProvider.setDataSourceDesc_impl(dataSourceDesc);
+ }
+
+ /**
+ * Build {@link MediaItem2}.
+ *
+ * @return a new {@link MediaItem2}.
+ */
+ public MediaItem2 build() {
+ return mProvider.build_impl();
+ }
+ }
}
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 11b745a..5917190 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -19,10 +19,10 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Context;
-import android.media.MediaSession2.BuilderBase;
+import android.media.MediaLibraryService2.MediaLibrarySession.Builder;
+import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import android.media.MediaSession2.ControllerInfo;
import android.media.update.ApiLoader;
import android.media.update.MediaLibraryService2Provider.LibraryRootProvider;
@@ -40,7 +40,7 @@
* and ask the application to start playing it. They may also be used to control content that
* is already playing by way of a {@link MediaSession2}.
* <p>
- * To extend this class, adding followings directly to your {@code AndroidManifest.xml}.
+ * When extending this class, also add the following to your {@code AndroidManifest.xml}.
* <pre>
* <service android:name="component_name_of_your_implementation" >
* <intent-filter>
@@ -48,11 +48,12 @@
* </intent-filter>
* </service></pre>
* <p>
- * A {@link MediaLibraryService2} is extension of {@link MediaSessionService2}. IDs shouldn't
+ * The {@link MediaLibraryService2} class derives from {@link MediaSessionService2}. IDs shouldn't
* be shared between the {@link MediaSessionService2} and {@link MediaSession2}. By
* default, an empty string will be used for ID of the service. If you want to specify an ID,
* declare metadata in the manifest as follows.
- * @hide
+ *
+ * @see MediaSessionService2
*/
public abstract class MediaLibraryService2 extends MediaSessionService2 {
/**
@@ -63,15 +64,187 @@
/**
* Session for the {@link MediaLibraryService2}. Build this object with
- * {@link MediaLibrarySessionBuilder} and return in {@link #onCreateSession(String)}.
+ * {@link Builder} and return in {@link #onCreateSession(String)}.
*/
- public static class MediaLibrarySession extends MediaSession2 {
+ public static final class MediaLibrarySession extends MediaSession2 {
private final MediaLibrarySessionProvider mProvider;
/**
+ * Callback for the {@link MediaLibrarySession}.
+ */
+ public static class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
+ public MediaLibrarySessionCallback(Context context) {
+ super(context);
+ }
+
+ /**
+ * Called to get the root information for browsing by a particular client.
+ * <p>
+ * The implementation should verify that the client package has permission
+ * to access browse media information before returning the root id; it
+ * should return null if the client is not allowed to access this
+ * information.
+ *
+ * @param controllerInfo information of the controller requesting access to browse media.
+ * @param rootHints An optional bundle of service-specific arguments to send
+ * to the media library service when connecting and retrieving the
+ * root id for browsing, or null if none. The contents of this
+ * bundle may affect the information returned when browsing.
+ * @return The {@link LibraryRoot} for accessing this app's content or null.
+ * @see LibraryRoot#EXTRA_RECENT
+ * @see LibraryRoot#EXTRA_OFFLINE
+ * @see LibraryRoot#EXTRA_SUGGESTED
+ */
+ public @Nullable LibraryRoot onGetLibraryRoot(@NonNull ControllerInfo controllerInfo,
+ @Nullable Bundle rootHints) {
+ return null;
+ }
+
+ /**
+ * Called to get an item. Return result here for the browser.
+ * <p>
+ * Return {@code null} for no result or error.
+ *
+ * @param mediaId item id to get media item.
+ * @return a media item. {@code null} for no result or error.
+ */
+ public @Nullable MediaItem2 onGetItem(@NonNull ControllerInfo controllerInfo,
+ @NonNull String mediaId) {
+ return null;
+ }
+
+ /**
+ * Called to get children of given parent id. Return the children here for the browser.
+ * <p>
+ * Return an empty list for no children, and return {@code null} for the error.
+ *
+ * @param parentId parent id to get children
+ * @param page number of page
+ * @param pageSize size of the page
+ * @param extras extra bundle
+ * @return list of children. Can be {@code null}.
+ */
+ public @Nullable List<MediaItem2> onGetChildren(@NonNull ControllerInfo controller,
+ @NonNull String parentId, int page, int pageSize, @Nullable Bundle extras) {
+ return null;
+ }
+
+ /**
+ * Called when a controller subscribes to the parent.
+ * <p>
+ * It's your responsibility to keep subscriptions by your own and call
+ * {@link MediaLibrarySession#notifyChildrenChanged(ControllerInfo, String, int, Bundle)}
+ * when the parent is changed.
+ *
+ * @param controller controller
+ * @param parentId parent id
+ * @param extras extra bundle
+ */
+ public void onSubscribe(@NonNull ControllerInfo controller, @NonNull String parentId,
+ @Nullable Bundle extras) {
+ }
+
+ /**
+ * Called when a controller unsubscribes to the parent.
+ *
+ * @param controller controller
+ * @param parentId parent id
+ */
+ public void onUnsubscribe(@NonNull ControllerInfo controller,
+ @NonNull String parentId) {
+ }
+
+ /**
+ * Called when a controller requests search.
+ *
+ * @param query The search query sent from the media browser. It contains keywords
+ * separated by space.
+ * @param extras The bundle of service-specific arguments sent from the media browser.
+ */
+ public void onSearch(@NonNull ControllerInfo controllerInfo, @NonNull String query,
+ @Nullable Bundle extras) {
+ }
+
+ /**
+ * Called to get the search result. Return search result here for the browser which has
+ * requested search previously.
+ * <p>
+ * Return an empty list for no search result, and return {@code null} for the error.
+ *
+ * @param controllerInfo Information of the controller requesting the search result.
+ * @param query The search query which was previously sent through
+ * {@link #onSearch(ControllerInfo, String, Bundle)} call.
+ * @param page page number. Starts from {@code 1}.
+ * @param pageSize page size. Should be greater or equal to {@code 1}.
+ * @param extras The bundle of service-specific arguments sent from the media browser.
+ * @return search result. {@code null} for error.
+ */
+ public @Nullable List<MediaItem2> onGetSearchResult(
+ @NonNull ControllerInfo controllerInfo, @NonNull String query, int page,
+ int pageSize, @Nullable Bundle extras) {
+ return null;
+ }
+ }
+
+ /**
+ * Builder for {@link MediaLibrarySession}.
+ */
+ // Override all methods just to show them with the type instead of generics in Javadoc.
+ // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
+ public static final class Builder extends BuilderBase<MediaLibrarySession, Builder,
+ MediaLibrarySessionCallback> {
+ // Builder requires MediaLibraryService2 instead of Context just to ensure that the
+ // builder can be only instantiated within the MediaLibraryService2.
+ // Ideally it's better to make it inner class of service to enforce, it violates API
+ // guideline that Builders should be the inner class of the building target.
+ public Builder(@NonNull MediaLibraryService2 service,
+ @NonNull @CallbackExecutor Executor callbackExecutor,
+ @NonNull MediaLibrarySessionCallback callback) {
+ super((instance) -> ApiLoader.getProvider(service)
+ .createMediaLibraryService2Builder(service, (Builder) instance,
+ callbackExecutor, callback));
+ }
+
+ @Override
+ public Builder setPlayer(@NonNull MediaPlayerBase player) {
+ return super.setPlayer(player);
+ }
+
+ @Override
+ public Builder setPlaylistController(@NonNull MediaPlaylistController mplc) {
+ return super.setPlaylistController(mplc);
+ }
+
+ @Override
+ public Builder setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
+ return super.setVolumeProvider(volumeProvider);
+ }
+
+ @Override
+ public Builder setSessionActivity(@Nullable PendingIntent pi) {
+ return super.setSessionActivity(pi);
+ }
+
+ @Override
+ public Builder setId(String id) {
+ return super.setId(id);
+ }
+
+ @Override
+ public Builder setSessionCallback(@NonNull Executor executor,
+ @NonNull MediaLibrarySessionCallback callback) {
+ return super.setSessionCallback(executor, callback);
+ }
+
+ @Override
+ public MediaLibrarySession build() {
+ return super.build();
+ }
+ }
+
+ /**
* @hide
*/
- @SystemApi
public MediaLibrarySession(MediaLibrarySessionProvider provider) {
super(provider);
mProvider = provider;
@@ -124,166 +297,6 @@
}
}
- /**
- * Callback for the {@link MediaLibrarySession}.
- */
- public static class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
-
- public MediaLibrarySessionCallback(Context context) {
- super(context);
- }
-
- /**
- * Called to get the root information for browsing by a particular client.
- * <p>
- * The implementation should verify that the client package has permission
- * to access browse media information before returning the root id; it
- * should return null if the client is not allowed to access this
- * information.
- *
- * @param controllerInfo information of the controller requesting access to browse media.
- * @param rootHints An optional bundle of service-specific arguments to send
- * to the media library service when connecting and retrieving the
- * root id for browsing, or null if none. The contents of this
- * bundle may affect the information returned when browsing.
- * @return The {@link LibraryRoot} for accessing this app's content or null.
- * @see LibraryRoot#EXTRA_RECENT
- * @see LibraryRoot#EXTRA_OFFLINE
- * @see LibraryRoot#EXTRA_SUGGESTED
- */
- public @Nullable LibraryRoot onGetLibraryRoot(@NonNull ControllerInfo controllerInfo,
- @Nullable Bundle rootHints) {
- return null;
- }
-
- /**
- * Called to get an item. Return result here for the browser.
- * <p>
- * Return {@code null} for no result or error.
- *
- * @param mediaId item id to get media item.
- * @return a media item. {@code null} for no result or error.
- */
- public @Nullable MediaItem2 onGetItem(@NonNull ControllerInfo controllerInfo,
- @NonNull String mediaId) {
- return null;
- }
-
- /**
- * Called to get children of given parent id. Return the children here for the browser.
- * <p>
- * Return an empty list for no children, and return {@code null} for the error.
- *
- * @param parentId parent id to get children
- * @param page number of page
- * @param pageSize size of the page
- * @param extras extra bundle
- * @return list of children. Can be {@code null}.
- */
- public @Nullable List<MediaItem2> onGetChildren(@NonNull ControllerInfo controller,
- @NonNull String parentId, int page, int pageSize, @Nullable Bundle extras) {
- return null;
- }
-
- /**
- * Called when a controller subscribes to the parent.
- * <p>
- * It's your responsibility to keep subscriptions by your own and call
- * {@link MediaLibrarySession#notifyChildrenChanged(ControllerInfo, String, int, Bundle)}
- * when the parent is changed.
- *
- * @param controller controller
- * @param parentId parent id
- * @param extras extra bundle
- */
- public void onSubscribe(@NonNull ControllerInfo controller, @NonNull String parentId,
- @Nullable Bundle extras) {
- }
-
- /**
- * Called when a controller unsubscribes to the parent.
- *
- * @param controller controller
- * @param parentId parent id
- */
- public void onUnsubscribe(@NonNull ControllerInfo controller, @NonNull String parentId) {
- }
-
- /**
- * Called when a controller requests search.
- *
- * @param query The search query sent from the media browser. It contains keywords separated
- * by space.
- * @param extras The bundle of service-specific arguments sent from the media browser.
- */
- public void onSearch(@NonNull ControllerInfo controllerInfo, @NonNull String query,
- @Nullable Bundle extras) {
- }
-
- /**
- * Called to get the search result. Return search result here for the browser which has
- * requested search previously.
- * <p>
- * Return an empty list for no search result, and return {@code null} for the error.
- *
- * @param controllerInfo Information of the controller requesting the search result.
- * @param query The search query which was previously sent through
- * {@link #onSearch(ControllerInfo, String, Bundle)} call.
- * @param page page number. Starts from {@code 1}.
- * @param pageSize page size. Should be greater or equal to {@code 1}.
- * @param extras The bundle of service-specific arguments sent from the media browser.
- * @return search result. {@code null} for error.
- */
- public @Nullable List<MediaItem2> onGetSearchResult(@NonNull ControllerInfo controllerInfo,
- @NonNull String query, int page, int pageSize, @Nullable Bundle extras) {
- return null;
- }
- }
-
- /**
- * Builder for {@link MediaLibrarySession}.
- */
- // Override all methods just to show them with the type instead of generics in Javadoc.
- // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
- public class MediaLibrarySessionBuilder extends BuilderBase<MediaLibrarySession,
- MediaLibrarySessionBuilder, MediaLibrarySessionCallback> {
- public MediaLibrarySessionBuilder(
- @NonNull Context context, @NonNull MediaPlayerInterface player,
- @NonNull @CallbackExecutor Executor callbackExecutor,
- @NonNull MediaLibrarySessionCallback callback) {
- super((instance) -> ApiLoader.getProvider(context).createMediaLibraryService2Builder(
- context, (MediaLibrarySessionBuilder) instance, player, callbackExecutor,
- callback));
- }
-
- @Override
- public MediaLibrarySessionBuilder setVolumeProvider(
- @Nullable VolumeProvider2 volumeProvider) {
- return super.setVolumeProvider(volumeProvider);
- }
-
- @Override
- public MediaLibrarySessionBuilder setSessionActivity(@Nullable PendingIntent pi) {
- return super.setSessionActivity(pi);
- }
-
- @Override
- public MediaLibrarySessionBuilder setId(String id) {
- return super.setId(id);
- }
-
- @Override
- public MediaLibrarySessionBuilder setSessionCallback(
- @NonNull Executor executor, @NonNull MediaLibrarySessionCallback callback) {
- return super.setSessionCallback(executor, callback);
- }
-
- @Override
- public MediaLibrarySession build() {
- return super.build();
- }
- }
-
@Override
MediaSessionService2Provider createProvider() {
return ApiLoader.getProvider(this).createMediaLibraryService2(this);
@@ -302,7 +315,7 @@
*
* @param sessionId session id written in the AndroidManifest.xml.
* @return a new library session
- * @see MediaLibrarySessionBuilder
+ * @see Builder
* @see #getSession()
* @throws RuntimeException if returned session is invalid
*/
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index 1f856bc..f3425e8 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
-import android.annotation.SystemApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.media.update.ApiLoader;
@@ -33,89 +32,152 @@
/**
* Contains metadata about an item, such as the title, artist, etc.
- *
- * @hide
*/
+// New version of MediaMetadata with following changes
+// - Don't implement Parcelable for updatable support.
+// - Also support MediaDescription features. MediaDescription is deprecated instead because
+// it was insufficient for controller to display media contents.
+// TODO(jaewan): Add @see for APIs from MediaDescription
public final class MediaMetadata2 {
- // New version of MediaMetadata that no longer implements Parcelable but added from/toBundle()
- // for updatable.
- // MediaDescription is deprecated because it was insufficient for controller to display media
- // contents. Added getExtra() here to support all the features from the MediaDescription.
-
/**
* The title of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
/**
* The artist of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
/**
* The duration of the media in ms. A negative duration indicates that the
* duration is unknown (or infinite).
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
/**
* The album title for the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
/**
* The author of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
/**
* The writer of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
/**
* The composer of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
/**
* The compilation status of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
/**
* The date the media was created or published. The format is unspecified
* but RFC 3339 is recommended.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
/**
* The year the media was created or published as a long.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
/**
* The genre of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
/**
* The track number for the media.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
/**
* The number of tracks in the media's original source.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
/**
* The disc number for the media's original source.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
/**
* The artist for the album of the media's original source.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
@@ -125,11 +187,19 @@
* The artwork should be relatively small and may be scaled down
* if it is too large. For higher resolution artwork
* {@link #METADATA_KEY_ART_URI} should be used instead.
+ *
+ * @see Builder#putBitmap(String, Bitmap)
+ * @see #getBitmap(String)
*/
public static final String METADATA_KEY_ART = "android.media.metadata.ART";
/**
* The artwork for the media as a Uri style String.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
@@ -139,26 +209,36 @@
* The artwork should be relatively small and may be scaled down
* if it is too large. For higher resolution artwork
* {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
+ *
+ * @see Builder#putBitmap(String, Bitmap)
+ * @see #getBitmap(String)
*/
public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
/**
* The artwork for the album of the media's original source as a Uri style
* String.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
/**
* The user's rating for the media.
*
- * @see Rating
+ * @see Builder#putRating(String, Rating2)
+ * @see #getRating(String)
*/
public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
/**
* The overall rating for the media.
*
- * @see Rating
+ * @see Builder#putRating(String, Rating2)
+ * @see #getRating(String)
*/
public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
@@ -167,6 +247,11 @@
* the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
* When displaying media described by this metadata this should be preferred
* if present.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
@@ -174,6 +259,11 @@
* A subtitle that is suitable for display to the user. When displaying a
* second line for media described by this metadata this should be preferred
* to other fields if present.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_SUBTITLE
= "android.media.metadata.DISPLAY_SUBTITLE";
@@ -182,6 +272,11 @@
* A description that is suitable for display to the user. When displaying
* more information for media described by this metadata this should be
* preferred to other fields if present.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_DESCRIPTION
= "android.media.metadata.DISPLAY_DESCRIPTION";
@@ -194,6 +289,9 @@
* The icon should be relatively small and may be scaled down
* if it is too large. For higher resolution artwork
* {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
+ *
+ * @see Builder#putBitmap(String, Bitmap)
+ * @see #getBitmap(String)
*/
public static final String METADATA_KEY_DISPLAY_ICON
= "android.media.metadata.DISPLAY_ICON";
@@ -203,6 +301,11 @@
* displaying more information for media described by this metadata the
* display description should be preferred to other fields when present.
* This must be a Uri style String.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_ICON_URI
= "android.media.metadata.DISPLAY_ICON_URI";
@@ -214,6 +317,11 @@
* {@link MediaController2#playFromMediaId(String, Bundle)}
* to initiate playback when provided by a {@link MediaBrowser2} connected to
* the same app.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
@@ -223,17 +331,30 @@
* {@link MediaController2#playFromUri(Uri, Bundle)}
* to initiate playback when provided by a {@link MediaBrowser2} connected to
* the same app.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
/**
* The radio frequency in Float format if this metdata representing radio content.
+ *
+ * @see Builder#putFloat(String, float)
+ * @see #getFloat(String)
*/
public static final String METADATA_KEY_RADIO_FREQUENCY =
"android.media.metadata.RADIO_FREQUENCY";
/**
* The radio callsign in String format if this metdata representing radio content.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_RADIO_CALLSIGN =
"android.media.metadata.RADIO_CALLSIGN";
@@ -250,6 +371,9 @@
* <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
* <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
* </ul>
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_BT_FOLDER_TYPE
= "android.media.metadata.BT_FOLDER_TYPE";
@@ -300,6 +424,9 @@
* Whether the media is an advertisement. A value of 0 indicates it is not an advertisement. A
* value of 1 or non-zero indicates it is an advertisement. If not specified, this value is set
* to 0 by default.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
@@ -312,6 +439,9 @@
* <li>{@link #STATUS_DOWNLOADING}</li>
* <li>{@link #STATUS_DOWNLOADED}</li>
* </ul>
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_DOWNLOAD_STATUS =
"android.media.metadata.DOWNLOAD_STATUS";
@@ -389,7 +519,6 @@
/**
* @hide
*/
- @SystemApi
public MediaMetadata2(MediaMetadata2Provider provider) {
mProvider = provider;
}
@@ -568,7 +697,6 @@
/**
* @hide
*/
- @SystemApi
public Builder(@NonNull MediaMetadata2Provider.BuilderProvider provider) {
mProvider = provider;
}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 1446660..e0047d6 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -22,15 +22,10 @@
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.SurfaceTexture;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Parcel;
-import android.os.PersistableBundle;
-import android.view.Surface;
-import android.view.SurfaceHolder;
import android.media.MediaDrm;
import android.media.MediaFormat;
import android.media.MediaPlayer2Impl;
+import android.media.MediaPlayerBase;
import android.media.MediaTimeProvider;
import android.media.PlaybackParams;
import android.media.SubtitleController;
@@ -38,6 +33,12 @@
import android.media.SubtitleData;
import android.media.SubtitleTrack.RenderingWidget;
import android.media.SyncParams;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.view.Surface;
+import android.view.SurfaceHolder;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -45,7 +46,6 @@
import java.lang.AutoCloseable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.List;
import java.util.Map;
@@ -91,7 +91,7 @@
* <p>From this state diagram, one can see that a MediaPlayer2 object has the
* following states:</p>
* <ul>
- * <li>When a MediaPlayer2 object is just created using <code>new</code> or
+ * <li>When a MediaPlayer2 object is just created using <code>create</code> or
* after {@link #reset()} is called, it is in the <em>Idle</em> state; and after
* {@link #close()} is called, it is in the <em>End</em> state. Between these
* two states is the life cycle of the MediaPlayer2 object.
@@ -100,9 +100,9 @@
* as {@link #getCurrentPosition()},
* {@link #getDuration()}, {@link #getVideoHeight()},
* {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
- * {@link #setVolume(float, float)}, {@link #pause()}, {@link #play()},
+ * {@link #setPlayerVolume(float)}, {@link #pause()}, {@link #play()},
* {@link #seekTo(long, int)} or
- * {@link #prepareAsync()} in the <em>Idle</em> state.
+ * {@link #prepare()} in the <em>Idle</em> state.
* <li>It is also recommended that once
* a MediaPlayer2 object is no longer being used, call {@link #close()} immediately
* so that resources used by the internal player engine associated with the
@@ -126,9 +126,9 @@
* these circumstances. Sometimes, due to programming errors, invoking a playback
* control operation in an invalid state may also occur. Under all these
* error conditions, the internal player engine invokes a user supplied
- * EventCallback.onError() method if an EventCallback has been
+ * MediaPlayer2EventCallback.onError() method if an MediaPlayer2EventCallback has been
* registered beforehand via
- * {@link #registerEventCallback(Executor, EventCallback)}.
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.
* <ul>
* <li>It is important to note that once an error occurs, the
* MediaPlayer2 object enters the <em>Error</em> state (except as noted
@@ -142,7 +142,7 @@
* the internal player engine.</li>
* <li>IllegalStateException is
* thrown to prevent programming errors such as calling
- * {@link #prepareAsync()}, {@link #setDataSource(DataSourceDesc)}, or
+ * {@link #prepare()}, {@link #setDataSource(DataSourceDesc)}, or
* {@code setPlaylist} methods in an invalid state. </li>
* </ul>
* </li>
@@ -164,21 +164,21 @@
* before playback can be started.
* <ul>
* <li>There are an asynchronous way that the <em>Prepared</em> state can be reached:
- * a call to {@link #prepareAsync()} (asynchronous) which
+ * a call to {@link #prepare()} (asynchronous) which
* first transfers the object to the <em>Preparing</em> state after the
* call returns (which occurs almost right way) while the internal
* player engine continues working on the rest of preparation work
* until the preparation work completes. When the preparation completes,
* the internal player engine then calls a user supplied callback method,
- * onInfo() of the EventCallback interface with {@link #MEDIA_INFO_PREPARED}, if an
- * EventCallback is registered beforehand via
- * {@link #registerEventCallback(Executor, EventCallback)}.</li>
+ * onInfo() of the MediaPlayer2EventCallback interface with {@link #MEDIA_INFO_PREPARED},
+ * if an MediaPlayer2EventCallback is registered beforehand via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.</li>
* <li>It is important to note that
* the <em>Preparing</em> state is a transient state, and the behavior
* of calling any method with side effect while a MediaPlayer2 object is
* in the <em>Preparing</em> state is undefined.</li>
* <li>An IllegalStateException is
- * thrown if {@link #prepareAsync()} is called in
+ * thrown if {@link #prepare()} is called in
* any other state.</li>
* <li>While in the <em>Prepared</em> state, properties
* such as audio/sound volume, screenOnWhilePlaying, looping can be
@@ -187,13 +187,14 @@
* </li>
* <li>To start the playback, {@link #play()} must be called. After
* {@link #play()} returns successfully, the MediaPlayer2 object is in the
- * <em>Started</em> state. {@link #isPlaying()} can be called to test
+ * <em>Started</em> state. {@link #getPlayerState()} can be called to test
* whether the MediaPlayer2 object is in the <em>Started</em> state.
* <ul>
* <li>While in the <em>Started</em> state, the internal player engine calls
- * a user supplied EventCallback.onBufferingUpdate() callback
- * method if an EventCallback has been registered beforehand
- * via {@link #registerEventCallback(Executor, EventCallback)}.
+ * a user supplied callback method MediaPlayer2EventCallback.onInfo() with
+ * {@link #MEDIA_INFO_BUFFERING_UPDATE} if an MediaPlayer2EventCallback has been
+ * registered beforehand via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.
* This callback allows applications to keep track of the buffering status
* while streaming audio/video.</li>
* <li>Calling {@link #play()} has not effect
@@ -206,7 +207,7 @@
* <em>Paused</em> state. Note that the transition from the <em>Started</em>
* state to the <em>Paused</em> state and vice versa happens
* asynchronously in the player engine. It may take some time before
- * the state is updated in calls to {@link #isPlaying()}, and it can be
+ * the state is updated in calls to {@link #getPlayerState()}, and it can be
* a number of seconds in the case of streamed content.
* <ul>
* <li>Calling {@link #play()} to resume playback for a paused
@@ -225,9 +226,9 @@
* call returns right away, the actual seek operation may take a while to
* finish, especially for audio/video being streamed. When the actual
* seek operation completes, the internal player engine calls a user
- * supplied EventCallback.onInfo() with {@link #MEDIA_INFO_COMPLETE_CALL_SEEK}
- * if an EventCallback has been registered beforehand via
- * {@link #registerEventCallback(Executor, EventCallback)}.</li>
+ * supplied MediaPlayer2EventCallback.onCallComplete() with {@link #MEDIA_CALL_SEEK_TO}
+ * if an MediaPlayer2EventCallback has been registered beforehand via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.</li>
* <li>Please
* note that {@link #seekTo(long, int)} can also be called in the other states,
* such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
@@ -243,15 +244,13 @@
* </li>
* <li>When the playback reaches the end of stream, the playback completes.
* <ul>
- * <li>If the looping mode was being set to one of the values of
- * {@link #LOOPING_MODE_FULL}, {@link #LOOPING_MODE_SINGLE} or
- * {@link #LOOPING_MODE_SHUFFLE} with
- * {@link #setLoopingMode(int)}, the MediaPlayer2 object shall remain in
- * the <em>Started</em> state.</li>
+ * <li>If current source is set to loop by {@link #loopCurrent(boolean)},
+ * the MediaPlayer2 object shall remain in the <em>Started</em> state.</li>
* <li>If the looping mode was set to <var>false
* </var>, the player engine calls a user supplied callback method,
- * EventCallback.onCompletion(), if an EventCallback is registered
- * beforehand via {@link #registerEventCallback(Executor, EventCallback)}.
+ * MediaPlayer2EventCallback.onCompletion(), if an MediaPlayer2EventCallback is
+ * registered beforehand via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)}.
* The invoke of the callback signals that the object is now in the <em>
* PlaybackCompleted</em> state.</li>
* <li>While in the <em>PlaybackCompleted</em>
@@ -305,7 +304,7 @@
* <td>Successful invoke of this method in a valid state does not change
* the state. Calling this method in an invalid state transfers the
* object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>isPlaying </p></td>
+ * <tr><td>getPlayerState </p></td>
* <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
* PlaybackCompleted}</p></td>
* <td>{Error}</p></td>
@@ -318,7 +317,7 @@
* <td>Successful invoke of this method in a valid state transfers the
* object to the <em>Paused</em> state. Calling this method in an
* invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>prepareAsync </p></td>
+ * <tr><td>prepare </p></td>
* <td>{Initialized, Stopped} </p></td>
* <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td>
* <td>Successful invoke of this method in a valid state transfers the
@@ -345,7 +344,7 @@
* <td>{Error}</p></td>
* <td>Successful invoke of this method does not change the state. In order for the
* target audio attributes type to become effective, this method must be called before
- * prepareAsync().</p></td></tr>
+ * prepare().</p></td></tr>
* <tr><td>setAudioSessionId </p></td>
* <td>{Idle} </p></td>
* <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
@@ -359,7 +358,7 @@
* <td>{Error}</p></td>
* <td>Successful invoke of this method does not change the state. In order for the
* target audio stream type to become effective, this method must be called before
- * prepareAsync().</p></td></tr>
+ * prepare().</p></td></tr>
* <tr><td>setAuxEffectSendLevel </p></td>
* <td>any</p></td>
* <td>{} </p></td>
@@ -388,7 +387,7 @@
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
- * <tr><td>setLoopingMode </p></td>
+ * <tr><td>loopCurrent </p></td>
* <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
* PlaybackCompleted}</p></td>
* <td>{Error}</p></td>
@@ -400,12 +399,12 @@
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
- * <tr><td>registerDrmEventCallback </p></td>
+ * <tr><td>setDrmEventCallback </p></td>
* <td>any </p></td>
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
- * <tr><td>registerEventCallback </p></td>
+ * <tr><td>setMediaPlayer2EventCallback </p></td>
* <td>any </p></td>
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
@@ -415,7 +414,7 @@
* <td>{Idle, Stopped} </p></td>
* <td>This method will change state in some cases, depending on when it's called.
* </p></td></tr>
- * <tr><td>setVolume </p></td>
+ * <tr><td>setPlayerVolume </p></td>
* <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
* PlaybackCompleted}</p></td>
* <td>{Error}</p></td>
@@ -463,51 +462,17 @@
* possible runtime errors during playback or streaming. Registration for
* these events is done by properly setting the appropriate listeners (via calls
* to
- * {@link #registerEventCallback(Executor, EventCallback)},
- * {@link #registerDrmEventCallback(Executor, DrmEventCallback)}).
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)},
+ * {@link #setDrmEventCallback(Executor, DrmEventCallback)}).
* In order to receive the respective callback
* associated with these listeners, applications are required to create
* MediaPlayer2 objects on a thread with its own Looper running (main UI
* thread by default has a Looper running).
*
*/
-public abstract class MediaPlayer2 implements SubtitleController.Listener
- , AudioRouting
- , AutoCloseable
-{
- /**
- Constant to retrieve only the new metadata since the last
- call.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean METADATA_UPDATE_ONLY = true;
-
- /**
- Constant to retrieve all the metadata.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean METADATA_ALL = false;
-
- /**
- Constant to enable the metadata filter during retrieval.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean APPLY_METADATA_FILTER = true;
-
- /**
- Constant to disable the metadata filter during retrieval.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean BYPASS_METADATA_FILTER = false;
-
+public abstract class MediaPlayer2 extends MediaPlayerBase
+ implements SubtitleController.Listener
+ , AudioRouting {
/**
* Create a MediaPlayer2 object.
*
@@ -525,6 +490,256 @@
public MediaPlayer2() { }
/**
+ * Releases the resources held by this {@code MediaPlayer2} object.
+ *
+ * It is considered good practice to call this method when you're
+ * done using the MediaPlayer2. In particular, whenever an Activity
+ * of an application is paused (its onPause() method is called),
+ * or stopped (its onStop() method is called), this method should be
+ * invoked to release the MediaPlayer2 object, unless the application
+ * has a special need to keep the object around. In addition to
+ * unnecessary resources (such as memory and instances of codecs)
+ * being held, failure to call this method immediately if a
+ * MediaPlayer2 object is no longer needed may also lead to
+ * continuous battery consumption for mobile devices, and playback
+ * failure for other applications if no multiple instances of the
+ * same codec are supported on a device. Even if multiple instances
+ * of the same codec are supported, some performance degradation
+ * may be expected when unnecessary multiple instances are used
+ * at the same time.
+ *
+ * {@code close()} may be safely called after a prior {@code close()}.
+ * This class implements the Java {@code AutoCloseable} interface and
+ * may be used with try-with-resources.
+ */
+ @Override
+ public abstract void close();
+
+ /**
+ * Starts or resumes playback. If playback had previously been paused,
+ * playback will continue from where it was paused. If playback had
+ * reached end of stream and been paused, or never started before,
+ * playback will start at the beginning. If the source had not been
+ * prepared, the player will prepare the source and play.
+ *
+ */
+ @Override
+ public abstract void play();
+
+ /**
+ * Prepares the player for playback, asynchronously.
+ *
+ * After setting the datasource and the display surface, you need to
+ * call prepare().
+ *
+ */
+ @Override
+ public abstract void prepare();
+
+ /**
+ * Pauses playback. Call play() to resume.
+ */
+ @Override
+ public abstract void pause();
+
+ /**
+ * Tries to play next data source if applicable.
+ */
+ @Override
+ public abstract void skipToNext();
+
+ /**
+ * Moves the media to specified time position.
+ * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
+ *
+ * @param msec the offset in milliseconds from the start to seek to
+ */
+ @Override
+ public void seekTo(long msec) {
+ seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+ }
+
+ /**
+ * Gets the current playback position.
+ *
+ * @return the current position in milliseconds
+ */
+ @Override
+ public abstract long getCurrentPosition();
+
+ /**
+ * Gets the duration of the file.
+ *
+ * @return the duration in milliseconds, if no duration is available
+ * (for example, if streaming live content), -1 is returned.
+ */
+ @Override
+ public abstract long getDuration();
+
+ /**
+ * Gets the current buffered media source position received through progressive downloading.
+ * The received buffering percentage indicates how much of the content has been buffered
+ * or played. For example a buffering update of 80 percent when half the content
+ * has already been played indicates that the next 30 percent of the
+ * content to play has been buffered.
+ *
+ * @return the current buffered media source position in milliseconds
+ */
+ @Override
+ public abstract long getBufferedPosition();
+
+ /**
+ * Gets the current player state.
+ *
+ * @return the current player state.
+ */
+ @Override
+ public abstract @PlayerState int getPlayerState();
+
+ /**
+ * Gets the current buffering state of the player.
+ * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
+ * buffered.
+ * @return the buffering state, one of the following:
+ */
+ @Override
+ public abstract @BuffState int getBufferingState();
+
+ /**
+ * Sets the audio attributes for this MediaPlayer2.
+ * See {@link AudioAttributes} for how to build and configure an instance of this class.
+ * You must call this method before {@link #prepare()} in order
+ * for the audio attributes to become effective thereafter.
+ * @param attributes a non-null set of audio attributes
+ */
+ @Override
+ public abstract void setAudioAttributes(@NonNull AudioAttributes attributes);
+
+ /**
+ * Gets the audio attributes for this MediaPlayer2.
+ * @return attributes a set of audio attributes
+ */
+ @Override
+ public abstract @Nullable AudioAttributes getAudioAttributes();
+
+ /**
+ * Sets the data source as described by a DataSourceDesc.
+ *
+ * @param dsd the descriptor of data source you want to play
+ */
+ @Override
+ public abstract void setDataSource(@NonNull DataSourceDesc dsd);
+
+ /**
+ * Sets a single data source as described by a DataSourceDesc which will be played
+ * after current data source is finished.
+ *
+ * @param dsd the descriptor of data source you want to play after current one
+ */
+ @Override
+ public abstract void setNextDataSource(@NonNull DataSourceDesc dsd);
+
+ /**
+ * Sets a list of data sources to be played sequentially after current data source is done.
+ *
+ * @param dsds the list of data sources you want to play after current one
+ */
+ @Override
+ public abstract void setNextDataSources(@NonNull List<DataSourceDesc> dsds);
+
+ /**
+ * Gets the current data source as described by a DataSourceDesc.
+ *
+ * @return the current DataSourceDesc
+ */
+ @Override
+ public abstract @NonNull DataSourceDesc getCurrentDataSource();
+
+ /**
+ * Configures the player to loop on the current data source.
+ * @param loop true if the current data source is meant to loop.
+ */
+ @Override
+ public abstract void loopCurrent(boolean loop);
+
+ /**
+ * Sets the playback speed.
+ * A value of 1.0f is the default playback value.
+ * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
+ * before using negative values.<br>
+ * After changing the playback speed, it is recommended to query the actual speed supported
+ * by the player, see {@link #getPlaybackSpeed()}.
+ * @param speed the desired playback speed
+ */
+ @Override
+ public abstract void setPlaybackSpeed(float speed);
+
+ /**
+ * Returns the actual playback speed to be used by the player when playing.
+ * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
+ * @return the actual playback speed
+ */
+ @Override
+ public float getPlaybackSpeed() {
+ return 1.0f;
+ }
+
+ /**
+ * Indicates whether reverse playback is supported.
+ * Reverse playback is indicated by negative playback speeds, see
+ * {@link #setPlaybackSpeed(float)}.
+ * @return true if reverse playback is supported.
+ */
+ @Override
+ public boolean isReversePlaybackSupported() {
+ return false;
+ }
+
+ /**
+ * Sets the volume of the audio of the media to play, expressed as a linear multiplier
+ * on the audio samples.
+ * Note that this volume is specific to the player, and is separate from stream volume
+ * used across the platform.<br>
+ * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
+ * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
+ * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
+ */
+ @Override
+ public abstract void setPlayerVolume(float volume);
+
+ /**
+ * Returns the current volume of this player to this player.
+ * Note that it does not take into account the associated stream volume.
+ * @return the player volume.
+ */
+ @Override
+ public abstract float getPlayerVolume();
+
+ /**
+ * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
+ */
+ @Override
+ public float getMaxPlayerVolume() {
+ return 1.0f;
+ }
+
+ /**
+ * Adds a callback to be notified of events for this player.
+ * @param e the {@link Executor} to be used for the events.
+ * @param cb the callback to receive the events.
+ */
+ @Override
+ public abstract void registerPlayerEventCallback(@NonNull Executor e,
+ @NonNull PlayerEventCallback cb);
+
+ /**
+ * Removes a previously registered callback for player events
+ * @param cb the callback to remove
+ */
+ @Override
+ public abstract void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb);
+
+ /**
* Create a request parcel which can be routed to the native media
* player using {@link #invoke(Parcel, Parcel)}. The Parcel
* returned has the proper InterfaceToken set. The caller should
@@ -556,6 +771,19 @@
public void invoke(Parcel request, Parcel reply) { }
/**
+ * Insert a task in the command queue to help the client to identify whether a batch
+ * of commands has been finished. When this command is processed, a notification
+ * {@code MediaPlayer2EventCallback.onCommandLabelReached} will be fired with the
+ * given {@code label}.
+ *
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCommandLabelReached
+ *
+ * @param label An application specific Object used to help to identify the completeness
+ * of a batch of commands.
+ */
+ public void notifyWhenCommandLabelReached(Object label) { }
+
+ /**
* Sets the {@link SurfaceHolder} to use for displaying the video
* portion of the media.
*
@@ -642,188 +870,6 @@
public abstract void clearPendingCommands();
/**
- * Sets the data source as described by a DataSourceDesc.
- *
- * @param dsd the descriptor of data source you want to play
- * @throws IllegalStateException if it is called in an invalid state
- * @throws NullPointerException if dsd is null
- */
- public abstract void setDataSource(@NonNull DataSourceDesc dsd) throws IOException;
-
- /**
- * Gets the current data source as described by a DataSourceDesc.
- *
- * @return the current DataSourceDesc
- */
- public abstract DataSourceDesc getCurrentDataSource();
-
- /**
- * Sets the play list.
- *
- * If startIndex falls outside play list range, it will be clamped to the nearest index
- * in the play list.
- *
- * @param pl the play list of data source you want to play
- * @param startIndex the index of the DataSourceDesc in the play list you want to play first
- * @throws IllegalStateException if it is called in an invalid state
- * @throws IllegalArgumentException if pl is null or empty, or pl contains null DataSourceDesc
- */
- public abstract void setPlaylist(@NonNull List<DataSourceDesc> pl, int startIndex)
- throws IOException;
-
- /**
- * Gets a copy of the play list.
- *
- * @return a copy of the play list used by {@link MediaPlayer2}
- */
- public abstract List<DataSourceDesc> getPlaylist();
-
- /**
- * Sets the index of current DataSourceDesc in the play list to be played.
- *
- * @param index the index of DataSourceDesc in the play list you want to play
- * @throws IllegalArgumentException if the play list is null
- * @throws NullPointerException if index is outside play list range
- */
- public abstract void setCurrentPlaylistItem(int index);
-
- /**
- * Sets the index of next-to-be-played DataSourceDesc in the play list.
- *
- * @param index the index of next-to-be-played DataSourceDesc in the play list
- * @throws IllegalArgumentException if the play list is null
- * @throws NullPointerException if index is outside play list range
- */
- public abstract void setNextPlaylistItem(int index);
-
- /**
- * Gets the current index of play list.
- *
- * @return the index of the current DataSourceDesc in the play list
- */
- public abstract int getCurrentPlaylistItemIndex();
-
- /**
- * Specifies a playback looping mode. The source will not be played in looping mode.
- */
- public static final int LOOPING_MODE_NONE = 0;
- /**
- * Specifies a playback looping mode. The full list of source will be played in looping mode,
- * and in the order specified in the play list.
- */
- public static final int LOOPING_MODE_FULL = 1;
- /**
- * Specifies a playback looping mode. The current DataSourceDesc will be played in looping mode.
- */
- public static final int LOOPING_MODE_SINGLE = 2;
- /**
- * Specifies a playback looping mode. The full list of source will be played in looping mode,
- * and in a random order.
- */
- public static final int LOOPING_MODE_SHUFFLE = 3;
-
- /** @hide */
- @IntDef(
- value = {
- LOOPING_MODE_NONE,
- LOOPING_MODE_FULL,
- LOOPING_MODE_SINGLE,
- LOOPING_MODE_SHUFFLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LoopingMode {}
-
- /**
- * Sets the looping mode of the play list.
- * The mode shall be one of {@link #LOOPING_MODE_NONE}, {@link #LOOPING_MODE_FULL},
- * {@link #LOOPING_MODE_SINGLE}, {@link #LOOPING_MODE_SHUFFLE}.
- *
- * @param mode the mode in which the play list will be played
- * @throws IllegalArgumentException if mode is not supported
- */
- public abstract void setLoopingMode(@LoopingMode int mode);
-
- /**
- * Gets the looping mode of play list.
- *
- * @return the looping mode of the play list
- */
- public abstract int getLoopingMode();
-
- /**
- * Moves the DataSourceDesc at indexFrom in the play list to indexTo.
- *
- * @throws IllegalArgumentException if the play list is null
- * @throws IndexOutOfBoundsException if indexFrom or indexTo is outside play list range
- */
- public abstract void movePlaylistItem(int indexFrom, int indexTo);
-
- /**
- * Removes the DataSourceDesc at index in the play list.
- *
- * If index is same as the current index of the play list, current DataSourceDesc
- * will be stopped and playback moves to next source in the list.
- *
- * @return the removed DataSourceDesc at index in the play list
- * @throws IllegalArgumentException if the play list is null
- * @throws IndexOutOfBoundsException if index is outside play list range
- */
- public abstract DataSourceDesc removePlaylistItem(int index);
-
- /**
- * Inserts the DataSourceDesc to the play list at position index.
- *
- * This will not change the DataSourceDesc currently being played.
- * If index is less than or equal to the current index of the play list,
- * the current index of the play list will be incremented correspondingly.
- *
- * @param index the index you want to add dsd to the play list
- * @param dsd the descriptor of data source you want to add to the play list
- * @throws IndexOutOfBoundsException if index is outside play list range
- * @throws NullPointerException if dsd is null
- */
- public abstract void addPlaylistItem(int index, DataSourceDesc dsd);
-
- /**
- * replaces the DataSourceDesc at index in the play list with given dsd.
- *
- * When index is same as the current index of the play list, the current source
- * will be stopped and the new source will be played, except that if new
- * and old source only differ on end position and current media position is
- * smaller then the new end position.
- *
- * This will not change the DataSourceDesc currently being played.
- * If index is less than or equal to the current index of the play list,
- * the current index of the play list will be incremented correspondingly.
- *
- * @param index the index you want to add dsd to the play list
- * @param dsd the descriptor of data source you want to add to the play list
- * @throws IndexOutOfBoundsException if index is outside play list range
- * @throws NullPointerException if dsd is null
- */
- public abstract DataSourceDesc editPlaylistItem(int index, DataSourceDesc dsd);
-
- /**
- * Prepares the player for playback, asynchronously.
- *
- * After setting the datasource and the display surface, you need to
- * call prepareAsync().
- *
- * @throws IllegalStateException if it is called in an invalid state
- */
- public abstract void prepareAsync();
-
- /**
- * Starts or resumes playback. If playback had previously been paused,
- * playback will continue from where it was paused. If playback had
- * been stopped, or never started before, playback will start at the
- * beginning.
- *
- * @throws IllegalStateException if it is called in an invalid state
- */
- public abstract void play();
-
- /**
* Stops playback after playback has been started or paused.
*
* @throws IllegalStateException if the internal player engine has not been
@@ -832,14 +878,6 @@
*/
public void stop() { }
- /**
- * Pauses playback. Call play() to resume.
- *
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
- */
- public abstract void pause();
-
//--------------------------------------------------------------------------
// Explicit Routing
//--------------------
@@ -927,9 +965,10 @@
*
* @return the width of the video, or 0 if there is no video,
* no display surface was set, or the width has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #registerEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the width is available.
+ * yet. The {@code MediaPlayer2EventCallback} can be registered via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
+ * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the width
+ * is available.
*/
public abstract int getVideoWidth();
@@ -938,9 +977,9 @@
*
* @return the height of the video, or 0 if there is no video,
* no display surface was set, or the height has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #registerEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the height is available.
+ * yet. The {@code MediaPlayer2EventCallback} can be registered via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
+ * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the height is available.
*/
public abstract int getVideoHeight();
@@ -962,10 +1001,59 @@
* @return true if currently playing, false otherwise
* @throws IllegalStateException if the internal player engine has not been
* initialized or has been released.
+ * @hide
*/
public abstract boolean isPlaying();
/**
+ * MediaPlayer2 has not been prepared or just has been reset.
+ * In this state, MediaPlayer2 doesn't fetch data.
+ */
+ public static final int MEDIAPLAYER2_STATE_IDLE = 1;
+
+ /**
+ * MediaPlayer2 has been just prepared.
+ * In this state, MediaPlayer2 just fetches data from media source,
+ * but doesn't actively render data.
+ */
+ public static final int MEDIAPLAYER2_STATE_PREPARED = 2;
+
+ /**
+ * MediaPlayer2 is paused.
+ * In this state, MediaPlayer2 doesn't actively render data.
+ */
+ public static final int MEDIAPLAYER2_STATE_PAUSED = 3;
+
+ /**
+ * MediaPlayer2 is actively playing back data.
+ */
+ public static final int MEDIAPLAYER2_STATE_PLAYING = 4;
+
+ /**
+ * MediaPlayer2 has hit some fatal error and cannot continue playback.
+ */
+ public static final int MEDIAPLAYER2_STATE_ERROR = 5;
+
+ /**
+ * @hide
+ */
+ @IntDef({
+ MEDIAPLAYER2_STATE_IDLE,
+ MEDIAPLAYER2_STATE_PREPARED,
+ MEDIAPLAYER2_STATE_PAUSED,
+ MEDIAPLAYER2_STATE_PLAYING,
+ MEDIAPLAYER2_STATE_ERROR })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MediaPlayer2State {}
+
+ /**
+ * Gets the current MediaPlayer2 state.
+ *
+ * @return the current MediaPlayer2 state.
+ */
+ public abstract @MediaPlayer2State int getMediaPlayer2State();
+
+ /**
* Gets the current buffering management params used by the source component.
* Calling it only after {@code setDataSource} has been called.
* Each type of data source might have different set of default params.
@@ -1075,10 +1163,6 @@
* non-zero speed is equivalent to calling play().
*
* @param params the playback params.
- *
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
- * @throws IllegalArgumentException if params is not supported.
*/
public abstract void setPlaybackParams(@NonNull PlaybackParams params);
@@ -1086,8 +1170,6 @@
* Gets the playback params, containing the current playback rate.
*
* @return the playback params.
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
*/
@NonNull
public abstract PlaybackParams getPlaybackParams();
@@ -1096,10 +1178,6 @@
* Sets A/V sync mode.
*
* @param params the A/V sync params to apply
- *
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
- * @throws IllegalArgumentException if params are not supported.
*/
public abstract void setSyncParams(@NonNull SyncParams params);
@@ -1107,9 +1185,6 @@
* Gets the A/V sync mode.
*
* @return the A/V sync params
- *
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
*/
@NonNull
public abstract SyncParams getSyncParams();
@@ -1191,9 +1266,6 @@
* or may not be a sync frame but is closest to or the same as msec.
* {@link #SEEK_CLOSEST} often has larger performance overhead compared
* to the other options if there is no sync frame located at msec.
- * @throws IllegalStateException if the internal player engine has not been
- * initialized
- * @throws IllegalArgumentException if the mode is invalid.
*/
public abstract void seekTo(long msec, @SeekMode int mode);
@@ -1219,21 +1291,6 @@
public abstract MediaTimestamp getTimestamp();
/**
- * Gets the current playback position.
- *
- * @return the current position in milliseconds
- */
- public abstract long getCurrentPosition();
-
- /**
- * Gets the duration of the file.
- *
- * @return the duration in milliseconds, if no duration is available
- * (for example, if streaming live content), -1 is returned.
- */
- public abstract long getDuration();
-
- /**
* Gets the media metadata.
*
* @param update_only controls whether the full set of available
@@ -1280,7 +1337,7 @@
/**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
- * data source and calling prepareAsync().
+ * data source and calling prepare().
*/
public abstract void reset();
@@ -1295,31 +1352,6 @@
public void notifyAt(long mediaTimeUs) { }
/**
- * Sets the audio attributes for this MediaPlayer2.
- * See {@link AudioAttributes} for how to build and configure an instance of this class.
- * You must call this method before {@link #prepareAsync()} in order
- * for the audio attributes to become effective thereafter.
- * @param attributes a non-null set of audio attributes
- * @throws IllegalArgumentException if the attributes are null or invalid.
- */
- public abstract void setAudioAttributes(AudioAttributes attributes);
-
- /**
- * Gets the audio attributes for this MediaPlayer2.
- * @return attributes a set of audio attributes
- * @throws IllegalArgumentException if the attributes are null or invalid.
- */
- public abstract AudioAttributes getAudioAttributes();
-
- /**
- * Sets the player to be looping or non-looping.
- *
- * @param looping whether to loop or not
- * @hide
- */
- public void setLooping(boolean looping) { }
-
- /**
* Checks whether the MediaPlayer2 is looping or non-looping.
*
* @return true if the MediaPlayer2 is currently looping, false otherwise
@@ -1330,31 +1362,6 @@
}
/**
- * Sets the volume on this player.
- * This API is recommended for balancing the output of audio streams
- * within an application. Unless you are writing an application to
- * control user settings, this API should be used in preference to
- * {@link AudioManager#setStreamVolume(int, int, int)} which sets the volume of ALL streams of
- * a particular type. Note that the passed volume values are raw scalars in range 0.0 to 1.0.
- * UI controls should be scaled logarithmically.
- *
- * @param leftVolume left volume scalar
- * @param rightVolume right volume scalar
- */
- /*
- * FIXME: Merge this into javadoc comment above when setVolume(float) is not @hide.
- * The single parameter form below is preferred if the channel volumes don't need
- * to be set independently.
- */
- public abstract void setVolume(float leftVolume, float rightVolume);
-
- /**
- * Similar, excepts sets volume of all channels to same value.
- * @hide
- */
- public void setVolume(float volume) { }
-
- /**
* Sets the audio session ID.
*
* @param sessionId the audio session ID.
@@ -1368,8 +1375,6 @@
* However, it is possible to force this player to be part of an already existing audio session
* by calling this method.
* This method must be called before one of the overloaded <code> setDataSource </code> methods.
- * @throws IllegalStateException if it is called in an invalid state
- * @throws IllegalArgumentException if the sessionId is invalid.
*/
public abstract void setAudioSessionId(int sessionId);
@@ -1458,7 +1463,6 @@
* @return List of track info. The total number of tracks is the array length.
* Must be called again if an external timed text source has been added after
* addTimedTextSource method is called.
- * @throws IllegalStateException if it is called in an invalid state.
*/
public abstract List<TrackInfo> getTrackInfo();
@@ -1643,32 +1647,6 @@
*/
public abstract void deselectTrack(int index);
- /**
- * Releases the resources held by this {@code MediaPlayer2} object.
- *
- * It is considered good practice to call this method when you're
- * done using the MediaPlayer2. In particular, whenever an Activity
- * of an application is paused (its onPause() method is called),
- * or stopped (its onStop() method is called), this method should be
- * invoked to release the MediaPlayer2 object, unless the application
- * has a special need to keep the object around. In addition to
- * unnecessary resources (such as memory and instances of codecs)
- * being held, failure to call this method immediately if a
- * MediaPlayer2 object is no longer needed may also lead to
- * continuous battery consumption for mobile devices, and playback
- * failure for other applications if no multiple instances of the
- * same codec are supported on a device. Even if multiple instances
- * of the same codec are supported, some performance degradation
- * may be expected when unnecessary multiple instances are used
- * at the same time.
- *
- * {@code close()} may be safely called after a prior {@code close()}.
- * This class implements the Java {@code AutoCloseable} interface and
- * may be used with try-with-resources.
- */
- @Override
- public abstract void close();
-
/** @hide */
public MediaTimeProvider getMediaTimeProvider() {
return null;
@@ -1678,22 +1656,7 @@
* Interface definition for callbacks to be invoked when the player has the corresponding
* events.
*/
- public abstract static class EventCallback {
- /**
- * Called to update status in buffering a media source received through
- * progressive downloading. The received buffering percentage
- * indicates how much of the content has been buffered or played.
- * For example a buffering update of 80 percent when half the content
- * has already been played indicates that the next 30 percent of the
- * content to play has been buffered.
- *
- * @param mp the MediaPlayer2 the update pertains to
- * @param srcId the Id of this data source
- * @param percent the percentage (0-100) of the content
- * that has been buffered or played thus far
- */
- public void onBufferingUpdate(MediaPlayer2 mp, long srcId, int percent) { }
-
+ public abstract static class MediaPlayer2EventCallback {
/**
* Called to indicate the video size
*
@@ -1701,22 +1664,22 @@
* no display surface was set, or the value was not determined yet.
*
* @param mp the MediaPlayer2 associated with this callback
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param width the width of the video
* @param height the height of the video
*/
- public void onVideoSizeChanged(MediaPlayer2 mp, long srcId, int width, int height) { }
+ public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) { }
/**
* Called to indicate an avaliable timed text
*
* @param mp the MediaPlayer2 associated with this callback
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param text the timed text sample which contains the text
* needed to be displayed and the display format.
* @hide
*/
- public void onTimedText(MediaPlayer2 mp, long srcId, TimedText text) { }
+ public void onTimedText(MediaPlayer2 mp, DataSourceDesc dsd, TimedText text) { }
/**
* Called to indicate avaliable timed metadata
@@ -1733,16 +1696,16 @@
* @see TimedMetaData
*
* @param mp the MediaPlayer2 associated with this callback
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param data the timed metadata sample associated with this event
*/
- public void onTimedMetaDataAvailable(MediaPlayer2 mp, long srcId, TimedMetaData data) { }
+ public void onTimedMetaDataAvailable(MediaPlayer2 mp, DataSourceDesc dsd, TimedMetaData data) { }
/**
* Called to indicate an error.
*
* @param mp the MediaPlayer2 the error pertains to
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param what the type of error that has occurred:
* <ul>
* <li>{@link #MEDIA_ERROR_UNKNOWN}
@@ -1757,13 +1720,13 @@
* <li><code>MEDIA_ERROR_SYSTEM (-2147483648)</code> - low-level system error.
* </ul>
*/
- public void onError(MediaPlayer2 mp, long srcId, int what, int extra) { }
+ public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { }
/**
* Called to indicate an info or a warning.
*
* @param mp the MediaPlayer2 the info pertains to.
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param what the type of info or warning.
* <ul>
* <li>{@link #MEDIA_INFO_UNKNOWN}
@@ -1773,9 +1736,6 @@
* <li>{@link #MEDIA_INFO_PLAYBACK_COMPLETE}
* <li>{@link #MEDIA_INFO_PLAYLIST_END}
* <li>{@link #MEDIA_INFO_PREPARED}
- * <li>{@link #MEDIA_INFO_COMPLETE_CALL_PLAY}
- * <li>{@link #MEDIA_INFO_COMPLETE_CALL_PAUSE}
- * <li>{@link #MEDIA_INFO_COMPLETE_CALL_SEEK}
* <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
* <li>{@link #MEDIA_INFO_BUFFERING_START}
* <li>{@link #MEDIA_INFO_BUFFERING_END}
@@ -1790,25 +1750,78 @@
* @param extra an extra code, specific to the info. Typically
* implementation dependent.
*/
- public void onInfo(MediaPlayer2 mp, long srcId, int what, int extra) { }
+ public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { }
+
+ /**
+ * Called to acknowledge an API call.
+ *
+ * @param mp the MediaPlayer2 the call was made on.
+ * @param dsd the DataSourceDesc of this data source
+ * @param what the enum for the API call.
+ * <ul>
+ * <li>{@link #MEDIA_CALL_ATTACH_AUX_EFFECT}
+ * <li>{@link #MEDIA_CALL_DESELECT_TRACK}
+ * <li>{@link #MEDIA_CALL_LOOP_CURRENT}
+ * <li>{@link #MEDIA_CALL_PAUSE}
+ * <li>{@link #MEDIA_CALL_PLAY}
+ * <li>{@link #MEDIA_CALL_PREPARE}
+ * <li>{@link #MEDIA_CALL_PREPARE_DRM}
+ * <li>{@link #MEDIA_CALL_PROVIDE_DRM_KEY_RESPONSE}
+ * <li>{@link #MEDIA_CALL_RELEASE_DRM}
+ * <li>{@link #MEDIA_CALL_RESTORE_DRM_KEYS}
+ * <li>{@link #MEDIA_CALL_SEEK_TO}
+ * <li>{@link #MEDIA_CALL_SELECT_TRACK}
+ * <li>{@link #MEDIA_CALL_SET_AUDIO_ATTRIBUTES}
+ * <li>{@link #MEDIA_CALL_SET_AUDIO_SESSION_ID}
+ * <li>{@link #MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL}
+ * <li>{@link #MEDIA_CALL_SET_DATA_SOURCE}
+ * <li>{@link #MEDIA_CALL_SET_DRM_CONFIG_HELPER}
+ * <li>{@link #MEDIA_CALL_SET_DRM_PROPERTY_STRING}
+ * <li>{@link #MEDIA_CALL_SET_NEXT_DATA_SOURCE}
+ * <li>{@link #MEDIA_CALL_SET_NEXT_DATA_SOURCES}
+ * <li>{@link #MEDIA_CALL_SET_PLAYBACK_PARAMS}
+ * <li>{@link #MEDIA_CALL_SET_PLAYBACK_SPEED}
+ * <li>{@link #MEDIA_CALL_SET_PLAYER_VOLUME}
+ * <li>{@link #MEDIA_CALL_SET_SURFACE}
+ * <li>{@link #MEDIA_CALL_SET_SYNC_PARAMS}
+ * <li>{@link #MEDIA_CALL_SKIP_TO_NEXT}
+ * </ul>
+ * @param status the returned status code for the call.
+ */
+ public void onCallComplete(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { }
+
+ /**
+ * Called to indicate media clock has changed.
+ *
+ * @param mp the MediaPlayer2 the media time pertains to.
+ * @param dsd the DataSourceDesc of this data source
+ * @param timestamp the new media clock.
+ */
+ public void onMediaTimeChanged(MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { }
+
+ /**
+ * Called to indicate {@link #notifyWhenCommandLabelReached(Object)} has been processed.
+ *
+ * @param mp the MediaPlayer2 {@link #notifyWhenCommandLabelReached(Object)} was called on.
+ * @param label the application specific Object given by
+ * {@link #notifyWhenCommandLabelReached(Object)}.
+ */
+ public void onCommandLabelReached(MediaPlayer2 mp, Object label) { }
}
/**
- * Register a callback to be invoked when the media source is ready
- * for playback.
+ * Sets the callback to be invoked when the media source is ready for playback.
*
* @param eventCallback the callback that will be run
* @param executor the executor through which the callback should be invoked
*/
- public abstract void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull EventCallback eventCallback);
+ public abstract void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull MediaPlayer2EventCallback eventCallback);
/**
- * Unregisters an {@link EventCallback}.
- *
- * @param callback an {@link EventCallback} to unregister
+ * Clears the {@link MediaPlayer2EventCallback}.
*/
- public abstract void unregisterEventCallback(EventCallback callback);
+ public abstract void clearMediaPlayer2EventCallback();
/**
* Interface definition of a callback to be invoked when a
@@ -1835,14 +1848,14 @@
* in include/media/mediaplayer2.h!
*/
/** Unspecified media player error.
- * @see android.media.MediaPlayer2.EventCallback.onError
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onError
*/
public static final int MEDIA_ERROR_UNKNOWN = 1;
/** The video is streamed and its container is not valid for progressive
* playback i.e the video's index (e.g moov atom) is not at the start of the
* file.
- * @see android.media.MediaPlayer2.EventCallback.onError
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onError
*/
public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
@@ -1858,7 +1871,7 @@
/** Unspecified low-level system error. This value originated from UNKNOWN_ERROR in
* system/core/include/utils/Errors.h
- * @see android.media.MediaPlayer2.EventCallback.onError
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onError
* @hide
*/
public static final int MEDIA_ERROR_SYSTEM = -2147483648;
@@ -1868,96 +1881,93 @@
* in include/media/mediaplayer2.h!
*/
/** Unspecified media player info.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_UNKNOWN = 1;
/** The player switched to this datas source because it is the
- * next-to-be-played in the play list.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * next-to-be-played in the playlist.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_STARTED_AS_NEXT = 2;
/** The player just pushed the very first video frame for rendering.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3;
/** The player just rendered the very first audio sample.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4;
/** The player just completed the playback of this data source.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_PLAYBACK_COMPLETE = 5;
- /** The player just completed the playback of the full play list.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ /** The player just completed the playback of the full playlist.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_PLAYLIST_END = 6;
/** The player just prepared a data source.
- * This also serves as call completion notification for {@link #prepareAsync()}.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_PREPARED = 100;
- /** The player just completed a call {@link #play()}.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
- */
- public static final int MEDIA_INFO_COMPLETE_CALL_PLAY = 101;
-
- /** The player just completed a call {@link #pause()}.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
- */
- public static final int MEDIA_INFO_COMPLETE_CALL_PAUSE = 102;
-
- /** The player just completed a call {@link #seekTo(long, int)}.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
- */
- public static final int MEDIA_INFO_COMPLETE_CALL_SEEK = 103;
-
/** The video is too complex for the decoder: it can't decode frames fast
* enough. Possibly only the audio plays fine at this stage.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
/** MediaPlayer2 is temporarily pausing playback internally in order to
* buffer more data.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_BUFFERING_START = 701;
/** MediaPlayer2 is resuming playback after filling buffers.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_BUFFERING_END = 702;
/** Estimated network bandwidth information (kbps) is available; currently this event fires
* simultaneously as {@link #MEDIA_INFO_BUFFERING_START} and {@link #MEDIA_INFO_BUFFERING_END}
* when playing network files.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
* @hide
*/
public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703;
+ /**
+ * Update status in buffering a media source received through progressive downloading.
+ * The received buffering percentage indicates how much of the content has been buffered
+ * or played. For example a buffering update of 80 percent when half the content
+ * has already been played indicates that the next 30 percent of the
+ * content to play has been buffered.
+ *
+ * The {@code extra} parameter in {@code MediaPlayer2EventCallback.onInfo} is the
+ * percentage (0-100) of the content that has been buffered or played thus far.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
+ */
+ public static final int MEDIA_INFO_BUFFERING_UPDATE = 704;
+
/** Bad interleaving means that a media has been improperly interleaved or
* not interleaved at all, e.g has all the video samples first then all the
* audio ones. Video is playing but a lot of disk seeks may be happening.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_BAD_INTERLEAVING = 800;
/** The media cannot be seeked (e.g live stream)
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
/** A new set of metadata is available.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_METADATA_UPDATE = 802;
@@ -1969,33 +1979,164 @@
/** Informs that audio is not playing. Note that playback of the video
* is not interrupted.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804;
/** Informs that video is not playing. Note that playback of the audio
* is not interrupted.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805;
/** Failed to handle timed text track properly.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*
* {@hide}
*/
public static final int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
/** Subtitle track was not supported by the media framework.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;
/** Reading the subtitle track takes too long.
- * @see android.media.MediaPlayer2.EventCallback.onInfo
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onInfo
*/
public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
+ //--------------------------------------------------------------------------
+ /** The player just completed a call {@code attachAuxEffect}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_ATTACH_AUX_EFFECT = 1;
+
+ /** The player just completed a call {@code deselectTrack}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_DESELECT_TRACK = 2;
+
+ /** The player just completed a call {@code loopCurrent}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback.CallComplete
+ */
+ public static final int MEDIA_CALL_LOOP_CURRENT = 3;
+
+ /** The player just completed a call {@code pause}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback.CallComplete
+ */
+ public static final int MEDIA_CALL_PAUSE = 4;
+
+ /** The player just completed a call {@code play}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_PLAY = 5;
+
+ /** The player just completed a call {@code prepare}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_PREPARE = 6;
+
+ /** The player just completed a call {@code prepareDrm}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_PREPARE_DRM = 7;
+
+ /** The player just completed a call {@code provideDrmKeyResponse}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_PROVIDE_DRM_KEY_RESPONSE = 8;
+
+ /** The player just completed a call {@code releaseDrm}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_RELEASE_DRM = 12;
+
+ /** The player just completed a call {@code restoreDrmKeys}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13;
+
+ /** The player just completed a call {@code seekTo}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SEEK_TO = 14;
+
+ /** The player just completed a call {@code selectTrack}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SELECT_TRACK = 15;
+
+ /** The player just completed a call {@code setAudioAttributes}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_AUDIO_ATTRIBUTES = 16;
+
+ /** The player just completed a call {@code setAudioSessionId}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17;
+
+ /** The player just completed a call {@code setAuxEffectSendLevel}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18;
+
+ /** The player just completed a call {@code setDataSource}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_DATA_SOURCE = 19;
+
+ /** The player just completed a call {@code setOnDrmConfigHelper}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_DRM_CONFIG_HELPER = 20;
+
+ /** The player just completed a call {@code setDrmPropertyString}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_DRM_PROPERTY_STRING = 21;
+
+ /** The player just completed a call {@code setNextDataSource}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22;
+
+ /** The player just completed a call {@code setNextDataSources}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23;
+
+ /** The player just completed a call {@code setPlaybackParams}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24;
+
+ /** The player just completed a call {@code setPlaybackSpeed}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_PLAYBACK_SPEED = 25;
+
+ /** The player just completed a call {@code setPlayerVolume}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_PLAYER_VOLUME = 26;
+
+ /** The player just completed a call {@code setSurface}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_SURFACE = 27;
+
+ /** The player just completed a call {@code setSyncParams}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SET_SYNC_PARAMS = 28;
+
+ /** The player just completed a call {@code skipToNext}.
+ * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+ */
+ public static final int MEDIA_CALL_SKIP_TO_NEXT = 29;
+
// Modular DRM begin
@@ -2015,9 +2156,9 @@
* Called to give the app the opportunity to configure DRM before the session is created
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
*/
- public void onDrmConfig(MediaPlayer2 mp, long srcId);
+ public void onDrmConfig(MediaPlayer2 mp, DataSourceDesc dsd);
}
/**
@@ -2039,42 +2180,40 @@
* Called to indicate DRM info is available
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param drmInfo DRM info of the source including PSSH, and subset
* of crypto schemes supported by this device
*/
- public void onDrmInfo(MediaPlayer2 mp, long srcId, DrmInfo drmInfo) { }
+ public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { }
/**
- * Called to notify the client that {@code prepareDrm} is finished and ready for key request/response.
+ * Called to notify the client that {@code prepareDrm} is finished and ready for
+ * key request/response.
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param srcId the Id of this data source
+ * @param dsd the DataSourceDesc of this data source
* @param status the result of DRM preparation which can be
* {@link #PREPARE_DRM_STATUS_SUCCESS},
* {@link #PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR},
* {@link #PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR}, or
* {@link #PREPARE_DRM_STATUS_PREPARATION_ERROR}.
*/
- public void onDrmPrepared(MediaPlayer2 mp, long srcId, @PrepareDrmStatusCode int status) { }
+ public void onDrmPrepared(MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
}
/**
- * Register a callback to be invoked when the media source is ready
- * for playback.
+ * Sets the callback to be invoked when the media source is ready for playback.
*
* @param eventCallback the callback that will be run
* @param executor the executor through which the callback should be invoked
*/
- public abstract void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+ public abstract void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull DrmEventCallback eventCallback);
/**
- * Unregisters a {@link DrmEventCallback}.
- *
- * @param callback a {@link DrmEventCallback} to unregister
+ * Clears the {@link DrmEventCallback}.
*/
- public abstract void unregisterDrmEventCallback(DrmEventCallback callback);
+ public abstract void clearDrmEventCallback();
/**
* The status codes for {@link DrmEventCallback#onDrmPrepared} listener.
@@ -2172,14 +2311,14 @@
* A key request/response exchange occurs between the app and a license server
* to obtain or release keys used to decrypt encrypted content.
* <p>
- * getKeyRequest() is used to obtain an opaque key request byte array that is
+ * getDrmKeyRequest() is used to obtain an opaque key request byte array that is
* delivered to the license server. The opaque key request byte array is returned
* in KeyRequest.data. The recommended URL to deliver the key request to is
* returned in KeyRequest.defaultUrl.
* <p>
* After the app has received the key request response from the server,
* it should deliver to the response to the DRM engine plugin using the method
- * {@link #provideKeyResponse}.
+ * {@link #provideDrmKeyResponse}.
*
* @param keySetId is the key-set identifier of the offline keys being released when keyType is
* {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
@@ -2206,22 +2345,23 @@
* @throws NoDrmSchemeException if there is no active DRM session
*/
@NonNull
- public abstract MediaDrm.KeyRequest getKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
+ public abstract MediaDrm.KeyRequest getDrmKeyRequest(
+ @Nullable byte[] keySetId, @Nullable byte[] initData,
@Nullable String mimeType, @MediaDrm.KeyType int keyType,
@Nullable Map<String, String> optionalParameters)
throws NoDrmSchemeException;
/**
* A key response is received from the license server by the app, then it is
- * provided to the DRM engine plugin using provideKeyResponse. When the
+ * provided to the DRM engine plugin using provideDrmKeyResponse. When the
* response is for an offline key request, a key-set identifier is returned that
* can be used to later restore the keys to a new session with the method
- * {@ link # restoreKeys}.
+ * {@ link # restoreDrmKeys}.
* When the response is for a streaming or release request, null is returned.
*
* @param keySetId When the response is for a release request, keySetId identifies
* the saved key associated with the release request (i.e., the same keySetId
- * passed to the earlier {@ link # getKeyRequest} call. It MUST be null when the
+ * passed to the earlier {@ link # getDrmKeyRequest} call. It MUST be null when the
* response is for either streaming or offline key requests.
*
* @param response the byte array response from the server
@@ -2230,16 +2370,17 @@
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
*/
- public abstract byte[] provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
+ public abstract byte[] provideDrmKeyResponse(
+ @Nullable byte[] keySetId, @NonNull byte[] response)
throws NoDrmSchemeException, DeniedByServerException;
/**
* Restore persisted offline keys into a new session. keySetId identifies the
- * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
+ * keys to load, obtained from a prior call to {@link #provideDrmKeyResponse}.
*
* @param keySetId identifies the saved key set to restore
*/
- public abstract void restoreKeys(@NonNull byte[] keySetId)
+ public abstract void restoreDrmKeys(@NonNull byte[] keySetId)
throws NoDrmSchemeException;
/**
@@ -2252,7 +2393,8 @@
* {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
*/
@NonNull
- public abstract String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName)
+ public abstract String getDrmPropertyString(
+ @NonNull @MediaDrm.StringProperty String propertyName)
throws NoDrmSchemeException;
/**
@@ -2265,8 +2407,8 @@
* {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
* {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
*/
- public abstract void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName,
- @NonNull String value)
+ public abstract void setDrmPropertyString(
+ @NonNull @MediaDrm.StringProperty String propertyName, @NonNull String value)
throws NoDrmSchemeException;
/**
@@ -2410,4 +2552,38 @@
public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
}
+
+ /**
+ Constant to retrieve only the new metadata since the last
+ call.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean METADATA_UPDATE_ONLY = true;
+
+ /**
+ Constant to retrieve all the metadata.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean METADATA_ALL = false;
+
+ /**
+ Constant to enable the metadata filter during retrieval.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean APPLY_METADATA_FILTER = true;
+
+ /**
+ Constant to disable the metadata filter during retrieval.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean BYPASS_METADATA_FILTER = false;
+
}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 7794e08..50bf738 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -24,6 +24,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
+import android.graphics.SurfaceTexture;
+import android.media.SubtitleController.Anchor;
+import android.media.SubtitleTrack.RenderingWidget;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -45,9 +48,6 @@
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.VideoView;
-import android.graphics.SurfaceTexture;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleTrack.RenderingWidget;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -77,7 +77,6 @@
import java.util.Collections;
import java.util.concurrent.Executor;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
@@ -87,453 +86,6 @@
/**
- * MediaPlayer2 class can be used to control playback
- * of audio/video files and streams. An example on how to use the methods in
- * this class can be found in {@link android.widget.VideoView}.
- *
- * <p>Topics covered here are:
- * <ol>
- * <li><a href="#StateDiagram">State Diagram</a>
- * <li><a href="#Valid_and_Invalid_States">Valid and Invalid States</a>
- * <li><a href="#Permissions">Permissions</a>
- * <li><a href="#Callbacks">Register informational and error callbacks</a>
- * </ol>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use MediaPlayer2, read the
- * <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a> developer guide.</p>
- * </div>
- *
- * <a name="StateDiagram"></a>
- * <h3>State Diagram</h3>
- *
- * <p>Playback control of audio/video files and streams is managed as a state
- * machine. The following diagram shows the life cycle and the states of a
- * MediaPlayer2 object driven by the supported playback control operations.
- * The ovals represent the states a MediaPlayer2 object may reside
- * in. The arcs represent the playback control operations that drive the object
- * state transition. There are two types of arcs. The arcs with a single arrow
- * head represent synchronous method calls, while those with
- * a double arrow head represent asynchronous method calls.</p>
- *
- * <p><img src="../../../images/mediaplayer_state_diagram.gif"
- * alt="MediaPlayer State diagram"
- * border="0" /></p>
- *
- * <p>From this state diagram, one can see that a MediaPlayer2 object has the
- * following states:</p>
- * <ul>
- * <li>When a MediaPlayer2 object is just created using <code>new</code> or
- * after {@link #reset()} is called, it is in the <em>Idle</em> state; and after
- * {@link #close()} is called, it is in the <em>End</em> state. Between these
- * two states is the life cycle of the MediaPlayer2 object.
- * <ul>
- * <li>There is a subtle but important difference between a newly constructed
- * MediaPlayer2 object and the MediaPlayer2 object after {@link #reset()}
- * is called. It is a programming error to invoke methods such
- * as {@link #getCurrentPosition()},
- * {@link #getDuration()}, {@link #getVideoHeight()},
- * {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
- * {@link #setLooping(boolean)},
- * {@link #setVolume(float, float)}, {@link #pause()}, {@link #play()},
- * {@link #seekTo(long, int)} or
- * {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
- * methods is called right after a MediaPlayer2 object is constructed,
- * the user supplied callback method OnErrorListener.onError() won't be
- * called by the internal player engine and the object state remains
- * unchanged; but if these methods are called right after {@link #reset()},
- * the user supplied callback method OnErrorListener.onError() will be
- * invoked by the internal player engine and the object will be
- * transfered to the <em>Error</em> state. </li>
- * <li>It is also recommended that once
- * a MediaPlayer2 object is no longer being used, call {@link #close()} immediately
- * so that resources used by the internal player engine associated with the
- * MediaPlayer2 object can be released immediately. Resource may include
- * singleton resources such as hardware acceleration components and
- * failure to call {@link #close()} may cause subsequent instances of
- * MediaPlayer2 objects to fallback to software implementations or fail
- * altogether. Once the MediaPlayer2
- * object is in the <em>End</em> state, it can no longer be used and
- * there is no way to bring it back to any other state. </li>
- * <li>Furthermore,
- * the MediaPlayer2 objects created using <code>new</code> is in the
- * <em>Idle</em> state.
- * </li>
- * </ul>
- * </li>
- * <li>In general, some playback control operation may fail due to various
- * reasons, such as unsupported audio/video format, poorly interleaved
- * audio/video, resolution too high, streaming timeout, and the like.
- * Thus, error reporting and recovery is an important concern under
- * these circumstances. Sometimes, due to programming errors, invoking a playback
- * control operation in an invalid state may also occur. Under all these
- * error conditions, the internal player engine invokes a user supplied
- * EventCallback.onError() method if an EventCallback has been
- * registered beforehand via
- * {@link #registerEventCallback(Executor, EventCallback)}.
- * <ul>
- * <li>It is important to note that once an error occurs, the
- * MediaPlayer2 object enters the <em>Error</em> state (except as noted
- * above), even if an error listener has not been registered by the application.</li>
- * <li>In order to reuse a MediaPlayer2 object that is in the <em>
- * Error</em> state and recover from the error,
- * {@link #reset()} can be called to restore the object to its <em>Idle</em>
- * state.</li>
- * <li>It is good programming practice to have your application
- * register a OnErrorListener to look out for error notifications from
- * the internal player engine.</li>
- * <li>IllegalStateException is
- * thrown to prevent programming errors such as calling
- * {@link #prepareAsync()}, {@link #setDataSource(DataSourceDesc)}, or
- * {@code setPlaylist} methods in an invalid state. </li>
- * </ul>
- * </li>
- * <li>Calling
- * {@link #setDataSource(DataSourceDesc)}, or
- * {@code setPlaylist} transfers a
- * MediaPlayer2 object in the <em>Idle</em> state to the
- * <em>Initialized</em> state.
- * <ul>
- * <li>An IllegalStateException is thrown if
- * setDataSource() or setPlaylist() is called in any other state.</li>
- * <li>It is good programming
- * practice to always look out for <code>IllegalArgumentException</code>
- * and <code>IOException</code> that may be thrown from
- * <code>setDataSource</code> and <code>setPlaylist</code> methods.</li>
- * </ul>
- * </li>
- * <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
- * before playback can be started.
- * <ul>
- * <li>{@link #prepareAsync()} first transfers the object to the
- * <em>Preparing</em> state after the
- * call returns (which occurs almost right way) while the internal
- * player engine continues working on the rest of preparation work
- * until the preparation work completes. When the preparation completes,
- * the internal player engine then calls a user supplied callback method,
- * onPrepared() of the EventCallback interface, if an
- * EventCallback is registered beforehand via {@link
- * #registerEventCallback(Executor, EventCallback)}.</li>
- * <li>It is important to note that
- * the <em>Preparing</em> state is a transient state, and the behavior
- * of calling any method with side effect while a MediaPlayer2 object is
- * in the <em>Preparing</em> state is undefined.</li>
- * <li>An IllegalStateException is
- * thrown if {@link #prepareAsync()} is called in
- * any other state.</li>
- * <li>While in the <em>Prepared</em> state, properties
- * such as audio/sound volume, screenOnWhilePlaying, looping can be
- * adjusted by invoking the corresponding set methods.</li>
- * </ul>
- * </li>
- * <li>To start the playback, {@link #play()} must be called. After
- * {@link #play()} returns successfully, the MediaPlayer2 object is in the
- * <em>Started</em> state. {@link #isPlaying()} can be called to test
- * whether the MediaPlayer2 object is in the <em>Started</em> state.
- * <ul>
- * <li>While in the <em>Started</em> state, the internal player engine calls
- * a user supplied EventCallback.onBufferingUpdate() callback
- * method if an EventCallback has been registered beforehand
- * via {@link #registerEventCallback(Executor, EventCallback)}.
- * This callback allows applications to keep track of the buffering status
- * while streaming audio/video.</li>
- * <li>Calling {@link #play()} has not effect
- * on a MediaPlayer2 object that is already in the <em>Started</em> state.</li>
- * </ul>
- * </li>
- * <li>Playback can be paused and stopped, and the current playback position
- * can be adjusted. Playback can be paused via {@link #pause()}. When the call to
- * {@link #pause()} returns, the MediaPlayer2 object enters the
- * <em>Paused</em> state. Note that the transition from the <em>Started</em>
- * state to the <em>Paused</em> state and vice versa happens
- * asynchronously in the player engine. It may take some time before
- * the state is updated in calls to {@link #isPlaying()}, and it can be
- * a number of seconds in the case of streamed content.
- * <ul>
- * <li>Calling {@link #play()} to resume playback for a paused
- * MediaPlayer2 object, and the resumed playback
- * position is the same as where it was paused. When the call to
- * {@link #play()} returns, the paused MediaPlayer2 object goes back to
- * the <em>Started</em> state.</li>
- * <li>Calling {@link #pause()} has no effect on
- * a MediaPlayer2 object that is already in the <em>Paused</em> state.</li>
- * </ul>
- * </li>
- * <li>The playback position can be adjusted with a call to
- * {@link #seekTo(long, int)}.
- * <ul>
- * <li>Although the asynchronuous {@link #seekTo(long, int)}
- * call returns right away, the actual seek operation may take a while to
- * finish, especially for audio/video being streamed. When the actual
- * seek operation completes, the internal player engine calls a user
- * supplied EventCallback.onSeekComplete() if an EventCallback
- * has been registered beforehand via
- * {@link #registerEventCallback(Executor, EventCallback)}.</li>
- * <li>Please
- * note that {@link #seekTo(long, int)} can also be called in the other states,
- * such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
- * </em> state. When {@link #seekTo(long, int)} is called in those states,
- * one video frame will be displayed if the stream has video and the requested
- * position is valid.
- * </li>
- * <li>Furthermore, the actual current playback position
- * can be retrieved with a call to {@link #getCurrentPosition()}, which
- * is helpful for applications such as a Music player that need to keep
- * track of the playback progress.</li>
- * </ul>
- * </li>
- * <li>When the playback reaches the end of stream, the playback completes.
- * <ul>
- * <li>If the looping mode was being set to <var>true</var>with
- * {@link #setLooping(boolean)}, the MediaPlayer2 object shall remain in
- * the <em>Started</em> state.</li>
- * <li>If the looping mode was set to <var>false
- * </var>, the player engine calls a user supplied callback method,
- * EventCallback.onCompletion(), if an EventCallback is registered
- * beforehand via {@link #registerEventCallback(Executor, EventCallback)}.
- * The invoke of the callback signals that the object is now in the <em>
- * PlaybackCompleted</em> state.</li>
- * <li>While in the <em>PlaybackCompleted</em>
- * state, calling {@link #play()} can restart the playback from the
- * beginning of the audio/video source.</li>
- * </ul>
- *
- *
- * <a name="Valid_and_Invalid_States"></a>
- * <h3>Valid and invalid states</h3>
- *
- * <table border="0" cellspacing="0" cellpadding="0">
- * <tr><td>Method Name </p></td>
- * <td>Valid Sates </p></td>
- * <td>Invalid States </p></td>
- * <td>Comments </p></td></tr>
- * <tr><td>attachAuxEffect </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
- * <td>{Idle, Error} </p></td>
- * <td>This method must be called after setDataSource or setPlaylist.
- * Calling it does not change the object state. </p></td></tr>
- * <tr><td>getAudioSessionId </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>getCurrentPosition </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted} </p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change the
- * state. Calling this method in an invalid state transfers the object
- * to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getDuration </p></td>
- * <td>{Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
- * <td>{Idle, Initialized, Error} </p></td>
- * <td>Successful invoke of this method in a valid state does not change the
- * state. Calling this method in an invalid state transfers the object
- * to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getVideoHeight </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change the
- * state. Calling this method in an invalid state transfers the object
- * to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getVideoWidth </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an invalid state transfers the
- * object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>isPlaying </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an invalid state transfers the
- * object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>pause </p></td>
- * <td>{Started, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Paused</em> state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>prepare </p></td>
- * <td>{Initialized, Stopped} </p></td>
- * <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Prepared</em> state. Calling this method in an
- * invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>prepareAsync </p></td>
- * <td>{Initialized, Stopped} </p></td>
- * <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Preparing</em> state. Calling this method in an
- * invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>release </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>After {@link #close()}, the object is no longer available. </p></td></tr>
- * <tr><td>reset </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted, Error}</p></td>
- * <td>{}</p></td>
- * <td>After {@link #reset()}, the object is like being just created.</p></td></tr>
- * <tr><td>seekTo </p></td>
- * <td>{Prepared, Started, Paused, PlaybackCompleted} </p></td>
- * <td>{Idle, Initialized, Stopped, Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an invalid state transfers the
- * object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>setAudioAttributes </p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method does not change the state. In order for the
- * target audio attributes type to become effective, this method must be called before
- * prepareAsync().</p></td></tr>
- * <tr><td>setAudioSessionId </p></td>
- * <td>{Idle} </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
- * Error} </p></td>
- * <td>This method must be called in idle state as the audio session ID must be known before
- * calling setDataSource or setPlaylist. Calling it does not change the object
- * state. </p></td></tr>
- * <tr><td>setAudioStreamType (deprecated)</p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method does not change the state. In order for the
- * target audio stream type to become effective, this method must be called before
- * prepareAsync().</p></td></tr>
- * <tr><td>setAuxEffectSendLevel </p></td>
- * <td>any</p></td>
- * <td>{} </p></td>
- * <td>Calling this method does not change the object state. </p></td></tr>
- * <tr><td>setDataSource </p></td>
- * <td>{Idle} </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
- * Error} </p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Initialized</em> state. Calling this method in an
- * invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>setPlaylist </p></td>
- * <td>{Idle} </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
- * Error} </p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Initialized</em> state. Calling this method in an
- * invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>setDisplay </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setSurface </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setVideoScalingMode </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
- * <td>{Idle, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- * <tr><td>setLooping </p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>isLooping </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>registerDrmEventCallback </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>registerEventCallback </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setPlaybackParams</p></td>
- * <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
- * <td>{Idle, Stopped} </p></td>
- * <td>This method will change state in some cases, depending on when it's called.
- * </p></td></tr>
- * <tr><td>setScreenOnWhilePlaying</></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setVolume </p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method does not change the state.
- * <tr><td>setWakeMode </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state.</p></td></tr>
- * <tr><td>start </p></td>
- * <td>{Prepared, Started, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Stopped, Error}</p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Started</em> state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>stop </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Stopped</em> state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>getTrackInfo </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- * <tr><td>addTimedTextSource </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- * <tr><td>selectTrack </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- * <tr><td>deselectTrack </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- *
- * </table>
- *
- * <a name="Permissions"></a>
- * <h3>Permissions</h3>
- * <p>One may need to declare a corresponding WAKE_LOCK permission {@link
- * android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
- * element.
- *
- * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
- * when used with network-based content.
- *
- * <a name="Callbacks"></a>
- * <h3>Callbacks</h3>
- * <p>Applications may want to register for informational and error
- * events in order to be informed of some internal state update and
- * possible runtime errors during playback or streaming. Registration for
- * these events is done by properly setting the appropriate listeners (via calls
- * to
- * {@link #registerEventCallback(Executor, EventCallback)},
- * {@link #registerDrmEventCallback(Executor, DrmEventCallback)}).
- * In order to receive the respective callback
- * associated with these listeners, applications are required to create
- * MediaPlayer2 objects on a thread with its own Looper running (main UI
- * thread by default has a Looper running).
- *
* @hide
*/
public final class MediaPlayer2Impl extends MediaPlayer2 {
@@ -558,12 +110,13 @@
private final CloseGuard mGuard = CloseGuard.get();
private final Object mPlLock = new Object();
+ private DataSourceDesc mCurrentDSD;
+ private long mCurrentSrcId = 0;
private List<DataSourceDesc> mPlaylist;
- private int mPlCurrentIndex = 0;
+ private long mNextSrcId = mCurrentSrcId + 1;
private int mPlNextIndex = -1;
private int mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
private boolean mPlNextSourcePlayPending = false;
- private int mLoopingMode = LOOPING_MODE_NONE;
// Modular DRM
private UUID mDrmUUID;
@@ -604,6 +157,381 @@
native_setup(new WeakReference<MediaPlayer2Impl>(this));
}
+ /**
+ * Releases the resources held by this {@code MediaPlayer2} object.
+ *
+ * It is considered good practice to call this method when you're
+ * done using the MediaPlayer2. In particular, whenever an Activity
+ * of an application is paused (its onPause() method is called),
+ * or stopped (its onStop() method is called), this method should be
+ * invoked to release the MediaPlayer2 object, unless the application
+ * has a special need to keep the object around. In addition to
+ * unnecessary resources (such as memory and instances of codecs)
+ * being held, failure to call this method immediately if a
+ * MediaPlayer2 object is no longer needed may also lead to
+ * continuous battery consumption for mobile devices, and playback
+ * failure for other applications if no multiple instances of the
+ * same codec are supported on a device. Even if multiple instances
+ * of the same codec are supported, some performance degradation
+ * may be expected when unnecessary multiple instances are used
+ * at the same time.
+ *
+ * {@code close()} may be safely called after a prior {@code close()}.
+ * This class implements the Java {@code AutoCloseable} interface and
+ * may be used with try-with-resources.
+ */
+ @Override
+ public void close() {
+ synchronized (mGuard) {
+ release();
+ }
+ }
+
+ /**
+ * Starts or resumes playback. If playback had previously been paused,
+ * playback will continue from where it was paused. If playback had
+ * been stopped, or never started before, playback will start at the
+ * beginning.
+ *
+ * @throws IllegalStateException if it is called in an invalid state
+ */
+ @Override
+ public void play() {
+ stayAwake(true);
+ _start();
+ }
+
+ private native void _start() throws IllegalStateException;
+
+ /**
+ * Prepares the player for playback, asynchronously.
+ *
+ * After setting the datasource and the display surface, you need to either
+ * call prepare(). For streams, you should call prepare(),
+ * which returns immediately, rather than blocking until enough data has been
+ * buffered.
+ *
+ * @throws IllegalStateException if it is called in an invalid state
+ */
+ @Override
+ public native void prepare();
+
+ /**
+ * Pauses playback. Call play() to resume.
+ *
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized.
+ */
+ @Override
+ public void pause() {
+ stayAwake(false);
+ _pause();
+ }
+
+ private native void _pause() throws IllegalStateException;
+
+ /**
+ * Tries to play next data source if applicable.
+ *
+ * @throws IllegalStateException if it is called in an invalid state
+ */
+ @Override
+ public void skipToNext() {
+ // TODO: switch to next data source and play
+ }
+
+ /**
+ * Gets the current playback position.
+ *
+ * @return the current position in milliseconds
+ */
+ @Override
+ public native long getCurrentPosition();
+
+ /**
+ * Gets the duration of the file.
+ *
+ * @return the duration in milliseconds, if no duration is available
+ * (for example, if streaming live content), -1 is returned.
+ */
+ @Override
+ public native long getDuration();
+
+ /**
+ * Gets the current buffered media source position received through progressive downloading.
+ * The received buffering percentage indicates how much of the content has been buffered
+ * or played. For example a buffering update of 80 percent when half the content
+ * has already been played indicates that the next 30 percent of the
+ * content to play has been buffered.
+ *
+ * @return the current buffered media source position in milliseconds
+ */
+ @Override
+ public long getBufferedPosition() {
+ // TODO: either get buffered position from native code, or cache BUFFERING_UPDATE
+ // number and convert it to buffered position.
+ return 0;
+ }
+
+ /**
+ * Gets the current player state.
+ *
+ * @return the current player state, one of the following:
+ * <ul>
+ * <li>{@link #PLAYER_STATE_IDLE}
+ * <li>{@link #PLAYER_STATE_PAUSED}
+ * <li>{@link #PLAYER_STATE_PLAYING}
+ * <li>{@link #PLAYER_STATE_ERROR}
+ * </ul>
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized or has been released.
+ */
+ @Override
+ public @PlayerState int getPlayerState() {
+ // TODO: use cached state or call native function.
+ return PLAYER_STATE_IDLE;
+ }
+
+ /**
+ * Gets the current buffering state of the player.
+ * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
+ * buffered.
+ * @return the buffering state, one of the following:
+ * <ul>
+ * <li>{@link #BUFFERING_STATE_UNKNOWN}
+ * <li>{@link #BUFFERING_STATE_BUFFERING_AND_PLAYABLE}
+ * <li>{@link #BUFFERING_STATE_BUFFERING_AND_STARVED}
+ * <li>{@link #BUFFERING_STATE_BUFFERING_COMPLETE}
+ * </ul>
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized or has been released.
+ */
+ @Override
+ public @BuffState int getBufferingState() {
+ // TODO: use cached state or call native function.
+ return BUFFERING_STATE_UNKNOWN;
+ }
+
+ /**
+ * Sets the audio attributes for this MediaPlayer2.
+ * See {@link AudioAttributes} for how to build and configure an instance of this class.
+ * You must call this method before {@link #prepare()} in order
+ * for the audio attributes to become effective thereafter.
+ * @param attributes a non-null set of audio attributes
+ * @throws IllegalArgumentException if the attributes are null or invalid.
+ */
+ @Override
+ public void setAudioAttributes(@NonNull AudioAttributes attributes) {
+ if (attributes == null) {
+ final String msg = "Cannot set AudioAttributes to null";
+ throw new IllegalArgumentException(msg);
+ }
+ mUsage = attributes.getUsage();
+ mBypassInterruptionPolicy = (attributes.getAllFlags()
+ & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
+ Parcel pattributes = Parcel.obtain();
+ attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
+ setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
+ pattributes.recycle();
+ }
+
+ @Override
+ public @NonNull AudioAttributes getAudioAttributes() {
+ Parcel pattributes = getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES);
+ AudioAttributes attributes = AudioAttributes.CREATOR.createFromParcel(pattributes);
+ pattributes.recycle();
+ return attributes;
+ }
+
+ /**
+ * Sets the data source as described by a DataSourceDesc.
+ *
+ * @param dsd the descriptor of data source you want to play
+ * @throws IllegalStateException if it is called in an invalid state
+ * @throws NullPointerException if dsd is null
+ */
+ @Override
+ public void setDataSource(@NonNull DataSourceDesc dsd) {
+ Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
+ synchronized (mPlLock) {
+ mCurrentDSD = dsd;
+ try {
+ handleDataSource(true /* isCurrent */, dsd);
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ /**
+ * Sets a single data source as described by a DataSourceDesc which will be played
+ * after current data source is finished.
+ *
+ * @param dsd the descriptor of data source you want to play after current one
+ * @throws IllegalStateException if it is called in an invalid state
+ * @throws NullPointerException if dsd is null
+ */
+ @Override
+ public void setNextDataSource(@NonNull DataSourceDesc dsd) {
+ Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
+
+ // TODO: save dsd in a list
+ }
+
+ /**
+ * Sets a list of data sources to be played sequentially after current data source is done.
+ *
+ * @param dsds the list of data sources you want to play after current one
+ * @throws IllegalStateException if it is called in an invalid state
+ * @throws IllegalArgumentException if dsds is null or empty, or contains null DataSourceDesc
+ */
+ @Override
+ public void setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
+ // TODO: save the list.
+ /*
+ if (dsds == null || dsds.size() == 0) {
+ throw new IllegalArgumentException("data source list cannot be null or empty.");
+ }
+ HashSet ids = new HashSet(pl.size());
+ for (DataSourceDesc dsd : pl) {
+ if (dsd == null) {
+ throw new IllegalArgumentException("DataSourceDesc in playlist cannot be null.");
+ }
+ if (ids.add(dsd.getId()) == false) {
+ throw new IllegalArgumentException("DataSourceDesc Id in playlist should be unique.");
+ }
+ }
+
+ if (startIndex < 0) {
+ startIndex = 0;
+ } else if (startIndex >= pl.size()) {
+ startIndex = pl.size() - 1;
+ }
+
+ synchronized (mPlLock) {
+ mPlaylist = Collections.synchronizedList(new ArrayList(pl));
+ handleDataSource(true, mPlaylist.get(startIndex));
+ // TODO: handle the preparation of next source in the playlist.
+ // It should be processed after current source is prepared.
+ mPlNextIndex = getNextIndex_l();
+ }
+ */
+ }
+
+ /**
+ * Gets the current data source as described by a DataSourceDesc.
+ *
+ * @return the current DataSourceDesc
+ */
+ @Override
+ public @NonNull DataSourceDesc getCurrentDataSource() {
+ synchronized (mPlLock) {
+ return mCurrentDSD;
+ }
+ }
+
+ /**
+ * Configures the player to loop on the current data source.
+ * @param loop true if the current data source is meant to loop.
+ */
+ @Override
+ public void loopCurrent(boolean loop) {
+ // TODO: set the looping mode, send notification
+ setLooping(loop);
+ }
+
+ private native void setLooping(boolean looping);
+
+ /**
+ * Sets the playback speed.
+ * A value of 1.0f is the default playback value.
+ * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
+ * before using negative values.<br>
+ * After changing the playback speed, it is recommended to query the actual speed supported
+ * by the player, see {@link #getPlaybackSpeed()}.
+ * @param speed the desired playback speed
+ */
+ @Override
+ public void setPlaybackSpeed(float speed) {
+ // TODO: send notification
+ setPlaybackParams(getPlaybackParams().setSpeed(speed));
+ }
+
+ /**
+ * Returns the actual playback speed to be used by the player when playing.
+ * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
+ * @return the actual playback speed
+ */
+ @Override
+ public float getPlaybackSpeed() {
+ return getPlaybackParams().getSpeed();
+ }
+
+ /**
+ * Indicates whether reverse playback is supported.
+ * Reverse playback is indicated by negative playback speeds, see
+ * {@link #setPlaybackSpeed(float)}.
+ * @return true if reverse playback is supported.
+ */
+ @Override
+ public boolean isReversePlaybackSupported() {
+ return false;
+ }
+
+ /**
+ * Sets the volume of the audio of the media to play, expressed as a linear multiplier
+ * on the audio samples.
+ * Note that this volume is specific to the player, and is separate from stream volume
+ * used across the platform.<br>
+ * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
+ * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
+ * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
+ */
+ @Override
+ public void setPlayerVolume(float volume) {
+ // send notification
+ _setVolume(volume, volume);
+ }
+
+ private native void _setVolume(float leftVolume, float rightVolume);
+
+ /**
+ * Returns the current volume of this player to this player.
+ * Note that it does not take into account the associated stream volume.
+ * @return the player volume.
+ */
+ @Override
+ public float getPlayerVolume() {
+ // TODO: get real volume
+ return 1.0f;
+ }
+
+ /**
+ * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
+ */
+ @Override
+ public float getMaxPlayerVolume() {
+ return 1.0f;
+ }
+
+ /**
+ * Adds a callback to be notified of events for this player.
+ * @param e the {@link Executor} to be used for the events.
+ * @param cb the callback to receive the events.
+ */
+ @Override
+ public void registerPlayerEventCallback(@NonNull Executor e,
+ @NonNull PlayerEventCallback cb) {
+ }
+
+ /**
+ * Removes a previously registered callback for player events
+ * @param cb the callback to remove
+ */
+ @Override
+ public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb) {
+ }
+
+
private static final int NEXT_SOURCE_STATE_ERROR = -1;
private static final int NEXT_SOURCE_STATE_INIT = 0;
private static final int NEXT_SOURCE_STATE_PREPARING = 1;
@@ -666,6 +594,11 @@
}
}
+ @Override
+ public void notifyWhenCommandLabelReached(Object label) {
+ // TODO: create an entry in command queue
+ }
+
/**
* Sets the {@link SurfaceHolder} to use for displaying the video
* portion of the media.
@@ -768,335 +701,6 @@
public void clearPendingCommands() {
}
- /**
- * Sets the data source as described by a DataSourceDesc.
- *
- * @param dsd the descriptor of data source you want to play
- * @throws IllegalStateException if it is called in an invalid state
- * @throws NullPointerException if dsd is null
- */
- @Override
- public void setDataSource(@NonNull DataSourceDesc dsd) throws IOException {
- Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- synchronized (mPlLock) {
- mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
- mPlaylist.add(dsd);
- mPlCurrentIndex = 0;
- mPlNextIndex = -1;
- handleDataSource(true /* isCurrent */, dsd);
- }
- }
-
- /**
- * Gets the current data source as described by a DataSourceDesc.
- *
- * @return the current DataSourceDesc
- */
- @Override
- public DataSourceDesc getCurrentDataSource() {
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- return null;
- }
- return mPlaylist.get(mPlCurrentIndex);
- }
- }
-
- /**
- * Sets the play list.
- *
- * If startIndex falls outside play list range, it will be clamped to the nearest index
- * in the play list.
- *
- * @param pl the play list of data source you want to play
- * @param startIndex the index of the DataSourceDesc in the play list you want to play first
- * @throws IllegalStateException if it is called in an invalid state
- * @throws IllegalArgumentException if pl is null or empty, or pl contains null DataSourceDesc
- */
- @Override
- public void setPlaylist(@NonNull List<DataSourceDesc> pl, int startIndex)
- throws IOException {
- if (pl == null || pl.size() == 0) {
- throw new IllegalArgumentException("play list cannot be null or empty.");
- }
- HashSet ids = new HashSet(pl.size());
- for (DataSourceDesc dsd : pl) {
- if (dsd == null) {
- throw new IllegalArgumentException("DataSourceDesc in play list cannot be null.");
- }
- if (ids.add(dsd.getId()) == false) {
- throw new IllegalArgumentException("DataSourceDesc Id in play list should be unique.");
- }
- }
-
- if (startIndex < 0) {
- startIndex = 0;
- } else if (startIndex >= pl.size()) {
- startIndex = pl.size() - 1;
- }
-
- synchronized (mPlLock) {
- mPlaylist = Collections.synchronizedList(new ArrayList(pl));
- mPlCurrentIndex = startIndex;
- handleDataSource(true /* isCurrent */, mPlaylist.get(startIndex));
- // TODO: handle the preparation of next source in the play list.
- // It should be processed after current source is prepared.
- mPlNextIndex = getNextIndex_l();
- }
- }
-
- /**
- * Gets a copy of the play list.
- *
- * @return a copy of the play list used by {@link MediaPlayer2}
- */
- @Override
- public List<DataSourceDesc> getPlaylist() {
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- return null;
- }
- return new ArrayList(mPlaylist);
- }
- }
-
- /**
- * Sets the index of current DataSourceDesc in the play list to be played.
- *
- * @param index the index of DataSourceDesc in the play list you want to play
- * @throws IllegalArgumentException if the play list is null
- * @throws NullPointerException if index is outside play list range
- */
- @Override
- public void setCurrentPlaylistItem(int index) {
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- if (index < 0 || index >= mPlaylist.size()) {
- throw new IndexOutOfBoundsException("index is out of play list range.");
- }
-
- if (index == mPlCurrentIndex) {
- return;
- }
-
- // TODO: in playing state, stop current source and start to play source of index.
- mPlCurrentIndex = index;
- }
- }
-
- /**
- * Sets the index of next-to-be-played DataSourceDesc in the play list.
- *
- * @param index the index of next-to-be-played DataSourceDesc in the play list
- * @throws IllegalArgumentException if the play list is null
- * @throws NullPointerException if index is outside play list range
- */
- @Override
- public void setNextPlaylistItem(int index) {
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- if (index < 0 || index >= mPlaylist.size()) {
- throw new IndexOutOfBoundsException("index is out of play list range.");
- }
-
- if (index == mPlNextIndex) {
- return;
- }
-
- // TODO: prepare the new next-to-be-played DataSourceDesc
- mPlNextIndex = index;
- }
- }
-
- /**
- * Gets the current index of play list.
- *
- * @return the index of the current DataSourceDesc in the play list
- */
- @Override
- public int getCurrentPlaylistItemIndex() {
- synchronized (mPlLock) {
- return mPlCurrentIndex;
- }
- }
-
- /**
- * Sets the looping mode of the play list.
- * The mode shall be one of {@link #LOOPING_MODE_NONE}, {@link #LOOPING_MODE_FULL},
- * {@link #LOOPING_MODE_SINGLE}, {@link #LOOPING_MODE_SHUFFLE}.
- *
- * @param mode the mode in which the play list will be played
- * @throws IllegalArgumentException if mode is not supported
- */
- @Override
- public void setLoopingMode(@LoopingMode int mode) {
- if (mode != LOOPING_MODE_NONE
- && mode != LOOPING_MODE_FULL
- && mode != LOOPING_MODE_SINGLE
- && mode != LOOPING_MODE_SHUFFLE) {
- throw new IllegalArgumentException("mode is not supported.");
- }
-
- synchronized (mPlLock) {
- mLoopingMode = mode;
- if (mPlaylist == null) {
- return;
- }
-
- // TODO: handle the new mode if necessary.
- }
- }
-
- /**
- * Gets the looping mode of play list.
- *
- * @return the looping mode of the play list
- */
- @Override
- public int getLoopingMode() {
- synchronized (mPlLock) {
- return mPlCurrentIndex;
- }
- }
-
- /**
- * Moves the DataSourceDesc at indexFrom in the play list to indexTo.
- *
- * @throws IllegalArgumentException if the play list is null
- * @throws IndexOutOfBoundsException if indexFrom or indexTo is outside play list range
- */
- @Override
- public void movePlaylistItem(int indexFrom, int indexTo) {
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- // TODO: move the DataSourceDesc from indexFrom to indexTo.
- }
- }
-
- /**
- * Removes the DataSourceDesc at index in the play list.
- *
- * If index is same as the current index of the play list, current DataSourceDesc
- * will be stopped and playback moves to next source in the list.
- *
- * @return the removed DataSourceDesc at index in the play list
- * @throws IllegalArgumentException if the play list is null
- * @throws IndexOutOfBoundsException if index is outside play list range
- */
- @Override
- public DataSourceDesc removePlaylistItem(int index) {
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
-
- DataSourceDesc oldDsd = mPlaylist.remove(index);
- // TODO: if index == mPlCurrentIndex, stop current source and move to next one.
- // if index == mPlNextIndex, prepare the new next-to-be-played source.
- return oldDsd;
- }
- }
-
- /**
- * Inserts the DataSourceDesc to the play list at position index.
- *
- * This will not change the DataSourceDesc currently being played.
- * If index is less than or equal to the current index of the play list,
- * the current index of the play list will be incremented correspondingly.
- *
- * @param index the index you want to add dsd to the play list
- * @param dsd the descriptor of data source you want to add to the play list
- * @throws IndexOutOfBoundsException if index is outside play list range
- * @throws NullPointerException if dsd is null
- */
- @Override
- public void addPlaylistItem(int index, DataSourceDesc dsd) {
- Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
-
- synchronized (mPlLock) {
- if (mPlaylist == null) {
- if (index == 0) {
- mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
- mPlaylist.add(dsd);
- mPlCurrentIndex = 0;
- return;
- }
- throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
- }
-
- long id = dsd.getId();
- for (DataSourceDesc pldsd : mPlaylist) {
- if (id == pldsd.getId()) {
- throw new IllegalArgumentException("Id of dsd already exists in the play list.");
- }
- }
-
- mPlaylist.add(index, dsd);
- if (index <= mPlCurrentIndex) {
- ++mPlCurrentIndex;
- }
- }
- }
-
- /**
- * replaces the DataSourceDesc at index in the play list with given dsd.
- *
- * When index is same as the current index of the play list, the current source
- * will be stopped and the new source will be played, except that if new
- * and old source only differ on end position and current media position is
- * smaller then the new end position.
- *
- * This will not change the DataSourceDesc currently being played.
- * If index is less than or equal to the current index of the play list,
- * the current index of the play list will be incremented correspondingly.
- *
- * @param index the index you want to add dsd to the play list
- * @param dsd the descriptor of data source you want to add to the play list
- * @throws IndexOutOfBoundsException if index is outside play list range
- * @throws NullPointerException if dsd is null
- */
- @Override
- public DataSourceDesc editPlaylistItem(int index, DataSourceDesc dsd) {
- Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- Preconditions.checkNotNull(mPlaylist, "the play list cannot be null");
-
- long id = dsd.getId();
- synchronized (mPlLock) {
- for (int i = 0; i < mPlaylist.size(); ++i) {
- if (i == index) {
- continue;
- }
- if (id == mPlaylist.get(i).getId()) {
- throw new IllegalArgumentException(
- "Id of dsd already exists in the play list.");
- }
- }
-
- // TODO: if needed, stop playback of current source, and start new dsd.
- DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
- return mPlaylist.set(index, dsd);
- }
- }
-
- // Called with mPlLock acquired.
- // TODO: support all looping modes
- private int getNextIndex_l() {
- if (mPlaylist.size() <= 1) {
- return -1;
- }
- int index = mPlCurrentIndex + 1;
- if (index >= mPlaylist.size()) {
- index = 0;
- }
- return index;
- }
-
private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd)
throws IOException {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
@@ -1104,13 +708,13 @@
switch (dsd.getType()) {
case DataSourceDesc.TYPE_CALLBACK:
handleDataSource(isCurrent,
- dsd.getId(),
+ 0, // TODO: get mapped Id
dsd.getMedia2DataSource());
break;
case DataSourceDesc.TYPE_FD:
handleDataSource(isCurrent,
- dsd.getId(),
+ 0, // TODO: get mapped Id
dsd.getFileDescriptor(),
dsd.getFileDescriptorOffset(),
dsd.getFileDescriptorLength());
@@ -1118,7 +722,7 @@
case DataSourceDesc.TYPE_URI:
handleDataSource(isCurrent,
- dsd.getId(),
+ 0, // TODO: get mapped Id
dsd.getUriContext(),
dsd.getUri(),
dsd.getUriHeaders(),
@@ -1304,11 +908,11 @@
try {
mPlNextSourceState = NEXT_SOURCE_STATE_PREPARING;
- handleDataSource(false /* isCurrent */, mPlaylist.get(mPlNextIndex));
+ handleDataSource(false /* isCurrent */, mPlaylist.get(0));
} catch (Exception e) {
Message msg2 = mEventHandler.obtainMessage(
MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
- final long nextSrcId = mPlaylist.get(mPlNextIndex).getId();
+ final long nextSrcId = mNextSrcId;
mEventHandler.post(new Runnable() {
@Override
public void run() {
@@ -1326,12 +930,12 @@
if (mPlNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
// Switch to next source only when it's in prepared state.
- mPlCurrentIndex = mPlNextIndex;
- mPlNextIndex = getNextIndex_l();
+ mCurrentSrcId = mNextSrcId;
+ mNextSrcId = 0; // TODO; fix it
mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
mPlNextSourcePlayPending = false;
- long srcId = mPlaylist.get(mPlCurrentIndex).getId();
+ long srcId = mCurrentSrcId;
try {
nativePlayNextDataSource(srcId);
} catch (Exception e) {
@@ -1356,35 +960,6 @@
private native void nativePlayNextDataSource(long srcId);
- /**
- * Prepares the player for playback, asynchronously.
- *
- * After setting the datasource and the display surface, you need to either
- * call prepareAsync(). For streams, you should call prepareAsync(),
- * which returns immediately, rather than blocking until enough data has been
- * buffered.
- *
- * @throws IllegalStateException if it is called in an invalid state
- */
- @Override
- public native void prepareAsync();
-
- /**
- * Starts or resumes playback. If playback had previously been paused,
- * playback will continue from where it was paused. If playback had
- * been stopped, or never started before, playback will start at the
- * beginning.
- *
- * @throws IllegalStateException if it is called in an invalid state
- */
- @Override
- public void play() {
- stayAwake(true);
- _start();
- }
-
- private native void _start() throws IllegalStateException;
-
private int getAudioStreamType() {
if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
@@ -1410,20 +985,6 @@
private native void _stop() throws IllegalStateException;
- /**
- * Pauses playback. Call play() to resume.
- *
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
- */
- @Override
- public void pause() {
- stayAwake(false);
- _pause();
- }
-
- private native void _pause() throws IllegalStateException;
-
//--------------------------------------------------------------------------
// Explicit Routing
//--------------------
@@ -1634,9 +1195,10 @@
*
* @return the width of the video, or 0 if there is no video,
* no display surface was set, or the width has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #registerEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the width is available.
+ * yet. The {@code MediaPlayer2EventCallback} can be registered via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
+ * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the width
+ * is available.
*/
@Override
public native int getVideoWidth();
@@ -1646,9 +1208,10 @@
*
* @return the height of the video, or 0 if there is no video,
* no display surface was set, or the height has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #registerEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the height is available.
+ * yet. The {@code MediaPlayer2EventCallback} can be registered via
+ * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
+ * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the height
+ * is available.
*/
@Override
public native int getVideoHeight();
@@ -1677,11 +1240,32 @@
* @return true if currently playing, false otherwise
* @throws IllegalStateException if the internal player engine has not been
* initialized or has been released.
+ * @hide
*/
@Override
public native boolean isPlaying();
/**
+ * Gets the current MediaPlayer2 state.
+ *
+ * @return the current MediaPlayer2 state, one of the following:
+ * <ul>
+ * <li>{@link #MEDIAPLAYER2_STATE_IDLE}
+ * <li>{@link #MEDIAPLAYER2_STATE_PREPARED}
+ * <li>{@link #MEDIAPLAYER2_STATE_PAUSED}
+ * <li>{@link #MEDIAPLAYER2_STATE_PLAYING}
+ * <li>{@link #MEDIAPLAYER2_STATE_ERROR}
+ * </ul>
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized or has been released.
+ */
+ @Override
+ public @MediaPlayer2State int getMediaPlayer2State() {
+ // TODO: get state from native layer or cached value.
+ return MEDIAPLAYER2_STATE_IDLE;
+ }
+
+ /**
* Gets the current buffering management params used by the source component.
* Calling it only after {@code setDataSource} has been called.
* Each type of data source might have different set of default params.
@@ -1801,8 +1385,6 @@
@NonNull
public native SyncParams getSyncParams();
- private native final void _seekTo(long msec, int mode);
-
/**
* Moves the media to specified time position by considering the given mode.
* <p>
@@ -1850,6 +1432,8 @@
_seekTo(msec, mode);
}
+ private native final void _seekTo(long msec, int mode);
+
/**
* Get current playback position as a {@link MediaTimestamp}.
* <p>
@@ -1884,23 +1468,6 @@
}
/**
- * Gets the current playback position.
- *
- * @return the current position in milliseconds
- */
- @Override
- public native long getCurrentPosition();
-
- /**
- * Gets the duration of the file.
- *
- * @return the duration in milliseconds, if no duration is available
- * (for example, if streaming live content), -1 is returned.
- */
- @Override
- public native long getDuration();
-
- /**
* Gets the media metadata.
*
* @param update_only controls whether the full set of available
@@ -1988,7 +1555,7 @@
/**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
- * data source and calling prepareAsync().
+ * data source and calling prepare().
*/
@Override
public void reset() {
@@ -2061,45 +1628,6 @@
private native Parcel getParameter(int key);
- /**
- * Sets the audio attributes for this MediaPlayer2.
- * See {@link AudioAttributes} for how to build and configure an instance of this class.
- * You must call this method before {@link #prepareAsync()} in order
- * for the audio attributes to become effective thereafter.
- * @param attributes a non-null set of audio attributes
- * @throws IllegalArgumentException if the attributes are null or invalid.
- */
- @Override
- public void setAudioAttributes(AudioAttributes attributes) {
- if (attributes == null) {
- final String msg = "Cannot set AudioAttributes to null";
- throw new IllegalArgumentException(msg);
- }
- mUsage = attributes.getUsage();
- mBypassInterruptionPolicy = (attributes.getAllFlags()
- & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
- Parcel pattributes = Parcel.obtain();
- attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
- setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
- pattributes.recycle();
- }
-
- @Override
- public AudioAttributes getAudioAttributes() {
- Parcel pattributes = getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES);
- AudioAttributes attributes = AudioAttributes.CREATOR.createFromParcel(pattributes);
- pattributes.recycle();
- return attributes;
- }
-
- /**
- * Sets the player to be looping or non-looping.
- *
- * @param looping whether to loop or not
- * @hide
- */
- @Override
- public native void setLooping(boolean looping);
/**
* Checks whether the MediaPlayer2 is looping or non-looping.
@@ -2111,39 +1639,6 @@
public native boolean isLooping();
/**
- * Sets the volume on this player.
- * This API is recommended for balancing the output of audio streams
- * within an application. Unless you are writing an application to
- * control user settings, this API should be used in preference to
- * {@link AudioManager#setStreamVolume(int, int, int)} which sets the volume of ALL streams of
- * a particular type. Note that the passed volume values are raw scalars in range 0.0 to 1.0.
- * UI controls should be scaled logarithmically.
- *
- * @param leftVolume left volume scalar
- * @param rightVolume right volume scalar
- */
- /*
- * FIXME: Merge this into javadoc comment above when setVolume(float) is not @hide.
- * The single parameter form below is preferred if the channel volumes don't need
- * to be set independently.
- */
- @Override
- public void setVolume(float leftVolume, float rightVolume) {
- _setVolume(leftVolume, rightVolume);
- }
-
- private native void _setVolume(float leftVolume, float rightVolume);
-
- /**
- * Similar, excepts sets volume of all channels to same value.
- * @hide
- */
- @Override
- public void setVolume(float volume) {
- setVolume(volume, volume);
- }
-
- /**
* Sets the audio session ID.
*
* @param sessionId the audio session ID.
@@ -2189,7 +1684,6 @@
@Override
public native void attachAuxEffect(int effectId);
-
/**
* Sets the send level of the player to the attached auxiliary effect.
* See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
@@ -3029,36 +2523,6 @@
}
}
- /**
- * Releases the resources held by this {@code MediaPlayer2} object.
- *
- * It is considered good practice to call this method when you're
- * done using the MediaPlayer2. In particular, whenever an Activity
- * of an application is paused (its onPause() method is called),
- * or stopped (its onStop() method is called), this method should be
- * invoked to release the MediaPlayer2 object, unless the application
- * has a special need to keep the object around. In addition to
- * unnecessary resources (such as memory and instances of codecs)
- * being held, failure to call this method immediately if a
- * MediaPlayer2 object is no longer needed may also lead to
- * continuous battery consumption for mobile devices, and playback
- * failure for other applications if no multiple instances of the
- * same codec are supported on a device. Even if multiple instances
- * of the same codec are supported, some performance degradation
- * may be expected when unnecessary multiple instances are used
- * at the same time.
- *
- * {@code close()} may be safely called after a prior {@code close()}.
- * This class implements the Java {@code AutoCloseable} interface and
- * may be used with try-with-resources.
- */
- @Override
- public void close() {
- synchronized (mGuard) {
- release();
- }
- }
-
// Have to declare protected for finalize() since it is protected
// in the base class Object.
@Override
@@ -3161,23 +2625,28 @@
sendMessage(msg2);
}
+ final DataSourceDesc dsd;
synchronized (mPlLock) {
Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
- + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
- if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
+ if (srcId == mCurrentSrcId) {
prepareNextDataSource_l();
- } else if (mPlNextIndex >= 0 && srcId == mPlaylist.get(mPlNextIndex).getId()) {
+ dsd = mCurrentDSD;
+ } else if (mPlNextIndex >= 0 && srcId == mNextSrcId) {
mPlNextSourceState = NEXT_SOURCE_STATE_PREPARED;
if (mPlNextSourcePlayPending) {
playNextDataSource_l();
}
+ dsd = mPlaylist.get(0);
+ } else {
+ dsd = null;
}
}
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, srcId, MEDIA_INFO_PREPARED, 0));
+ mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
}
}
return;
@@ -3198,12 +2667,11 @@
}
// notifying the client outside the lock
- // TODO: get srcId
if (drmInfo != null) {
synchronized (mEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
cb.first.execute(() -> cb.second.onDrmInfo(
- mMediaPlayer, 0, drmInfo));
+ mMediaPlayer, mCurrentDSD, drmInfo));
}
}
}
@@ -3214,17 +2682,17 @@
case MEDIA_PLAYBACK_COMPLETE:
synchronized (mPlLock) {
- if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ if (srcId == mCurrentSrcId) {
Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
- + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+ + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
playNextDataSource_l();
}
}
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, srcId, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+ mMediaPlayer, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
}
}
stayAwake(false);
@@ -3252,18 +2720,18 @@
case MEDIA_BUFFERING_UPDATE:
final int percent = msg.arg1;
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onBufferingUpdate(
- mMediaPlayer, srcId, percent));
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onInfo(
+ mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE, percent));
}
}
return;
case MEDIA_SEEK_COMPLETE:
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, srcId, MEDIA_INFO_COMPLETE_CALL_SEEK, 0));
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onCallComplete(
+ mMediaPlayer, mCurrentDSD, MEDIA_CALL_SEEK_TO, 0));
}
}
// fall through
@@ -3281,9 +2749,9 @@
final int width = msg.arg1;
final int height = msg.arg2;
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onVideoSizeChanged(
- mMediaPlayer, srcId, width, height));
+ mMediaPlayer, mCurrentDSD, width, height));
}
}
return;
@@ -3291,11 +2759,11 @@
case MEDIA_ERROR:
Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onError(
- mMediaPlayer, srcId, what, extra));
+ mMediaPlayer, mCurrentDSD, what, extra));
cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, srcId, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+ mMediaPlayer, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
}
}
stayAwake(false);
@@ -3304,7 +2772,7 @@
case MEDIA_INFO:
switch (msg.arg1) {
case MEDIA_INFO_STARTED_AS_NEXT:
- if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ if (srcId == mCurrentSrcId) {
prepareNextDataSource_l();
}
break;
@@ -3342,9 +2810,9 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, srcId, what, extra));
+ mMediaPlayer, mCurrentDSD, what, extra));
}
}
// No real default action so far.
@@ -3368,8 +2836,8 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, srcId, text));
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, mCurrentDSD, text));
}
}
return;
@@ -3398,9 +2866,9 @@
}
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
- mMediaPlayer, srcId, data));
+ mMediaPlayer, mCurrentDSD, data));
}
}
return;
@@ -3473,7 +2941,7 @@
case MEDIA_PREPARED:
// By this time, we've learned about DrmInfo's presence or absence. This is meant
- // mainly for prepareAsync() use case. For prepare(), this still can run to a race
+ // mainly for prepare() use case. For prepare(), this still can run to a race
// condition b/c MediaPlayerNative releases the prepare() lock before calling notify
// so we also set mDrmInfoResolved in prepare().
synchronized (mp.mDrmLock) {
@@ -3496,8 +2964,8 @@
}
private final Object mEventCbLock = new Object();
- private ArrayList<Pair<Executor, EventCallback> > mEventCallbackRecords
- = new ArrayList<Pair<Executor, EventCallback> >();
+ private ArrayList<Pair<Executor, MediaPlayer2EventCallback> > mEventCallbackRecords
+ = new ArrayList<Pair<Executor, MediaPlayer2EventCallback> >();
/**
* Register a callback to be invoked when the media source is ready
@@ -3507,13 +2975,14 @@
* @param executor the executor through which the callback should be invoked
*/
@Override
- public void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull EventCallback eventCallback) {
+ public void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull MediaPlayer2EventCallback eventCallback) {
if (eventCallback == null) {
- throw new IllegalArgumentException("Illegal null EventCallback");
+ throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
}
if (executor == null) {
- throw new IllegalArgumentException("Illegal null Executor for the EventCallback");
+ throw new IllegalArgumentException(
+ "Illegal null Executor for the MediaPlayer2EventCallback");
}
synchronized (mEventCbLock) {
mEventCallbackRecords.add(new Pair(executor, eventCallback));
@@ -3521,17 +2990,13 @@
}
/**
- * Unregisters an {@link EventCallback}.
- *
- * @param callback an {@link EventCallback} to unregister
+ * Clears the {@link MediaPlayer2EventCallback}.
*/
@Override
- public void unregisterEventCallback(EventCallback callback) {
+ public void clearMediaPlayer2EventCallback() {
synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
- if (cb.second == callback) {
- mEventCallbackRecords.remove(cb);
- }
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ mEventCallbackRecords.remove(cb);
}
}
}
@@ -3583,13 +3048,14 @@
* @param executor the executor through which the callback should be invoked
*/
@Override
- public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+ public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull DrmEventCallback eventCallback) {
if (eventCallback == null) {
- throw new IllegalArgumentException("Illegal null EventCallback");
+ throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
}
if (executor == null) {
- throw new IllegalArgumentException("Illegal null Executor for the EventCallback");
+ throw new IllegalArgumentException(
+ "Illegal null Executor for the MediaPlayer2EventCallback");
}
synchronized (mDrmEventCbLock) {
mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
@@ -3597,18 +3063,13 @@
}
/**
- * Unregisters a {@link DrmEventCallback}.
- *
- * @param callback a {@link DrmEventCallback} to unregister
+ * Clears the {@link DrmEventCallback}.
*/
@Override
- public void unregisterDrmEventCallback(DrmEventCallback callback) {
+ public void clearDrmEventCallback() {
synchronized (mDrmEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
- if (cb.second == callback) {
- mDrmEventCallbackRecords.remove(cb);
- break;
- }
+ mDrmEventCallbackRecords.remove(cb);
}
}
}
@@ -3617,7 +3078,7 @@
/**
* Retrieves the DRM Info associated with the current source
*
- * @throws IllegalStateException if called before prepareAsync()
+ * @throws IllegalStateException if called before prepare()
*/
@Override
public DrmInfo getDrmInfo() {
@@ -3668,7 +3129,7 @@
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
* from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
*
- * @throws IllegalStateException if called before prepareAsync(), or the DRM was
+ * @throws IllegalStateException if called before prepare(), or the DRM was
* prepared already
* @throws UnsupportedSchemeException if the crypto scheme is not supported
* @throws ResourceBusyException if required DRM resources are in use
@@ -3723,7 +3184,7 @@
try {
// only creating the DRM object to allow pre-openSession configuration
- prepareDrm_createDrmStep(uuid);
+ prepareDrm(uuid);
} catch (Exception e) {
Log.w(TAG, "prepareDrm(): Exception ", e);
mPrepareDrmInProgress = false;
@@ -3735,9 +3196,8 @@
// call the callback outside the lock
- // TODO: get srcId
if (mOnDrmConfigHelper != null) {
- mOnDrmConfigHelper.onDrmConfig(this, 0);
+ mOnDrmConfigHelper.onDrmConfig(this, mCurrentDSD);
}
synchronized (mDrmLock) {
@@ -3807,12 +3267,11 @@
// if finished successfully without provisioning, call the callback outside the lock
- // TODO: get srcId
if (allDoneWithoutProvisioning) {
synchronized (mDrmEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
cb.first.execute(() -> cb.second.onDrmPrepared(
- this, 0, PREPARE_DRM_STATUS_SUCCESS));
+ this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS));
}
}
}
@@ -3868,14 +3327,14 @@
* A key request/response exchange occurs between the app and a license server
* to obtain or release keys used to decrypt encrypted content.
* <p>
- * getKeyRequest() is used to obtain an opaque key request byte array that is
+ * getDrmKeyRequest() is used to obtain an opaque key request byte array that is
* delivered to the license server. The opaque key request byte array is returned
* in KeyRequest.data. The recommended URL to deliver the key request to is
* returned in KeyRequest.defaultUrl.
* <p>
* After the app has received the key request response from the server,
* it should deliver to the response to the DRM engine plugin using the method
- * {@link #provideKeyResponse}.
+ * {@link #provideDrmKeyResponse}.
*
* @param keySetId is the key-set identifier of the offline keys being released when keyType is
* {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
@@ -3903,19 +3362,19 @@
*/
@Override
@NonNull
- public MediaDrm.KeyRequest getKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
+ public MediaDrm.KeyRequest getDrmKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
@Nullable String mimeType, @MediaDrm.KeyType int keyType,
@Nullable Map<String, String> optionalParameters)
throws NoDrmSchemeException
{
- Log.v(TAG, "getKeyRequest: " +
+ Log.v(TAG, "getDrmKeyRequest: " +
" keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
" keyType: " + keyType + " optionalParameters: " + optionalParameters);
synchronized (mDrmLock) {
if (!mActiveDrmScheme) {
- Log.e(TAG, "getKeyRequest NoDrmSchemeException");
- throw new NoDrmSchemeExceptionImpl("getKeyRequest: Has to set a DRM scheme first.");
+ Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
+ throw new NoDrmSchemeExceptionImpl("getDrmKeyRequest: Has to set a DRM scheme first.");
}
try {
@@ -3930,16 +3389,16 @@
MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType,
keyType, hmapOptionalParameters);
- Log.v(TAG, "getKeyRequest: --> request: " + request);
+ Log.v(TAG, "getDrmKeyRequest: --> request: " + request);
return request;
} catch (NotProvisionedException e) {
- Log.w(TAG, "getKeyRequest NotProvisionedException: " +
+ Log.w(TAG, "getDrmKeyRequest NotProvisionedException: " +
"Unexpected. Shouldn't have reached here.");
- throw new IllegalStateException("getKeyRequest: Unexpected provisioning error.");
+ throw new IllegalStateException("getDrmKeyRequest: Unexpected provisioning error.");
} catch (Exception e) {
- Log.w(TAG, "getKeyRequest Exception " + e);
+ Log.w(TAG, "getDrmKeyRequest Exception " + e);
throw e;
}
@@ -3949,15 +3408,15 @@
/**
* A key response is received from the license server by the app, then it is
- * provided to the DRM engine plugin using provideKeyResponse. When the
+ * provided to the DRM engine plugin using provideDrmKeyResponse. When the
* response is for an offline key request, a key-set identifier is returned that
* can be used to later restore the keys to a new session with the method
- * {@ link # restoreKeys}.
+ * {@ link # restoreDrmKeys}.
* When the response is for a streaming or release request, null is returned.
*
* @param keySetId When the response is for a release request, keySetId identifies
* the saved key associated with the release request (i.e., the same keySetId
- * passed to the earlier {@ link # getKeyRequest} call. It MUST be null when the
+ * passed to the earlier {@ link #getDrmKeyRequest} call. It MUST be null when the
* response is for either streaming or offline key requests.
*
* @param response the byte array response from the server
@@ -3967,16 +3426,16 @@
* server rejected the request
*/
@Override
- public byte[] provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
+ public byte[] provideDrmKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
throws NoDrmSchemeException, DeniedByServerException
{
- Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response);
+ Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response);
synchronized (mDrmLock) {
if (!mActiveDrmScheme) {
- Log.e(TAG, "getKeyRequest NoDrmSchemeException");
- throw new NoDrmSchemeExceptionImpl("getKeyRequest: Has to set a DRM scheme first.");
+ Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
+ throw new NoDrmSchemeExceptionImpl("getDrmKeyRequest: Has to set a DRM scheme first.");
}
try {
@@ -3986,19 +3445,19 @@
byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
- Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response +
+ Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response +
" --> " + keySetResult);
return keySetResult;
} catch (NotProvisionedException e) {
- Log.w(TAG, "provideKeyResponse NotProvisionedException: " +
+ Log.w(TAG, "provideDrmKeyResponse NotProvisionedException: " +
"Unexpected. Shouldn't have reached here.");
- throw new IllegalStateException("provideKeyResponse: " +
+ throw new IllegalStateException("provideDrmKeyResponse: " +
"Unexpected provisioning error.");
} catch (Exception e) {
- Log.w(TAG, "provideKeyResponse Exception " + e);
+ Log.w(TAG, "provideDrmKeyResponse Exception " + e);
throw e;
}
} // synchronized
@@ -4007,21 +3466,21 @@
/**
* Restore persisted offline keys into a new session. keySetId identifies the
- * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
+ * keys to load, obtained from a prior call to {@link #provideDrmKeyResponse}.
*
* @param keySetId identifies the saved key set to restore
*/
@Override
- public void restoreKeys(@NonNull byte[] keySetId)
+ public void restoreDrmKeys(@NonNull byte[] keySetId)
throws NoDrmSchemeException
{
- Log.v(TAG, "restoreKeys: keySetId: " + keySetId);
+ Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
synchronized (mDrmLock) {
if (!mActiveDrmScheme) {
- Log.w(TAG, "restoreKeys NoDrmSchemeException");
- throw new NoDrmSchemeExceptionImpl("restoreKeys: Has to set a DRM scheme first.");
+ Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
+ throw new NoDrmSchemeExceptionImpl("restoreDrmKeys: Has to set a DRM scheme first.");
}
try {
@@ -4305,7 +3764,7 @@
// TODO: don't need an open session for a future specialKeyReleaseDrm mode but we should do
// it anyway so it raises provisioning error if needed. We'd rather handle provisioning
- // at prepareDrm/openSession rather than getKeyRequest/provideKeyResponse
+ // at prepareDrm/openSession rather than getDrmKeyRequest/provideDrmKeyResponse
try {
mDrmSessionId = mDrmObj.openSession();
Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
@@ -4478,10 +3937,10 @@
} // synchronized
// calling the callback outside the lock
- // TODO: get srcId
synchronized (mDrmEventCbLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onDrmPrepared(mediaPlayer, 0, status));
+ cb.first.execute(() -> cb.second.onDrmPrepared(
+ mediaPlayer, mCurrentDSD, status));
}
}
} else { // blocking mode already has the lock
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
new file mode 100644
index 0000000..3739847
--- /dev/null
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2018 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.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Base class for all media players that want media session.
+ */
+public abstract class MediaPlayerBase implements AutoCloseable {
+ /**
+ * @hide
+ */
+ @IntDef({
+ PLAYER_STATE_IDLE,
+ PLAYER_STATE_PAUSED,
+ PLAYER_STATE_PLAYING,
+ PLAYER_STATE_ERROR })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PlayerState {}
+
+ /**
+ * @hide
+ */
+ @IntDef({
+ BUFFERING_STATE_UNKNOWN,
+ BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ BUFFERING_STATE_BUFFERING_AND_STARVED,
+ BUFFERING_STATE_BUFFERING_COMPLETE })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BuffState {}
+
+ /**
+ * State when the player is idle, and needs configuration to start playback.
+ */
+ public static final int PLAYER_STATE_IDLE = 0;
+
+ /**
+ * State when the player's playback is paused
+ */
+ public static final int PLAYER_STATE_PAUSED = 1;
+
+ /**
+ * State when the player's playback is ongoing
+ */
+ public static final int PLAYER_STATE_PLAYING = 2;
+
+ /**
+ * State when the player is in error state and cannot be recovered self.
+ */
+ public static final int PLAYER_STATE_ERROR = 3;
+
+ /**
+ * Buffering state is unknown.
+ */
+ public static final int BUFFERING_STATE_UNKNOWN = 0;
+
+ /**
+ * Buffering state indicating the player is buffering but enough has been buffered
+ * for this player to be able to play the content.
+ * See {@link #getBufferedPosition()} for how far is buffered already.
+ */
+ public static final int BUFFERING_STATE_BUFFERING_AND_PLAYABLE = 1;
+
+ /**
+ * Buffering state indicating the player is buffering, but the player is currently starved
+ * for data, and cannot play.
+ */
+ public static final int BUFFERING_STATE_BUFFERING_AND_STARVED = 2;
+
+ /**
+ * Buffering state indicating the player is done buffering, and the remainder of the content is
+ * available for playback.
+ */
+ public static final int BUFFERING_STATE_BUFFERING_COMPLETE = 3;
+
+ /**
+ * Starts or resumes playback.
+ */
+ public abstract void play();
+
+ /**
+ * Prepares the player for playback.
+ * See {@link PlayerEventCallback#onMediaPrepared(MediaPlayerBase, DataSourceDesc)} for being
+ * notified when the preparation phase completed. During this time, the player may allocate
+ * resources required to play, such as audio and video decoders.
+ */
+ public abstract void prepare();
+
+ /**
+ * Pauses playback.
+ */
+ public abstract void pause();
+
+ /**
+ *
+ */
+ public abstract void skipToNext();
+
+ /**
+ * Moves the playback head to the specified position
+ * @param pos the new playback position expressed in ms.
+ */
+ public abstract void seekTo(long pos);
+
+ public static final long UNKNOWN_TIME = -1;
+
+ /**
+ * Returns the current playback head position.
+ * @return the current play position in ms, or {@link #UNKNOWN_TIME} if unknown.
+ */
+ public long getCurrentPosition() { return UNKNOWN_TIME; }
+
+ /**
+ * Returns the duration of the current data source, or {@link #UNKNOWN_TIME} if unknown.
+ * @return the duration in ms, or {@link #UNKNOWN_TIME}.
+ */
+ public long getDuration() { return UNKNOWN_TIME; }
+
+ /**
+ * Returns the duration of the current data source, or {@link #UNKNOWN_TIME} if unknown.
+ * @return the duration in ms, or {@link #UNKNOWN_TIME}.
+ */
+ public long getBufferedPosition() { return UNKNOWN_TIME; }
+
+ /**
+ * Returns the current player state.
+ * See also {@link PlayerEventCallback#onPlayerStateChanged(MediaPlayerBase, int)} for
+ * notification of changes.
+ * @return the current player state
+ */
+ public abstract @PlayerState int getPlayerState();
+
+ /**
+ * Returns the current buffering state of the player.
+ * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
+ * buffered.
+ * @return the buffering state.
+ */
+ public abstract @BuffState int getBufferingState();
+
+ /**
+ * Sets the {@link AudioAttributes} to be used during the playback of the media.
+ *
+ * @param attributes non-null <code>AudioAttributes</code>.
+ */
+ public abstract void setAudioAttributes(@NonNull AudioAttributes attributes);
+
+ /**
+ * Returns AudioAttributes that media player has.
+ */
+ public abstract @Nullable AudioAttributes getAudioAttributes();
+
+ /**
+ * Sets the data source to be played.
+ * @param dsd
+ */
+ public abstract void setDataSource(@NonNull DataSourceDesc dsd);
+
+ /**
+ * Sets the data source that will be played immediately after the current one is done playing.
+ * @param dsd
+ */
+ public abstract void setNextDataSource(@NonNull DataSourceDesc dsd);
+
+ /**
+ * Sets the list of data sources that will be sequentially played after the current one. Each
+ * data source is played immediately after the previous one is done playing.
+ * @param dsds
+ */
+ public abstract void setNextDataSources(@NonNull List<DataSourceDesc> dsds);
+
+ /**
+ * Returns the current data source.
+ * @return the current data source, or null if none is set, or none available to play.
+ */
+ public abstract @Nullable DataSourceDesc getCurrentDataSource();
+
+ /**
+ * Configures the player to loop on the current data source.
+ * @param loop true if the current data source is meant to loop.
+ */
+ public abstract void loopCurrent(boolean loop);
+
+ /**
+ * Sets the playback speed.
+ * A value of 1.0f is the default playback value.
+ * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
+ * before using negative values.<br>
+ * After changing the playback speed, it is recommended to query the actual speed supported
+ * by the player, see {@link #getPlaybackSpeed()}.
+ * @param speed
+ */
+ public abstract void setPlaybackSpeed(float speed);
+
+ /**
+ * Returns the actual playback speed to be used by the player when playing.
+ * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
+ * @return the actual playback speed
+ */
+ public float getPlaybackSpeed() { return 1.0f; }
+
+ /**
+ * Indicates whether reverse playback is supported.
+ * Reverse playback is indicated by negative playback speeds, see
+ * {@link #setPlaybackSpeed(float)}.
+ * @return true if reverse playback is supported.
+ */
+ public boolean isReversePlaybackSupported() { return false; }
+
+ /**
+ * Sets the volume of the audio of the media to play, expressed as a linear multiplier
+ * on the audio samples.
+ * Note that this volume is specific to the player, and is separate from stream volume
+ * used across the platform.<br>
+ * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
+ * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
+ * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
+ */
+ public abstract void setPlayerVolume(float volume);
+
+ /**
+ * Returns the current volume of this player to this player.
+ * Note that it does not take into account the associated stream volume.
+ * @return the player volume.
+ */
+ public abstract float getPlayerVolume();
+
+ /**
+ * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
+ */
+ public float getMaxPlayerVolume() { return 1.0f; }
+
+ /**
+ * Adds a callback to be notified of events for this player.
+ * @param e the {@link Executor} to be used for the events.
+ * @param cb the callback to receive the events.
+ */
+ public abstract void registerPlayerEventCallback(@NonNull Executor e,
+ @NonNull PlayerEventCallback cb);
+
+ /**
+ * Removes a previously registered callback for player events
+ * @param cb the callback to remove
+ */
+ public abstract void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb);
+
+ /**
+ * A callback class to receive notifications for events on the media player.
+ * See {@link MediaPlayerBase#registerPlayerEventCallback(Executor, PlayerEventCallback)} to
+ * register this callback.
+ */
+ public static abstract class PlayerEventCallback {
+ /**
+ * Called when the player's curretn data source has changed.
+ * @param mpb the player whose data source changed.
+ * @param dsd the new current data source.
+ */
+ public void onCurrentDataSourceChanged(@NonNull MediaPlayerBase mpb,
+ @Nullable DataSourceDesc dsd) { }
+ /**
+ * Called when the player is <i>prepared</i>, i.e. it is ready to play the content
+ * referenced by the given data source.
+ * @param mpb the player that is prepared.
+ * @param dsd the data source that the player is prepared to play.
+ */
+ public void onMediaPrepared(@NonNull MediaPlayerBase mpb, @NonNull DataSourceDesc dsd) { }
+
+ /**
+ * Called to indicate that the state of the player has changed.
+ * See {@link MediaPlayerBase#getPlayerState()} for polling the player state.
+ * @param mpb the player whose state has changed.
+ * @param state the new state of the player.
+ */
+ public void onPlayerStateChanged(@NonNull MediaPlayerBase mpb, @PlayerState int state) { }
+
+ /**
+ * Called to report buffering events for a data source.
+ * @param mpb the player that is buffering
+ * @param dsd the data source for which buffering is happening.
+ * @param state the new buffering state.
+ */
+ public void onBufferingStateChanged(@NonNull MediaPlayerBase mpb,
+ @NonNull DataSourceDesc dsd, @BuffState int state) { }
+ }
+
+}
diff --git a/media/java/android/media/MediaPlayerInterface.java b/media/java/android/media/MediaPlayerInterface.java
deleted file mode 100644
index b81c3d6..0000000
--- a/media/java/android/media/MediaPlayerInterface.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2018 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.media;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.MediaSession2.PlaylistParams;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Base interfaces for all media players that want media session.
- * @hide
- */
-public interface MediaPlayerInterface {
- /**
- * Unspecified media player error.
- */
- int MEDIA_ERROR_UNKNOWN = MediaPlayer2.MEDIA_ERROR_UNKNOWN;
-
- /**
- * The video is streamed and its container is not valid for progressive
- * playback i.e the video's index (e.g moov atom) is not at the start of the
- * file.
- */
- int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK =
- MediaPlayer2.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK;
-
- /**
- * File or network related operation errors.
- */
- int MEDIA_ERROR_IO = MediaPlayer2.MEDIA_ERROR_IO;
-
- /**
- * Bitstream is not conforming to the related coding standard or file spec.
- */
- int MEDIA_ERROR_MALFORMED = MediaPlayer2.MEDIA_ERROR_MALFORMED;
-
- /**
- * Bitstream is conforming to the related coding standard or file spec, but
- * the media framework does not support the feature.
- */
- int MEDIA_ERROR_UNSUPPORTED = MediaPlayer2.MEDIA_ERROR_UNSUPPORTED;
-
- /**
- * Some operation takes too long to complete, usually more than 3-5 seconds.
- */
- int MEDIA_ERROR_TIMED_OUT = MediaPlayer2.MEDIA_ERROR_TIMED_OUT;
-
- /**
- * Callbacks to listens to the changes in {@link PlaybackState2} and error.
- */
- interface EventCallback {
- /**
- * Called when {@link PlaybackState2} for this player is changed.
- */
- default void onPlaybackStateChanged(PlaybackState2 state) { }
-
- /**
- * Called to indicate an error.
- *
- * @param mediaId optional mediaId to indicate error
- * @param what what
- * @param extra
- */
- default void onError(@Nullable String mediaId, int what, int extra) { }
- }
-
- // Transport controls that session will send command directly to this player.
- void play();
- void prepare();
- void pause();
- void stop();
- void skipToPrevious();
- void skipToNext();
- void seekTo(long pos);
- void fastForward();
- void rewind();
-
- PlaybackState2 getPlaybackState();
-
- /**
- * Sets the {@link AudioAttributes} to be used during the playback of the media.
- *
- * @param attributes non-null <code>AudioAttributes</code>.
- */
- void setAudioAttributes(@NonNull AudioAttributes attributes);
-
- /**
- * Returns AudioAttributes that media player has.
- */
- @Nullable
- AudioAttributes getAudioAttributes();
-
- void addPlaylistItem(int index, MediaItem2 item);
- void removePlaylistItem(MediaItem2 item);
-
- void setPlaylist(List<MediaItem2> playlist);
- List<MediaItem2> getPlaylist();
-
- void setCurrentPlaylistItem(int index);
- void setPlaylistParams(PlaylistParams params);
- PlaylistParams getPlaylistParams();
-
- /**
- * Register a {@link EventCallback}.
- *
- * @param executor a callback executor
- * @param callback a EventCallback
- */
- void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull EventCallback callback);
-
- /**
- * Unregister previously registered {@link EventCallback}.
- *
- * @param callback a EventCallback
- */
- void unregisterEventCallback(@NonNull EventCallback callback);
-}
diff --git a/media/java/android/media/MediaPlaylistController.java b/media/java/android/media/MediaPlaylistController.java
new file mode 100644
index 0000000..c98d50e
--- /dev/null
+++ b/media/java/android/media/MediaPlaylistController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 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.media;
+
+import android.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Controller interface for playlist management.
+ * Playlists are composed of one or multiple {@link MediaItem2} instances, which combine metadata
+ * and data sources (as {@link DataSourceDesc})
+ * Used by {@link MediaSession2} and {@link MediaController2}.
+ */
+ // This class only includes methods that contain {@link MediaItem2}.
+ // Note that setPlaylist() isn't added on purpose because it's considered session-specific.
+
+public interface MediaPlaylistController {
+ void addPlaylistItem(int index, @NonNull MediaItem2 item);
+ void removePlaylistItem(@NonNull MediaItem2 item);
+ MediaItem2 getCurrentPlaylistItem();
+ void skipToPlaylistItem(@NonNull MediaItem2 item);
+ void replacePlaylistItem(int index, @NonNull MediaItem2 item);
+ List<MediaItem2> getPlaylist();
+}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 63e4e65..ae5a8c6 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -20,11 +20,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.media.MediaPlayerInterface.EventCallback;
+import android.media.MediaPlayerBase.PlayerEventCallback;
+import android.media.MediaPlaylistController;
import android.media.session.MediaSession;
import android.media.session.MediaSession.Callback;
import android.media.session.PlaybackState;
@@ -70,7 +70,7 @@
* <p>
* When a session receive transport control commands, the session sends the commands directly to
* the the underlying media player set by {@link Builder} or
- * {@link #setPlayer(MediaPlayerInterface)}.
+ * {@link #updatePlayer}.
* <p>
* When an app is finished performing playback it must call {@link #close()} to clean up the session
* and notify any controllers.
@@ -78,9 +78,8 @@
* {@link MediaSession2} objects should be used on the thread on the looper.
*
* @see MediaSessionService2
- * @hide
*/
-public class MediaSession2 implements AutoCloseable {
+public class MediaSession2 implements AutoCloseable, MediaPlaylistController {
private final MediaSession2Provider mProvider;
// TODO(jaewan): Should we define IntDef? Currently we don't have to allow subclass to add more.
@@ -119,7 +118,7 @@
public static final int COMMAND_CODE_PLAYBACK_STOP = 3;
/**
- * Command code for {@link MediaController2#skipToNext()} ()}.
+ * Command code for {@link MediaController2#skipToNext()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
* through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
@@ -127,7 +126,7 @@
public static final int COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM = 4;
/**
- * Command code for {@link MediaController2#skipToPrevious()} ()}.
+ * Command code for {@link MediaController2#skipToPrevious()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
* through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
@@ -143,7 +142,7 @@
public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6;
/**
- * Command code for {@link MediaController2#fastForward()} ()}.
+ * Command code for {@link MediaController2#fastForward()}.
* <p>
* This is transport control command. Command would be sent directly to the player if the
* session doesn't reject the request through the
@@ -160,22 +159,22 @@
public static final int COMMAND_CODE_PLAYBACK_REWIND = 8;
/**
- * Command code for {@link MediaController2#seekTo(long)} ()}.
+ * Command code for {@link MediaController2#seekTo(long)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
* through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9;
/**
- * Command code for {@link MediaController2#setCurrentPlaylistItem(int)} ()}.
+ * Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
* through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
*/
- public static final int COMMAND_CODE_PLAYBACK_SET_CURRENT_PLAYLIST_ITEM = 10;
+ public static final int COMMAND_CODE_PLAYBACK_SKIP_TO_PLAYLIST_ITEM = 10;
/**
- * Command code for {@link MediaController2#setPlaylistParams(PlaylistParams)} ()}.
+ * Command code for {@link MediaController2#setPlaylistParams(PlaylistParams)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
* through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
@@ -222,7 +221,7 @@
public static final int COMMAND_CODE_PLAY_FROM_MEDIA_ID = 16;
/**
- * Command code for {@link MediaController2#playFromUri(String, Bundle)}.
+ * Command code for {@link MediaController2#playFromUri(Uri, Bundle)}.
*/
public static final int COMMAND_CODE_PLAY_FROM_URI = 17;
@@ -256,6 +255,84 @@
public static final int COMMAND_CODE_BROWSER = 22;
/**
+ * @hide
+ */
+ @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED,
+ ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED,
+ ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED,
+ ERROR_CODE_NOT_AVAILABLE_IN_REGION, ERROR_CODE_CONTENT_ALREADY_PLAYING,
+ ERROR_CODE_SKIP_LIMIT_REACHED, ERROR_CODE_ACTION_ABORTED, ERROR_CODE_END_OF_QUEUE,
+ ERROR_CODE_SETUP_REQUIRED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ErrorCode {}
+
+ /**
+ * This is the default error code and indicates that none of the other error codes applies.
+ */
+ public static final int ERROR_CODE_UNKNOWN_ERROR = 0;
+
+ /**
+ * Error code when the application state is invalid to fulfill the request.
+ */
+ public static final int ERROR_CODE_APP_ERROR = 1;
+
+ /**
+ * Error code when the request is not supported by the application.
+ */
+ public static final int ERROR_CODE_NOT_SUPPORTED = 2;
+
+ /**
+ * Error code when the request cannot be performed because authentication has expired.
+ */
+ public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3;
+
+ /**
+ * Error code when a premium account is required for the request to succeed.
+ */
+ public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4;
+
+ /**
+ * Error code when too many concurrent streams are detected.
+ */
+ public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5;
+
+ /**
+ * Error code when the content is blocked due to parental controls.
+ */
+ public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6;
+
+ /**
+ * Error code when the content is blocked due to being regionally unavailable.
+ */
+ public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7;
+
+ /**
+ * Error code when the requested content is already playing.
+ */
+ public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8;
+
+ /**
+ * Error code when the application cannot skip any more songs because skip limit is reached.
+ */
+ public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9;
+
+ /**
+ * Error code when the action is interrupted due to some external event.
+ */
+ public static final int ERROR_CODE_ACTION_ABORTED = 10;
+
+ /**
+ * Error code when the playback navigation (previous, next) is not possible because the queue
+ * was exhausted.
+ */
+ public static final int ERROR_CODE_END_OF_QUEUE = 11;
+
+ /**
+ * Error code when the session needs user's manual intervention.
+ */
+ public static final int ERROR_CODE_SETUP_REQUIRED = 12;
+
+ /**
* Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
* <p>
* If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
@@ -271,12 +348,12 @@
.createMediaSession2Command(this, commandCode, null, null);
}
- public Command(@NonNull Context context, @NonNull String action, @Nullable Bundle extra) {
+ public Command(@NonNull Context context, @NonNull String action, @Nullable Bundle extras) {
if (action == null) {
throw new IllegalArgumentException("action shouldn't be null");
}
mProvider = ApiLoader.getProvider(context)
- .createMediaSession2Command(this, COMMAND_CODE_CUSTOM, action, extra);
+ .createMediaSession2Command(this, COMMAND_CODE_CUSTOM, action, extras);
}
public int getCommandCode() {
@@ -287,8 +364,8 @@
return mProvider.getCustomCommand_impl();
}
- public @Nullable Bundle getExtra() {
- return mProvider.getExtra_impl();
+ public @Nullable Bundle getExtras() {
+ return mProvider.getExtras_impl();
}
/**
@@ -324,7 +401,7 @@
/**
* Represent set of {@link Command}.
*/
- public static class CommandGroup {
+ public static final class CommandGroup {
private final CommandGroupProvider mProvider;
public CommandGroup(Context context) {
@@ -357,10 +434,14 @@
return mProvider.hasCommand_impl(code);
}
+ public List<Command> getCommands() {
+ // TODO: implement this
+ return null;
+ }
+
/**
* @hide
*/
- @SystemApi
public CommandGroupProvider getProvider() {
return mProvider;
}
@@ -390,7 +471,7 @@
* default.
*/
// TODO(jaewan): Can we move this inside of the updatable for default implementation.
- public static class SessionCallback {
+ public static abstract class SessionCallback {
private final Context mContext;
public SessionCallback(Context context) {
@@ -437,7 +518,7 @@
* @see #COMMAND_CODE_PLAYBACK_FAST_FORWARD
* @see #COMMAND_CODE_PLAYBACK_REWIND
* @see #COMMAND_CODE_PLAYBACK_SEEK_TO
- * @see #COMMAND_CODE_PLAYBACK_SET_CURRENT_PLAYLIST_ITEM
+ * @see #COMMAND_CODE_PLAYBACK_SKIP_TO_PLAYLIST_ITEM
* @see #COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS
* @see #COMMAND_CODE_PLAYLIST_ADD
* @see #COMMAND_CODE_PLAYLIST_REMOVE
@@ -587,7 +668,7 @@
/**
* Base builder class for MediaSession2 and its subclass. Any change in this class should be
* also applied to the subclasses {@link MediaSession2.Builder} and
- * {@link MediaLibraryService2.MediaLibrarySessionBuilder}.
+ * {@link MediaLibraryService2.MediaLibrarySession.Builder}.
* <p>
* APIs here should be package private, but should have documentations for developers.
* Otherwise, javadoc will generate documentation with the generic types such as follows.
@@ -610,16 +691,38 @@
}
/**
- * Set volume provider to configure this session to use remote volume handling.
- * This must be called to receive volume button events, otherwise the system
- * will adjust the appropriate stream volume for this session's player.
+ * Set the underlying {@link MediaPlayerBase} for this session to dispatch incoming event
+ * to.
* <p>
- * Set {@code null} to reset.
*
- * @param volumeProvider The provider that will handle volume changes. Can be {@code null}.
+ * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
*/
- U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
- mProvider.setVolumeProvider_impl(volumeProvider);
+ U setPlayer(@NonNull MediaPlayerBase player) {
+ // TODO: Change the provider properly
+ mProvider.setPlayer_impl(player, null, null);
+ return (U) this;
+ }
+
+ /**
+ * Set the {@link MediaPlaylistController} for this session to manages playlist of the
+ * underlying {@link MediaPlayerBase player}.
+ *
+ * @param mplc a {@link MediaPlaylistController} that manages playlist of the
+ * {@code player.}
+ */
+ U setPlaylistController(@NonNull MediaPlaylistController mplc) {
+ // TODO: implement this
+ return (U) this;
+ }
+
+ /**
+ * Set the {@link VolumeProvider2} for this session to receive volume button events. If not
+ * set, system will adjust the appropriate stream volume for this session's player.
+ *
+ * @param volumeProvider The provider that will receive volume button events.
+ */
+ U setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
+ // TODO: implement this
return (U) this;
}
@@ -684,13 +787,32 @@
// Override all methods just to show them with the type instead of generics in Javadoc.
// This workarounds javadoc issue described in the MediaSession2.BuilderBase.
public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> {
- public Builder(Context context, @NonNull MediaPlayerInterface player) {
+ public Builder(Context context) {
super((instance) -> ApiLoader.getProvider(context).createMediaSession2Builder(
- context, (Builder) instance, player));
+ context, (Builder) instance));
}
@Override
- public Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
+ public Builder setPlayer(@NonNull MediaPlayerBase player) {
+ if (player == null) {
+ throw new IllegalArgumentException("Illegal null MediaPlayerBase");
+ }
+ return super.setPlayer(player);
+ }
+
+ @Override
+ public Builder setPlaylistController(@NonNull MediaPlaylistController mplc) {
+ if (mplc == null) {
+ throw new IllegalArgumentException("Illegal null MediaPlaylistController");
+ }
+ return super.setPlaylistController(mplc);
+ }
+
+ @Override
+ public Builder setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
+ if (volumeProvider == null) {
+ throw new IllegalArgumentException("Illegal null VolumeProvider2");
+ }
return super.setVolumeProvider(volumeProvider);
}
@@ -725,7 +847,6 @@
/**
* @hide
*/
- // TODO(jaewan): SystemApi
// TODO(jaewan): Also accept componentName to check notificaiton listener.
public ControllerInfo(Context context, int uid, int pid, String packageName,
IInterface callback) {
@@ -762,7 +883,6 @@
/**
* @hide
*/
- @SystemApi
public ControllerInfoProvider getProvider() {
return mProvider;
}
@@ -794,13 +914,12 @@
* <p>
* It's up to the controller's decision to respect or ignore this customization request.
*/
- public static class CommandButton {
+ public static final class CommandButton {
private final CommandButtonProvider mProvider;
/**
* @hide
*/
- @SystemApi
public CommandButton(CommandButtonProvider provider) {
mProvider = provider;
}
@@ -840,8 +959,8 @@
*
* @return
*/
- public @Nullable Bundle getExtra() {
- return mProvider.getExtra_impl();
+ public @Nullable Bundle getExtras() {
+ return mProvider.getExtras_impl();
}
/**
@@ -856,7 +975,6 @@
/**
* @hide
*/
- @SystemApi
public CommandButtonProvider getProvider() {
return mProvider;
}
@@ -864,7 +982,7 @@
/**
* Builder for {@link CommandButton}.
*/
- public static class Builder {
+ public static final class Builder {
private final CommandButtonProvider.BuilderProvider mProvider;
public Builder(@NonNull Context context) {
@@ -888,8 +1006,8 @@
return mProvider.setEnabled_impl(enabled);
}
- public Builder setExtra(Bundle extra) {
- return mProvider.setExtra_impl(extra);
+ public Builder setExtras(Bundle extras) {
+ return mProvider.setExtras_impl(extras);
}
public CommandButton build() {
@@ -1038,7 +1156,6 @@
* framework had to add heuristics to figure out if an app is
* @hide
*/
- @SystemApi
public MediaSession2(MediaSession2Provider provider) {
super();
mProvider = provider;
@@ -1047,41 +1164,25 @@
/**
* @hide
*/
- @SystemApi
public MediaSession2Provider getProvider() {
return mProvider;
}
/**
- * Set the underlying {@link MediaPlayerInterface} for this session to dispatch incoming event
+ * Set the underlying {@link MediaPlayerBase} for this session to dispatch incoming event
* to. Events from the {@link MediaController2} will be sent directly to the underlying
* player on the {@link Handler} where the session is created on.
- * <p>
- * If the new player is successfully set,
- * {@link EventCallback#onPlaybackStateChanged(PlaybackState2)} will be called to tell the
- * current playback state of the new player.
- * <p>
- * For the remote playback case which you want to handle volume by yourself, use
- * {@link #setPlayer(MediaPlayerInterface, VolumeProvider2)}.
*
- * @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
- * @throws IllegalArgumentException if the player is {@code null}.
+ * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
+ * @param mplc a {@link MediaPlaylistController} that manages playlist of the
+ * {@code player.}
+ * @param volumeProvider The provider that will receive volume button events. If
+ * {@code null}, system will adjust the appropriate stream volume for this session's player.
*/
- public void setPlayer(@NonNull MediaPlayerInterface player) {
- mProvider.setPlayer_impl(player);
- }
-
- /**
- * Set the underlying {@link MediaPlayerInterface} with the volume provider for remote playback.
- *
- * @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
- * @param volumeProvider a volume provider
- * @see #setPlayer(MediaPlayerInterface)
- * @see Builder#setVolumeProvider(VolumeProvider2)
- */
- public void setPlayer(@NonNull MediaPlayerInterface player,
- @NonNull VolumeProvider2 volumeProvider) {
- mProvider.setPlayer_impl(player, volumeProvider);
+ public void updatePlayer(@NonNull MediaPlayerBase player,
+ @Nullable MediaPlaylistController mplc, @NonNull VolumeProvider2 volumeProvider) {
+ // TODO: rename setPlayer_impl to updatePlayer_impl
+ mProvider.setPlayer_impl(player, mplc, volumeProvider);
}
@Override
@@ -1093,11 +1194,29 @@
* @return player
*/
public @Nullable
- MediaPlayerInterface getPlayer() {
+ MediaPlayerBase getPlayer() {
return mProvider.getPlayer_impl();
}
/**
+ * @return playlist controller
+ */
+ public @Nullable
+ MediaPlaylistController getMediaPlaylistController() {
+ // TODO: implement this
+ return null;
+ }
+
+ /**
+ * @return volume provider
+ */
+ public @Nullable
+ VolumeProvider2 getVolumeProvider() {
+ // TODO: implement this
+ return null;
+ }
+
+ /**
* Returns the {@link SessionToken2} for creating {@link MediaController2}.
*/
public @NonNull
@@ -1110,22 +1229,13 @@
}
/**
- * Sets which type of audio focus will be requested during the playback, or configures playback
- * to not request audio focus. Valid values for focus requests are
- * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
- * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
- * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. Or use
- * {@link AudioManager#AUDIOFOCUS_NONE} to express that audio focus should not be
- * requested when playback starts. You can for instance use this when playing a silent animation
- * through this class, and you don't want to affect other audio applications playing in the
- * background.
+ * Set the {@link AudioFocusRequest} to obtain the audio focus
*
- * @param focusGain the type of audio focus gain that will be requested, or
- * {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during
- * playback.
+ * @param afr the full request parameters
*/
- public void setAudioFocusRequest(int focusGain) {
- mProvider.setAudioFocusRequest_impl(focusGain);
+ public void setAudioFocusRequest(AudioFocusRequest afr) {
+ // TODO: implement this
+ // mProvider.setAudioFocusRequest_impl(focusGain);
}
/**
@@ -1164,14 +1274,6 @@
}
/**
- * Notify changes in metadata of previously set playlist. Controller will get the whole set of
- * playlist again.
- */
- public void notifyMetadataChanged() {
- mProvider.notifyMetadataChanged_impl();
- }
-
- /**
* Send custom command to all connected controllers.
*
* @param command a command
@@ -1264,14 +1366,14 @@
}
/**
- * Sets the index of current DataSourceDesc in the play list to be played.
+ * Skip to the item in the play list.
*
- * @param index the index of DataSourceDesc in the play list you want to play
+ * @param item item in the play list you want to play
* @throws IllegalArgumentException if the play list is null
* @throws NullPointerException if index is outside play list range
*/
- public void setCurrentPlaylistItem(int index) {
- mProvider.setCurrentPlaylistItem_impl(index);
+ public void skipToPlaylistItem(MediaItem2 item) {
+ mProvider.skipToPlaylistItem_impl(item);
}
/**
@@ -1289,7 +1391,7 @@
}
/**
- * Sets a list of {@link MediaItem2} as the current play list.
+ * Set a list of {@link MediaItem2} as the current play list.
*
* @param playlist A list of {@link MediaItem2} objects to set as a play list.
* @throws IllegalArgumentException if given {@param playlist} is null.
@@ -1299,13 +1401,66 @@
}
/**
- * Returns the playlist which is lastly set.
+ * Remove the media item in the play list.
+ * <p>
+ * If the item is the currently playing item of the playlist, current playback
+ * will be stopped and playback moves to next source in the list.
+ *
+ * @throws IllegalArgumentException if the play list is null
*/
+ // TODO(jaewan): Remove with index was previously rejected by council (b/36524925)
+ // TODO(jaewan): Should we also add movePlaylistItem from index to index?
+ public void removePlaylistItem(MediaItem2 item) {
+ mProvider.removePlaylistItem_impl(item);
+ }
+
+ /**
+ * Add the media item to the play list at position index.
+ * <p>
+ * This will not change the currently playing media item.
+ * If index is less than or equal to the current index of the play list,
+ * the current index of the play list will be incremented correspondingly.
+ *
+ * @param index the index you want to add
+ * @param item the media item you want to add
+ * @throws IndexOutOfBoundsException if index is outside play list range
+ */
+ @Override
+ public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
+ mProvider.addPlaylistItem_impl(index, item);
+ }
+
+ /**
+ * Replace the media item at index in the playlist.
+ * @param index the index of the item to replace
+ * @param item the new item
+ */
+ @Override
+ public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
+ mProvider.replacePlaylistItem_impl(index, item);
+ }
+
+ /**
+ * Return the playlist which is lastly set.
+ *
+ * @return playlist
+ */
+ @Override
public List<MediaItem2> getPlaylist() {
return mProvider.getPlaylist_impl();
}
/**
+ * Return currently playing media item.
+ *
+ * @return currently playing media item
+ */
+ @Override
+ public MediaItem2 getCurrentPlaylistItem() {
+ return mProvider.getCurrentPlaylistItem_impl();
+ }
+
+ /**
* Sets the {@link PlaylistParams} for the current play list. Repeat/shuffle mode and metadata
* for the list can be set by calling this method.
*
@@ -1324,18 +1479,30 @@
return mProvider.getPlaylistParams_impl();
}
- /*
+ /**
+ * Notify errors to the connected controllers
+ *
+ * @param errorCode error code
+ * @param extras extras
+ */
+ public void notifyError(@ErrorCode int errorCode, @Nullable Bundle extras) {
+ mProvider.notifyError_impl(errorCode, extras);
+ }
+
+ /**
* Register {@link EventCallback} to listen changes in the underlying
- * {@link MediaPlayerInterface}, regardless of the change in the underlying player.
+ * {@link MediaPlayerBase}, regardless of the change in the underlying player.
* <p>
* Registered callbacks will be also called when the underlying player is changed.
*
* @param executor a callback Executor
* @param callback a EventCallback
* @throws IllegalArgumentException if executor or callback is {@code null}.
+ * @hide
*/
+ // TODO(jaewan): Unhide or remove
public void registerPlayerEventCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull EventCallback callback) {
+ @NonNull PlayerEventCallback callback) {
mProvider.registerPlayerEventCallback_impl(executor, callback);
}
@@ -1344,8 +1511,10 @@
*
* @param callback the callback to be removed
* @throws IllegalArgumentException if the callback is {@code null}.
+ * @hide
*/
- public void unregisterPlayerEventCallback(@NonNull EventCallback callback) {
+ // TODO(jaewan): Unhide or remove
+ public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback callback) {
mProvider.unregisterPlayerEventCallback_impl(callback);
}
@@ -1353,8 +1522,26 @@
* Return the {@link PlaybackState2} from the player.
*
* @return playback state
+ * @hide
*/
public PlaybackState2 getPlaybackState() {
return mProvider.getPlaybackState_impl();
}
+
+ /**
+ * Get the playback speed.
+ *
+ * @return speed
+ */
+ public float getPlaybackSpeed() {
+ // TODO: implement this
+ return -1;
+ }
+
+ /**
+ * Set the playback speed.
+ */
+ public void setPlaybackSpeed(float speed) {
+ // TODO: implement this
+ }
}
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index 0b5dddf..56e8e5d 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -90,7 +90,7 @@
* rejected, the controller will unbind. If it's accepted, the controller will be available to use
* and keep binding.
* <p>
- * When playback is started for this session service, {@link #onUpdateNotification(PlaybackState2)}
+ * When playback is started for this session service, {@link #onUpdateNotification()}
* is called and service would become a foreground service. It's needed to keep playback after the
* controller is destroyed. The session service becomes background service when the playback is
* stopped.
@@ -100,7 +100,6 @@
* Any app can bind to the session service with controller, but the controller can be used only if
* the session service accepted the connection request through
* {@link MediaSession2.SessionCallback#onConnect(ControllerInfo)}.
- * @hide
*/
public abstract class MediaSessionService2 extends Service {
private final MediaSessionService2Provider mProvider;
@@ -158,17 +157,16 @@
public @NonNull abstract MediaSession2 onCreateSession(String sessionId);
/**
- * Called when the playback state of this session is changed, and notification needs update.
- * Override this method to show your own notification UI.
+ * Called when the playback state of this session is changed so notification needs update.
+ * Override this method to show or cancel your own notification UI.
* <p>
* With the notification returned here, the service become foreground service when the playback
* is started. It becomes background service after the playback is stopped.
*
- * @param state playback state
* @return a {@link MediaNotification}. If it's {@code null}, notification wouldn't be shown.
*/
- public MediaNotification onUpdateNotification(PlaybackState2 state) {
- return mProvider.onUpdateNotification_impl(state);
+ public MediaNotification onUpdateNotification() {
+ return mProvider.onUpdateNotification_impl();
}
/**
@@ -201,9 +199,9 @@
}
/**
- * Returned by {@link #onUpdateNotification(PlaybackState2)} for making session service
- * foreground service to keep playback running in the background. It's highly recommended to
- * show media style notification here.
+ * Returned by {@link #onUpdateNotification()} for making session service forground service
+ * to keep playback running in the background. It's highly recommended to show media style
+ * notification here.
*/
public static class MediaNotification {
private final MediaNotificationProvider mProvider;
diff --git a/media/java/android/media/PlaybackState2.java b/media/java/android/media/PlaybackState2.java
index a95b8f2..7afb579 100644
--- a/media/java/android/media/PlaybackState2.java
+++ b/media/java/android/media/PlaybackState2.java
@@ -28,11 +28,12 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Playback state for a {@link MediaPlayerInterface}, to be shared between {@link MediaSession2} and
+ * Playback state for a {@link MediaPlayerBase}, to be shared between {@link MediaSession2} and
* {@link MediaController2}. This includes a playback state {@link #STATE_PLAYING},
* the current playback position and extra.
* @hide
*/
+// TODO(jaewan): Remove this.
public final class PlaybackState2 {
// Similar to the PlaybackState with following changes
// - Not implement Parcelable and added from/toBundle()
@@ -214,4 +215,4 @@
@Nullable Bundle bundle) {
return ApiLoader.getProvider(context).fromBundle_PlaybackState2(context, bundle);
}
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
index 4f77ecd..e5b05fb 100644
--- a/media/java/android/media/Rating2.java
+++ b/media/java/android/media/Rating2.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.content.Context;
import android.media.update.ApiLoader;
import android.media.update.Rating2Provider;
@@ -36,12 +35,10 @@
* {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
* be defined as "unrated"), both of which are defined when the rating instance is constructed
* through one of the factory methods.
- * @hide
*/
+// New version of Rating with following change
+// - Don't implement Parcelable for updatable support.
public final class Rating2 {
- // Mostly same as the android.media.Rating, but it's no longer implements Parcelable for
- // updatable support.
-
/**
* @hide
*/
@@ -100,7 +97,6 @@
/**
* @hide
*/
- @SystemApi
public Rating2(@NonNull Rating2Provider provider) {
mProvider = provider;
}
@@ -113,7 +109,6 @@
/**
* @hide
*/
- @SystemApi
public Rating2Provider getProvider() {
return mProvider;
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 209ec42..c0468dc9 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -40,7 +40,7 @@
* <p>
* For ways of retrieving {@link Ringtone} objects or to show a ringtone
* picker, see {@link RingtoneManager}.
- *
+ *
* @see RingtoneManager
*/
public class Ringtone {
@@ -97,7 +97,7 @@
/**
* Sets the stream type where this ringtone will be played.
- *
+ *
* @param streamType The stream, see {@link AudioManager}.
* @deprecated use {@link #setAudioAttributes(AudioAttributes)}
*/
@@ -111,7 +111,7 @@
/**
* Gets the stream type where this ringtone will be played.
- *
+ *
* @return The stream type, see {@link AudioManager}.
* @deprecated use of stream types is deprecated, see
* {@link #setAudioAttributes(AudioAttributes)}
@@ -146,9 +146,8 @@
}
/**
- * @hide
* Sets the player to be looping or non-looping.
- * @param looping whether to loop or not
+ * @param looping whether to loop or not.
*/
public void setLooping(boolean looping) {
synchronized (mPlaybackSettingsLock) {
@@ -158,7 +157,16 @@
}
/**
- * @hide
+ * Returns whether the looping mode was enabled on this player.
+ * @return true if this player loops when playing.
+ */
+ public boolean isLooping() {
+ synchronized (mPlaybackSettingsLock) {
+ return mIsLooping;
+ }
+ }
+
+ /**
* Sets the volume on this player.
* @param volume a raw scalar in range 0.0 to 1.0, where 0.0 mutes this player, and 1.0
* corresponds to no attenuation being applied.
@@ -173,6 +181,16 @@
}
/**
+ * Returns the volume scalar set on this player.
+ * @return a value between 0.0f and 1.0f.
+ */
+ public float getVolume() {
+ synchronized (mPlaybackSettingsLock) {
+ return mVolume;
+ }
+ }
+
+ /**
* Must be called synchronized on mPlaybackSettingsLock
*/
private void applyPlaybackProperties_sync() {
@@ -194,8 +212,8 @@
/**
* Returns a human-presentable title for ringtone. Looks in media
* content provider. If not in either, uses the filename
- *
- * @param context A context used for querying.
+ *
+ * @param context A context used for querying.
*/
public String getTitle(Context context) {
if (mTitle != null) return mTitle;
@@ -265,12 +283,11 @@
if (title == null) {
title = context.getString(com.android.internal.R.string.ringtone_unknown);
-
if (title == null) {
title = "";
}
}
-
+
return title;
}
@@ -395,7 +412,7 @@
/**
* Whether this ringtone is currently playing.
- *
+ *
* @return True if playing, false otherwise.
*/
public boolean isPlaying() {
diff --git a/media/java/android/media/SessionToken2.java b/media/java/android/media/SessionToken2.java
index 2c2090c..fdfa43a 100644
--- a/media/java/android/media/SessionToken2.java
+++ b/media/java/android/media/SessionToken2.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.content.Context;
import android.media.session.MediaSessionManager;
import android.media.update.ApiLoader;
@@ -36,8 +35,11 @@
* {@link MediaController2} to communicate with the session.
* <p>
* It can be also obtained by {@link MediaSessionManager}.
- * @hide
*/
+// New version of MediaSession.Token for following reasons
+// - Stop implementing Parcelable for updatable support
+// - Represent session and library service (formerly browser service) in one class.
+// Previously MediaSession.Token was for session and ComponentName was for service.
public final class SessionToken2 {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
@@ -86,7 +88,6 @@
* Constructor for the token.
* @hide
*/
- @SystemApi
public SessionToken2(@NonNull SessionToken2Provider provider) {
mProvider = provider;
}
@@ -106,7 +107,9 @@
return mProvider.toString_impl();
}
- @SystemApi
+ /**
+ * @hide
+ */
public SessionToken2Provider getProvider() {
return mProvider;
}
@@ -147,7 +150,7 @@
* @return
*/
public static SessionToken2 fromBundle(@NonNull Context context, @NonNull Bundle bundle) {
- return ApiLoader.getProvider(context).SessionToken2_fromBundle(context, bundle);
+ return ApiLoader.getProvider(context).fromBundle_SessionToken2(context, bundle);
}
/**
diff --git a/media/java/android/media/VolumeProvider2.java b/media/java/android/media/VolumeProvider2.java
index 53ba466..711f51f 100644
--- a/media/java/android/media/VolumeProvider2.java
+++ b/media/java/android/media/VolumeProvider2.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.content.Context;
import android.media.update.ApiLoader;
import android.media.update.VolumeProvider2Provider;
@@ -32,12 +31,11 @@
* {@link #setCurrentVolume(int)} each time the volume being provided changes.
* <p>
* You can set a volume provider on a session by calling
- * {@link MediaSession2#setPlayer(MediaPlayerInterface, VolumeProvider2)}.
- *
- * @hide
+ * {@link MediaSession2#updatePlayer}.
*/
+// New version of VolumeProvider with following changes
+// - Don't implement Parcelable for updatable support.
public abstract class VolumeProvider2 {
-
/**
* @hide
*/
@@ -85,7 +83,6 @@
/**
* @hide
*/
- @SystemApi
public VolumeProvider2Provider getProvider() {
return mProvider;
}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 7dbca3b..21d6873 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -39,6 +39,7 @@
* <li> {@link android.media.audiofx.BassBoost}</li>
* <li> {@link android.media.audiofx.PresetReverb}</li>
* <li> {@link android.media.audiofx.EnvironmentalReverb}</li>
+ * <li> {@link android.media.audiofx.DynamicsProcessing}</li>
* </ul>
* <p>To apply the audio effect to a specific AudioTrack or MediaPlayer instance,
* the application must specify the audio session ID of that instance when creating the AudioEffect.
@@ -126,6 +127,12 @@
.fromString("fe3199be-aed0-413f-87bb-11260eb63cf1");
/**
+ * UUID for Dynamics Processing
+ */
+ public static final UUID EFFECT_TYPE_DYNAMICS_PROCESSING = UUID
+ .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e");
+
+ /**
* Null effect UUID. Used when the UUID for effect type of
* @hide
*/
@@ -203,7 +210,8 @@
* {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC},
* {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB},
* {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS},
- * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}.
+ * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER},
+ * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}.
* </li>
* <li>uuid: UUID for this particular implementation</li>
* <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
@@ -224,7 +232,8 @@
* {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB},
* {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS},
* {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB},
- * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}.
+ * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER},
+ * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}.
* @param uuid UUID for this particular implementation
* @param connectMode {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
* @param name human readable effect name
@@ -246,7 +255,8 @@
* {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST},
* {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, {@link AudioEffect#EFFECT_TYPE_EQUALIZER},
* {@link AudioEffect#EFFECT_TYPE_NS}, {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}
- * or {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}.<br>
+ * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}
+ * or {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}.<br>
* For reverberation, bass boost, EQ and virtualizer, the UUID
* corresponds to the OpenSL ES Interface ID.
*/
@@ -1344,6 +1354,34 @@
/**
* @hide
*/
+ public static float byteArrayToFloat(byte[] valueBuf) {
+ return byteArrayToFloat(valueBuf, 0);
+
+ }
+
+ /**
+ * @hide
+ */
+ public static float byteArrayToFloat(byte[] valueBuf, int offset) {
+ ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+ converter.order(ByteOrder.nativeOrder());
+ return converter.getFloat(offset);
+
+ }
+
+ /**
+ * @hide
+ */
+ public static byte[] floatToByteArray(float value) {
+ ByteBuffer converter = ByteBuffer.allocate(4);
+ converter.order(ByteOrder.nativeOrder());
+ converter.putFloat(value);
+ return converter.array();
+ }
+
+ /**
+ * @hide
+ */
public static byte[] concatArrays(byte[]... arrays) {
int len = 0;
for (byte[] a : arrays) {
diff --git a/media/java/android/media/audiofx/DynamicsProcessing.java b/media/java/android/media/audiofx/DynamicsProcessing.java
new file mode 100644
index 0000000..d09c9a8
--- /dev/null
+++ b/media/java/android/media/audiofx/DynamicsProcessing.java
@@ -0,0 +1,2257 @@
+/*
+ * Copyright (C) 2018 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.media.audiofx;
+
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.DynamicsProcessing.Settings;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.StringTokenizer;
+
+/**
+ * DynamicsProcessing is an audio effect for equalizing and changing dynamic range properties of the
+ * sound. It is composed of multiple stages including equalization, multi-band compression and
+ * limiter.
+ * <p>The number of bands and active stages is configurable, and most parameters can be controlled
+ * in realtime, such as gains, attack/release times, thresholds, etc.
+ * <p>The effect is instantiated and controlled by channels. Each channel has the same basic
+ * architecture, but all of their parameters are independent from other channels.
+ * <p>The basic channel configuration is:
+ * <pre>
+ *
+ * Channel 0 Channel 1 .... Channel N-1
+ * Input Input Input
+ * | | |
+ * +----v----+ +----v----+ +----v----+
+ * |inputGain| |inputGain| |inputGain|
+ * +---------+ +---------+ +---------+
+ * | | |
+ * +-----v-----+ +-----v-----+ +-----v-----+
+ * | PreEQ | | PreEQ | | PreEQ |
+ * +-----------+ +-----------+ +-----------+
+ * | | |
+ * +-----v-----+ +-----v-----+ +-----v-----+
+ * | MBC | | MBC | | MBC |
+ * +-----------+ +-----------+ +-----------+
+ * | | |
+ * +-----v-----+ +-----v-----+ +-----v-----+
+ * | PostEQ | | PostEQ | | PostEQ |
+ * +-----------+ +-----------+ +-----------+
+ * | | |
+ * +-----v-----+ +-----v-----+ +-----v-----+
+ * | Limiter | | Limiter | | Limiter |
+ * +-----------+ +-----------+ +-----------+
+ * | | |
+ * Output Output Output
+ * </pre>
+ *
+ * <p>Where the stages are:
+ * inputGain: input gain factor in decibels (dB). 0 dB means no change in level.
+ * PreEQ: Multi-band Equalizer.
+ * MBC: Multi-band Compressor
+ * PostEQ: Multi-band Equalizer
+ * Limiter: Single band compressor/limiter.
+ *
+ * <p>An application creates a DynamicsProcessing object to instantiate and control this audio
+ * effect in the audio framework. A DynamicsProcessor.Config and DynamicsProcessor.Config.Builder
+ * are available to help configure the multiple stages and each band parameters if desired.
+ * <p>See each stage documentation for further details.
+ * <p>If no Config is specified during creation, a default configuration is chosen.
+ * <p>To attach the DynamicsProcessing to a particular AudioTrack or MediaPlayer,
+ * specify the audio session ID of this AudioTrack or MediaPlayer when constructing the effect
+ * (see {@link AudioTrack#getAudioSessionId()} and {@link MediaPlayer#getAudioSessionId()}).
+ *
+ * <p>To attach the DynamicsProcessing to a particular AudioTrack or MediaPlayer, specify the audio
+ * session ID of this AudioTrack or MediaPlayer when constructing the DynamicsProcessing.
+ * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions.
+ * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio
+ * effects.
+ */
+
+public final class DynamicsProcessing extends AudioEffect {
+
+ private final static String TAG = "DynamicsProcessing";
+
+ /**
+ * Config object used to initialize and change effect parameters at runtime.
+ */
+ private Config mConfig = null;
+
+
+ // These parameter constants must be synchronized with those in
+ // /system/media/audio_effects/include/audio_effects/effect_dynamicsprocessing.h
+
+ private static final int PARAM_GET_CHANNEL_COUNT = 0x0;
+ private static final int PARAM_EQ_BAND_COUNT = 0x1;
+ private static final int PARAM_MBC_BAND_COUNT = 0x2;
+ private static final int PARAM_INPUT_GAIN = 0x3;
+ private static final int PARAM_PRE_EQ_ENABLED = 0x10;
+ private static final int PARAM_PRE_EQ_BAND_ENABLED = 0x11;
+ private static final int PARAM_PRE_EQ_BAND_FREQUENCY = 0x12;
+ private static final int PARAM_PRE_EQ_BAND_GAIN = 0x13;
+ private static final int PARAM_EQ_FREQUENCY_RANGE = 0x22;
+ private static final int PARAM_EQ_GAIN_RANGE = 0x23;
+ private static final int PARAM_MBC_ENABLED = 0x30;
+ private static final int PARAM_MBC_BAND_ENABLED = 0x31;
+ private static final int PARAM_MBC_BAND_FREQUENCY = 0x32;
+ private static final int PARAM_MBC_BAND_ATTACK_TIME = 0x33;
+ private static final int PARAM_MBC_BAND_RELEASE_TIME = 0x34;
+ private static final int PARAM_MBC_BAND_RATIO = 0x35;
+ private static final int PARAM_MBC_BAND_THRESHOLD = 0x36;
+ private static final int PARAM_MBC_BAND_KNEE_WIDTH = 0x37;
+ private static final int PARAM_MBC_BAND_NOISE_GATE_THRESHOLD = 0x38;
+ private static final int PARAM_MBC_BAND_EXPANDER_RATIO = 0x39;
+ private static final int PARAM_MBC_BAND_GAIN_PRE = 0x3A;
+ private static final int PARAM_MBC_BAND_GAIN_POST = 0x3B;
+ private static final int PARAM_MBC_FREQUENCY_RANGE = 0x42;
+ private static final int PARAM_MBC_ATTACK_TIME_RANGE = 0x43;
+ private static final int PARAM_MBC_RELEASE_TIME_RANGE = 0x44;
+ private static final int PARAM_MBC_RATIO_RANGE = 0x45;
+ private static final int PARAM_MBC_THRESHOLD_RANGE = 0x46;
+ private static final int PARAM_MBC_KNEE_WIDTH_RANGE = 0x47;
+ private static final int PARAM_MBC_NOISE_GATE_THRESHOLD_RANGE = 0x48;
+ private static final int PARAM_MBC_EXPANDER_RATIO_RANGE = 0x49;
+ private static final int PARAM_MBC_GAIN_RANGE = 0x4A;
+ private static final int PARAM_POST_EQ_ENABLED = 0x50;
+ private static final int PARAM_POST_EQ_BAND_ENABLED = 0x51;
+ private static final int PARAM_POST_EQ_BAND_FREQUENCY = 0x52;
+ private static final int PARAM_POST_EQ_BAND_GAIN = 0x53;
+ private static final int PARAM_LIMITER_ENABLED = 0x60;
+ private static final int PARAM_LIMITER_LINK_GROUP = 0x61;
+ private static final int PARAM_LIMITER_ATTACK_TIME = 0x62;
+ private static final int PARAM_LIMITER_RELEASE_TIME = 0x63;
+ private static final int PARAM_LIMITER_RATIO = 0x64;
+ private static final int PARAM_LIMITER_THRESHOLD = 0x65;
+ private static final int PARAM_LIMITER_GAIN_POST = 0x66;
+ private static final int PARAM_LIMITER_ATTACK_TIME_RANGE = 0x72;
+ private static final int PARAM_LIMITER_RELEASE_TIME_RANGE = 0x73;
+ private static final int PARAM_LIMITER_RATIO_RANGE = 0x74;
+ private static final int PARAM_LIMITER_THRESHOLD_RANGE = 0x75;
+ private static final int PARAM_LIMITER_GAIN_RANGE = 0x76;
+ private static final int PARAM_VARIANT = 0x100;
+ private static final int PARAM_VARIANT_DESCRIPTION = 0x101;
+ private static final int PARAM_VARIANT_COUNT = 0x102;
+ private static final int PARAM_SET_ENGINE_ARCHITECTURE = 0x200;
+
+ /**
+ * Index of variant that favors frequency resolution. Frequency domain based implementation.
+ */
+ public static final int VARIANT_FAVOR_FREQUENCY_RESOLUTION = 0;
+
+ /**
+ * Index of variant that favors time resolution resolution. Time domain based implementation.
+ */
+ public static final int VARIANT_FAVOR_TIME_RESOLUTION = 1;
+
+ /**
+ * Maximum expected channels to be reported by effect
+ */
+ private static final int CHANNEL_COUNT_MAX = 32;
+
+ /**
+ * Number of channels in effect architecture
+ */
+ private int mChannelCount = 0;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change events
+ * from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * Class constructor.
+ * @param audioSession system-wide unique audio session identifier. The DynamicsProcessing
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ */
+ public DynamicsProcessing(int audioSession) {
+ this(0 /*priority*/, audioSession);
+ }
+
+ /**
+ * @hide
+ * Class constructor for the DynamicsProcessing audio effect.
+ * @param priority the priority level requested by the application for controlling the
+ * DynamicsProcessing engine. As the same engine can be shared by several applications,
+ * this parameter indicates how much the requesting application needs control of effect
+ * parameters. The normal priority is 0, above normal is a positive number, below normal a
+ * negative number.
+ * @param audioSession system-wide unique audio session identifier. The DynamicsProcessing
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ */
+ public DynamicsProcessing(int priority, int audioSession) {
+ this(priority, audioSession, null);
+ }
+
+ /**
+ * Class constructor for the DynamicsProcessing audio effect
+ * @param priority the priority level requested by the application for controlling the
+ * DynamicsProcessing engine. As the same engine can be shared by several applications,
+ * this parameter indicates how much the requesting application needs control of effect
+ * parameters. The normal priority is 0, above normal is a positive number, below normal a
+ * negative number.
+ * @param audioSession system-wide unique audio session identifier. The DynamicsProcessing
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ * @param cfg Config object used to setup the audio effect, including bands per stage, and
+ * specific parameters for each stage/band. Use
+ * {@link android.media.audiofx.DynamicsProcessing.Config.Builder} to create a
+ * Config object that suits your needs. A null cfg parameter will create and use a default
+ * configuration for the effect
+ */
+ public DynamicsProcessing(int priority, int audioSession, Config cfg) {
+ super(EFFECT_TYPE_DYNAMICS_PROCESSING, EFFECT_TYPE_NULL, priority, audioSession);
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a DynamicsProcessing to global output mix is"
+ + "deprecated!");
+ }
+ mChannelCount = getChannelCount();
+ if (cfg == null) {
+ //create a default configuration and effect, with the number of channels this effect has
+ DynamicsProcessing.Config.Builder builder =
+ new DynamicsProcessing.Config.Builder(
+ CONFIG_DEFAULT_VARIANT,
+ mChannelCount,
+ true /*use preEQ*/, 6 /*pre eq bands*/,
+ true /*use mbc*/, 6 /*mbc bands*/,
+ true /*use postEQ*/, 6 /*postEq bands*/,
+ true /*use Limiter*/);
+ mConfig = builder.build();
+ } else {
+ //validate channels are ok. decide what to do: replicate channels if more, or fail, or
+ mConfig = new DynamicsProcessing.Config(mChannelCount, cfg);
+ }
+
+ setEngineArchitecture(mConfig.getVariant(),
+ mConfig.isPreEqInUse(), mConfig.getPreEqBandCount(),
+ mConfig.isMbcInUse(), mConfig.getMbcBandCount(),
+ mConfig.isPostEqInUse(), mConfig.getPostEqBandCount(),
+ mConfig.isLimiterInUse());
+ }
+
+ /**
+ * Returns the Config object used to setup this effect.
+ * @return Config Current Config object used to setup this DynamicsProcessing effect.
+ */
+ public Config getConfig() {
+ return mConfig;
+ }
+
+
+ private static final int CONFIG_DEFAULT_VARIANT = 0; //favor frequency
+ private static final float CHANNEL_DEFAULT_INPUT_GAIN = 0; // dB
+ private static final float CONFIG_PREFERRED_FRAME_DURATION_MS = 10.0f; //milliseconds
+
+ private static final float EQ_DEFAULT_GAIN = 0; // dB
+ private static final boolean PREEQ_DEFAULT_ENABLED = true;
+ private static final boolean POSTEQ_DEFAULT_ENABLED = true;
+
+
+ private static final boolean MBC_DEFAULT_ENABLED = true;
+ private static final float MBC_DEFAULT_ATTACK_TIME = 50; // ms
+ private static final float MBC_DEFAULT_RELEASE_TIME = 120; // ms
+ private static final float MBC_DEFAULT_RATIO = 2; // 1:N
+ private static final float MBC_DEFAULT_THRESHOLD = -30; // dB
+ private static final float MBC_DEFAULT_KNEE_WIDTH = 0; // dB
+ private static final float MBC_DEFAULT_NOISE_GATE_THRESHOLD = -80; // dB
+ private static final float MBC_DEFAULT_EXPANDER_RATIO = 1.5f; // N:1
+ private static final float MBC_DEFAULT_PRE_GAIN = 0; // dB
+ private static final float MBC_DEFAULT_POST_GAIN = 10; // dB
+
+ private static final boolean LIMITER_DEFAULT_ENABLED = true;
+ private static final int LIMITER_DEFAULT_LINK_GROUP = 0;//;
+ private static final float LIMITER_DEFAULT_ATTACK_TIME = 50; // ms
+ private static final float LIMITER_DEFAULT_RELEASE_TIME = 120; // ms
+ private static final float LIMITER_DEFAULT_RATIO = 2; // 1:N
+ private static final float LIMITER_DEFAULT_THRESHOLD = -30; // dB
+ private static final float LIMITER_DEFAULT_POST_GAIN = 10; // dB
+
+ private static final float DEFAULT_MIN_FREQUENCY = 220; // Hz
+ private static final float DEFAULT_MAX_FREQUENCY = 20000; // Hz
+ private static final float mMinFreqLog = (float)Math.log10(DEFAULT_MIN_FREQUENCY);
+ private static final float mMaxFreqLog = (float)Math.log10(DEFAULT_MAX_FREQUENCY);
+
+ /**
+ * base class for the different stages.
+ */
+ public static class Stage {
+ private boolean mInUse;
+ private boolean mEnabled;
+ /**
+ * Class constructor for stage
+ * @param inUse true if this stage is set to be used. False otherwise. Stages that are not
+ * set "inUse" at initialization time are not available to be used at any time.
+ * @param enabled true if this stage is currently used to process sound. When disabled,
+ * the stage is bypassed and the sound is copied unaltered from input to output.
+ */
+ public Stage(boolean inUse, boolean enabled) {
+ mInUse = inUse;
+ mEnabled = enabled;
+ }
+
+ /**
+ * returns enabled state of the stage
+ * @return true if stage is enabled for processing, false otherwise
+ */
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+ /**
+ * sets enabled state of the stage
+ * @param enabled true for enabled, false otherwise
+ */
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ /**
+ * returns inUse state of the stage.
+ * @return inUse state of the stage. True if this stage is currently used to process sound.
+ * When false, the stage is bypassed and the sound is copied unaltered from input to output.
+ */
+ public boolean isInUse() {
+ return mInUse;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format(" Stage InUse: %b\n", isInUse()));
+ if (isInUse()) {
+ sb.append(String.format(" Stage Enabled: %b\n", mEnabled));
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Base class for stages that hold bands
+ */
+ public static class BandStage extends Stage{
+ private int mBandCount;
+ /**
+ * Class constructor for BandStage
+ * @param inUse true if this stage is set to be used. False otherwise. Stages that are not
+ * set "inUse" at initialization time are not available to be used at any time.
+ * @param enabled true if this stage is currently used to process sound. When disabled,
+ * the stage is bypassed and the sound is copied unaltered from input to output.
+ * @param bandCount number of bands this stage will handle. If stage is not inUse, bandcount
+ * is set to 0
+ */
+ public BandStage(boolean inUse, boolean enabled, int bandCount) {
+ super(inUse, enabled);
+ mBandCount = isInUse() ? bandCount : 0;
+ }
+
+ /**
+ * gets number of bands held in this stage
+ * @return number of bands held in this stage
+ */
+ public int getBandCount() {
+ return mBandCount;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ if (isInUse()) {
+ sb.append(String.format(" Band Count: %d\n", mBandCount));
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Base class for bands
+ */
+ public static class BandBase {
+ private boolean mEnabled;
+ private float mCutoffFrequency;
+ /**
+ * Class constructor for BandBase
+ * @param enabled true if this band is currently used to process sound. When false,
+ * the band is effectively muted and sound set to zero.
+ * @param cutoffFrequency topmost frequency number (in Hz) this band will process. The
+ * effective bandwidth for the band is then computed using this and the previous band
+ * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with
+ * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on.
+ */
+ public BandBase(boolean enabled, float cutoffFrequency) {
+ mEnabled = enabled;
+ mCutoffFrequency = cutoffFrequency;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format(" Enabled: %b\n", mEnabled));
+ sb.append(String.format(" CutoffFrequency: %f\n", mCutoffFrequency));
+ return sb.toString();
+ }
+
+ /**
+ * returns enabled state of the band
+ * @return true if bands is enabled for processing, false otherwise
+ */
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+ /**
+ * sets enabled state of the band
+ * @param enabled true for enabled, false otherwise
+ */
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ /**
+ * gets cutoffFrequency for this band in Hertz (Hz)
+ * @return cutoffFrequency for this band in Hertz (Hz)
+ */
+ public float getCutoffFrequency() {
+ return mCutoffFrequency;
+ }
+
+ /**
+ * sets topmost frequency number (in Hz) this band will process. The
+ * effective bandwidth for the band is then computed using this and the previous band
+ * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with
+ * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on.
+ * @param frequency
+ */
+ public void setCutoffFrequency(float frequency) {
+ mCutoffFrequency = frequency;
+ }
+ }
+
+ /**
+ * Class for Equalizer Bands
+ * Equalizer bands have three controllable parameters: enabled/disabled, cutoffFrequency and
+ * gain
+ */
+ public final static class EqBand extends BandBase {
+ private float mGain;
+ /**
+ * Class constructor for EqBand
+ * @param enabled true if this band is currently used to process sound. When false,
+ * the band is effectively muted and sound set to zero.
+ * @param cutoffFrequency topmost frequency number (in Hz) this band will process. The
+ * effective bandwidth for the band is then computed using this and the previous band
+ * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with
+ * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on.
+ * @param gain of equalizer band in decibels (dB). A gain of 0 dB means no change in level.
+ */
+ public EqBand(boolean enabled, float cutoffFrequency, float gain) {
+ super(enabled, cutoffFrequency);
+ mGain = gain;
+ }
+
+ /**
+ * Class constructor for EqBand
+ * @param cfg copy constructor
+ */
+ public EqBand(EqBand cfg) {
+ super(cfg.isEnabled(), cfg.getCutoffFrequency());
+ mGain = cfg.mGain;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ sb.append(String.format(" Gain: %f\n", mGain));
+ return sb.toString();
+ }
+
+ /**
+ * gets current gain of band in decibels (dB)
+ * @return current gain of band in decibels (dB)
+ */
+ public float getGain() {
+ return mGain;
+ }
+
+ /**
+ * sets current gain of band in decibels (dB)
+ * @param gain desired in decibels (db)
+ */
+ public void setGain(float gain) {
+ mGain = gain;
+ }
+ }
+
+ /**
+ * Class for Multi-Band compressor bands
+ * MBC bands have multiple controllable parameters: enabled/disabled, cutoffFrequency,
+ * attackTime, releaseTime, ratio, threshold, kneeWidth, noiseGateThreshold, expanderRatio,
+ * preGain and postGain.
+ */
+ public final static class MbcBand extends BandBase{
+ private float mAttackTime;
+ private float mReleaseTime;
+ private float mRatio;
+ private float mThreshold;
+ private float mKneeWidth;
+ private float mNoiseGateThreshold;
+ private float mExpanderRatio;
+ private float mPreGain;
+ private float mPostGain;
+ /**
+ * Class constructor for MbcBand
+ * @param enabled true if this band is currently used to process sound. When false,
+ * the band is effectively muted and sound set to zero.
+ * @param cutoffFrequency topmost frequency number (in Hz) this band will process. The
+ * effective bandwidth for the band is then computed using this and the previous band
+ * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with
+ * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on.
+ * @param attackTime Attack Time for compressor in milliseconds (ms)
+ * @param releaseTime Release Time for compressor in milliseconds (ms)
+ * @param ratio Compressor ratio (1:N)
+ * @param threshold Compressor threshold measured in decibels (dB) from 0 dB Full Scale
+ * (dBFS).
+ * @param kneeWidth Width in decibels (dB) around compressor threshold point.
+ * @param noiseGateThreshold Noise gate threshold in decibels (dB) from 0 dB Full Scale
+ * (dBFS).
+ * @param expanderRatio Expander ratio (N:1) for signals below the Noise Gate Threshold.
+ * @param preGain Gain applied to the signal BEFORE the compression.
+ * @param postGain Gain applied to the signal AFTER compression.
+ */
+ public MbcBand(boolean enabled, float cutoffFrequency, float attackTime, float releaseTime,
+ float ratio, float threshold, float kneeWidth, float noiseGateThreshold,
+ float expanderRatio, float preGain, float postGain) {
+ super(enabled, cutoffFrequency);
+ mAttackTime = attackTime;
+ mReleaseTime = releaseTime;
+ mRatio = ratio;
+ mThreshold = threshold;
+ mKneeWidth = kneeWidth;
+ mNoiseGateThreshold = noiseGateThreshold;
+ mExpanderRatio = expanderRatio;
+ mPreGain = preGain;
+ mPostGain = postGain;
+ }
+
+ /**
+ * Class constructor for MbcBand
+ * @param cfg copy constructor
+ */
+ public MbcBand(MbcBand cfg) {
+ super(cfg.isEnabled(), cfg.getCutoffFrequency());
+ mAttackTime = cfg.mAttackTime;
+ mReleaseTime = cfg.mReleaseTime;
+ mRatio = cfg.mRatio;
+ mThreshold = cfg.mThreshold;
+ mKneeWidth = cfg.mKneeWidth;
+ mNoiseGateThreshold = cfg.mNoiseGateThreshold;
+ mExpanderRatio = cfg.mExpanderRatio;
+ mPreGain = cfg.mPreGain;
+ mPostGain = cfg.mPostGain;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ sb.append(String.format(" AttackTime: %f (ms)\n", mAttackTime));
+ sb.append(String.format(" ReleaseTime: %f (ms)\n", mReleaseTime));
+ sb.append(String.format(" Ratio: 1:%f\n", mRatio));
+ sb.append(String.format(" Threshold: %f (dB)\n", mThreshold));
+ sb.append(String.format(" NoiseGateThreshold: %f(dB)\n", mNoiseGateThreshold));
+ sb.append(String.format(" ExpanderRatio: %f:1\n", mExpanderRatio));
+ sb.append(String.format(" PreGain: %f (dB)\n", mPreGain));
+ sb.append(String.format(" PostGain: %f (dB)\n", mPostGain));
+ return sb.toString();
+ }
+
+ /**
+ * gets attack time for compressor in milliseconds (ms)
+ * @return attack time for compressor in milliseconds (ms)
+ */
+ public float getAttackTime() { return mAttackTime; }
+ /**
+ * sets attack time for compressor in milliseconds (ms)
+ * @param attackTime desired for compressor in milliseconds (ms)
+ */
+ public void setAttackTime(float attackTime) { mAttackTime = attackTime; }
+ /**
+ * gets release time for compressor in milliseconds (ms)
+ * @return release time for compressor in milliseconds (ms)
+ */
+ public float getReleaseTime() { return mReleaseTime; }
+ /**
+ * sets release time for compressor in milliseconds (ms)
+ * @param releaseTime desired for compressor in milliseconds (ms)
+ */
+ public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; }
+ /**
+ * gets the compressor ratio (1:N)
+ * @return compressor ratio (1:N)
+ */
+ public float getRatio() { return mRatio; }
+ /**
+ * sets compressor ratio (1:N)
+ * @param ratio desired for the compressor (1:N)
+ */
+ public void setRatio(float ratio) { mRatio = ratio; }
+ /**
+ * gets the compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Thresholds are negative. A threshold of 0 dB means no compression will take place.
+ * @return compressor threshold in decibels (dB)
+ */
+ public float getThreshold() { return mThreshold; }
+ /**
+ * sets the compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Thresholds are negative. A threshold of 0 dB means no compression will take place.
+ * @param threshold desired for compressor in decibels(dB)
+ */
+ public void setThreshold(float threshold) { mThreshold = threshold; }
+ /**
+ * get Knee Width in decibels (dB) around compressor threshold point. Widths are always
+ * positive, with higher values representing a wider area of transition from the linear zone
+ * to the compression zone. A knee of 0 dB means a more abrupt transition.
+ * @return Knee Width in decibels (dB)
+ */
+ public float getKneeWidth() { return mKneeWidth; }
+ /**
+ * sets knee width in decibels (dB). See
+ * {@link android.media.audiofx.DynamicsProcessing.MbcBand#getKneeWidth} for more
+ * information.
+ * @param kneeWidth desired in decibels (dB)
+ */
+ public void setKneeWidth(float kneeWidth) { mKneeWidth = kneeWidth; }
+ /**
+ * gets the noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS). Noise gate
+ * thresholds are negative. Signals below this level will be expanded according the
+ * expanderRatio parameter. A Noise Gate Threshold of -75 dB means very quiet signals might
+ * be effectively removed from the signal.
+ * @return Noise Gate Threshold in decibels (dB)
+ */
+ public float getNoiseGateThreshold() { return mNoiseGateThreshold; }
+ /**
+ * sets noise gate threshod in decibels (dB). See
+ * {@link android.media.audiofx.DynamicsProcessing.MbcBand#getNoiseGateThreshold} for more
+ * information.
+ * @param noiseGateThreshold desired in decibels (dB)
+ */
+ public void setNoiseGateThreshold(float noiseGateThreshold) {
+ mNoiseGateThreshold = noiseGateThreshold; }
+ /**
+ * gets Expander ratio (N:1) for signals below the Noise Gate Threshold.
+ * @return Expander ratio (N:1)
+ */
+ public float getExpanderRatio() { return mExpanderRatio; }
+ /**
+ * sets Expander ratio (N:1) for signals below the Noise Gate Threshold.
+ * @param expanderRatio desired expander ratio (N:1)
+ */
+ public void setExpanderRatio(float expanderRatio) { mExpanderRatio = expanderRatio; }
+ /**
+ * gets the gain applied to the signal BEFORE the compression. Measured in decibels (dB)
+ * where 0 dB means no level change.
+ * @return preGain value in decibels (dB)
+ */
+ public float getPreGain() { return mPreGain; }
+ /**
+ * sets the gain to be applied to the signal BEFORE the compression, measured in decibels
+ * (dB), where 0 dB means no level change.
+ * @param preGain desired in decibels (dB)
+ */
+ public void setPreGain(float preGain) { mPreGain = preGain; }
+ /**
+ * gets the gain applied to the signal AFTER compression. Measured in decibels (dB) where 0
+ * dB means no level change
+ * @return postGain value in decibels (dB)
+ */
+ public float getPostGain() { return mPostGain; }
+ /**
+ * sets the gain to be applied to the siganl AFTER the compression. Measured in decibels
+ * (dB), where 0 dB means no level change.
+ * @param postGain desired value in decibels (dB)
+ */
+ public void setPostGain(float postGain) { mPostGain = postGain; }
+ }
+
+ /**
+ * Class for Equalizer stage
+ */
+ public final static class Eq extends BandStage {
+ private final EqBand[] mBands;
+ /**
+ * Class constructor for Equalizer (Eq) stage
+ * @param inUse true if Eq stage will be used, false otherwise.
+ * @param enabled true if Eq stage is enabled/disabled. This can be changed while effect is
+ * running
+ * @param bandCount number of bands for this Equalizer stage. Can't be changed while effect
+ * is running
+ */
+ public Eq(boolean inUse, boolean enabled, int bandCount) {
+ super(inUse, enabled, bandCount);
+ if (isInUse()) {
+ mBands = new EqBand[bandCount];
+ for (int b = 0; b < bandCount; b++) {
+ float freq = DEFAULT_MAX_FREQUENCY;
+ if (bandCount > 1) {
+ freq = (float)Math.pow(10, mMinFreqLog +
+ b * (mMaxFreqLog - mMinFreqLog)/(bandCount -1));
+ }
+ mBands[b] = new EqBand(true, freq, EQ_DEFAULT_GAIN);
+ }
+ } else {
+ mBands = null;
+ }
+ }
+ /**
+ * Class constructor for Eq stage
+ * @param cfg copy constructor
+ */
+ public Eq(Eq cfg) {
+ super(cfg.isInUse(), cfg.isEnabled(), cfg.getBandCount());
+ if (isInUse()) {
+ mBands = new EqBand[cfg.mBands.length];
+ for (int b = 0; b < mBands.length; b++) {
+ mBands[b] = new EqBand(cfg.mBands[b]);
+ }
+ } else {
+ mBands = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ if (isInUse()) {
+ sb.append("--->EqBands: " + mBands.length + "\n");
+ for (int b = 0; b < mBands.length; b++) {
+ sb.append(String.format(" Band %d\n", b));
+ sb.append(mBands[b].toString());
+ }
+ }
+ return sb.toString();
+ }
+ /**
+ * Helper function to check if band index is within range
+ * @param band index to check
+ */
+ private void checkBand(int band) {
+ if (mBands == null || band < 0 || band >= mBands.length) {
+ throw new IllegalArgumentException("band index " + band +" out of bounds");
+ }
+ }
+ /**
+ * Sets EqBand object for given band index
+ * @param band index of band to be modified
+ * @param bandCfg EqBand object.
+ */
+ public void setBand(int band, EqBand bandCfg) {
+ checkBand(band);
+ mBands[band] = new EqBand(bandCfg);
+ }
+ /**
+ * Gets EqBand object for band of interest.
+ * @param band index of band of interest
+ * @return EqBand Object
+ */
+ public EqBand getBand(int band) {
+ checkBand(band);
+ return mBands[band];
+ }
+ }
+
+ /**
+ * Class for Multi-Band Compressor (MBC) stage
+ */
+ public final static class Mbc extends BandStage {
+ private final MbcBand[] mBands;
+ /**
+ * Constructor for Multi-Band Compressor (MBC) stage
+ * @param inUse true if MBC stage will be used, false otherwise.
+ * @param enabled true if MBC stage is enabled/disabled. This can be changed while effect
+ * is running
+ * @param bandCount number of bands for this MBC stage. Can't be changed while effect is
+ * running
+ */
+ public Mbc(boolean inUse, boolean enabled, int bandCount) {
+ super(inUse, enabled, bandCount);
+ if (isInUse()) {
+ mBands = new MbcBand[bandCount];
+ for (int b = 0; b < bandCount; b++) {
+ float freq = DEFAULT_MAX_FREQUENCY;
+ if (bandCount > 1) {
+ freq = (float)Math.pow(10, mMinFreqLog +
+ b * (mMaxFreqLog - mMinFreqLog)/(bandCount -1));
+ }
+ mBands[b] = new MbcBand(true, freq, MBC_DEFAULT_ATTACK_TIME,
+ MBC_DEFAULT_RELEASE_TIME, MBC_DEFAULT_RATIO,
+ MBC_DEFAULT_THRESHOLD, MBC_DEFAULT_KNEE_WIDTH,
+ MBC_DEFAULT_NOISE_GATE_THRESHOLD, MBC_DEFAULT_EXPANDER_RATIO,
+ MBC_DEFAULT_PRE_GAIN, MBC_DEFAULT_POST_GAIN);
+ }
+ } else {
+ mBands = null;
+ }
+ }
+ /**
+ * Class constructor for MBC stage
+ * @param cfg copy constructor
+ */
+ public Mbc(Mbc cfg) {
+ super(cfg.isInUse(), cfg.isEnabled(), cfg.getBandCount());
+ if (isInUse()) {
+ mBands = new MbcBand[cfg.mBands.length];
+ for (int b = 0; b < mBands.length; b++) {
+ mBands[b] = new MbcBand(cfg.mBands[b]);
+ }
+ } else {
+ mBands = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ if (isInUse()) {
+ sb.append("--->MbcBands: " + mBands.length + "\n");
+ for (int b = 0; b < mBands.length; b++) {
+ sb.append(String.format(" Band %d\n", b));
+ sb.append(mBands[b].toString());
+ }
+ }
+ return sb.toString();
+ }
+ /**
+ * Helper function to check if band index is within range
+ * @param band index to check
+ */
+ private void checkBand(int band) {
+ if (mBands == null || band < 0 || band >= mBands.length) {
+ throw new IllegalArgumentException("band index " + band +" out of bounds");
+ }
+ }
+ /**
+ * Sets MbcBand object for given band index
+ * @param band index of band to be modified
+ * @param bandCfg MbcBand object.
+ */
+ public void setBand(int band, MbcBand bandCfg) {
+ checkBand(band);
+ mBands[band] = new MbcBand(bandCfg);
+ }
+ /**
+ * Gets MbcBand object for band of interest.
+ * @param band index of band of interest
+ * @return MbcBand Object
+ */
+ public MbcBand getBand(int band) {
+ checkBand(band);
+ return mBands[band];
+ }
+ }
+
+ /**
+ * Class for Limiter Stage
+ * Limiter is a single band compressor at the end of the processing chain, commonly used to
+ * protect the signal from overloading and distortion. Limiters have multiple controllable
+ * parameters: enabled/disabled, linkGroup, attackTime, releaseTime, ratio, threshold, and
+ * postGain.
+ * <p>Limiters can be linked in groups across multiple channels. Linked limiters will trigger
+ * the same limiting if any of the linked limiters starts compressing.
+ */
+ public final static class Limiter extends Stage {
+ private int mLinkGroup;
+ private float mAttackTime;
+ private float mReleaseTime;
+ private float mRatio;
+ private float mThreshold;
+ private float mPostGain;
+
+ /**
+ * Class constructor for Limiter Stage
+ * @param inUse true if MBC stage will be used, false otherwise.
+ * @param enabled true if MBC stage is enabled/disabled. This can be changed while effect
+ * is running
+ * @param linkGroup index of group assigned to this Limiter. Only limiters that share the
+ * same linkGroup index will react together.
+ * @param attackTime Attack Time for limiter compressor in milliseconds (ms)
+ * @param releaseTime Release Time for limiter compressor in milliseconds (ms)
+ * @param ratio Limiter Compressor ratio (1:N)
+ * @param threshold Limiter Compressor threshold measured in decibels (dB) from 0 dB Full
+ * Scale (dBFS).
+ * @param postGain Gain applied to the signal AFTER compression.
+ */
+ public Limiter(boolean inUse, boolean enabled, int linkGroup, float attackTime,
+ float releaseTime, float ratio, float threshold, float postGain) {
+ super(inUse, enabled);
+ mLinkGroup = linkGroup;
+ mAttackTime = attackTime;
+ mReleaseTime = releaseTime;
+ mRatio = ratio;
+ mThreshold = threshold;
+ mPostGain = postGain;
+ }
+
+ /**
+ * Class Constructor for Limiter
+ * @param cfg copy constructor
+ */
+ public Limiter(Limiter cfg) {
+ super(cfg.isInUse(), cfg.isEnabled());
+ mLinkGroup = cfg.mLinkGroup;
+ mAttackTime = cfg.mAttackTime;
+ mReleaseTime = cfg.mReleaseTime;
+ mRatio = cfg.mRatio;
+ mThreshold = cfg.mThreshold;
+ mPostGain = cfg.mPostGain;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ if (isInUse()) {
+ sb.append(String.format(" LinkGroup: %d (group)\n", mLinkGroup));
+ sb.append(String.format(" AttackTime: %f (ms)\n", mAttackTime));
+ sb.append(String.format(" ReleaseTime: %f (ms)\n", mReleaseTime));
+ sb.append(String.format(" Ratio: 1:%f\n", mRatio));
+ sb.append(String.format(" Threshold: %f (dB)\n", mThreshold));
+ sb.append(String.format(" PostGain: %f (dB)\n", mPostGain));
+ }
+ return sb.toString();
+ }
+ /**
+ * Gets the linkGroup index for this Limiter Stage. Only limiters that share the same
+ * linkGroup index will react together.
+ * @return linkGroup index.
+ */
+ public int getLinkGroup() { return mLinkGroup; }
+ /**
+ * Sets the linkGroup index for this limiter Stage.
+ * @param linkGroup desired linkGroup index
+ */
+ public void setLinkGroup(int linkGroup) { mLinkGroup = linkGroup; }
+ /**
+ * gets attack time for limiter compressor in milliseconds (ms)
+ * @return attack time for limiter compressor in milliseconds (ms)
+ */
+ public float getAttackTime() { return mAttackTime; }
+ /**
+ * sets attack time for limiter compressor in milliseconds (ms)
+ * @param attackTime desired for limiter compressor in milliseconds (ms)
+ */
+ public void setAttackTime(float attackTime) { mAttackTime = attackTime; }
+ /**
+ * gets release time for limiter compressor in milliseconds (ms)
+ * @return release time for limiter compressor in milliseconds (ms)
+ */
+ public float getReleaseTime() { return mReleaseTime; }
+ /**
+ * sets release time for limiter compressor in milliseconds (ms)
+ * @param releaseTime desired for limiter compressor in milliseconds (ms)
+ */
+ public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; }
+ /**
+ * gets the limiter compressor ratio (1:N)
+ * @return limiter compressor ratio (1:N)
+ */
+ public float getRatio() { return mRatio; }
+ /**
+ * sets limiter compressor ratio (1:N)
+ * @param ratio desired for the limiter compressor (1:N)
+ */
+ public void setRatio(float ratio) { mRatio = ratio; }
+ /**
+ * gets the limiter compressor threshold measured in decibels (dB) from 0 dB Full Scale
+ * (dBFS). Thresholds are negative. A threshold of 0 dB means no limiting will take place.
+ * @return limiter compressor threshold in decibels (dB)
+ */
+ public float getThreshold() { return mThreshold; }
+ /**
+ * sets the limiter compressor threshold measured in decibels (dB) from 0 dB Full Scale
+ * (dBFS). Thresholds are negative. A threshold of 0 dB means no limiting will take place.
+ * @param threshold desired for limiter compressor in decibels(dB)
+ */
+ public void setThreshold(float threshold) { mThreshold = threshold; }
+ /**
+ * gets the gain applied to the signal AFTER limiting. Measured in decibels (dB) where 0
+ * dB means no level change
+ * @return postGain value in decibels (dB)
+ */
+ public float getPostGain() { return mPostGain; }
+ /**
+ * sets the gain to be applied to the siganl AFTER the limiter. Measured in decibels
+ * (dB), where 0 dB means no level change.
+ * @param postGain desired value in decibels (dB)
+ */
+ public void setPostGain(float postGain) { mPostGain = postGain; }
+ }
+
+ /**
+ * Class for Channel configuration parameters. It is composed of multiple stages, which can be
+ * used/enabled independently. Stages not used or disabled will be bypassed and the sound would
+ * be unaffected by them.
+ */
+ public final static class Channel {
+ private float mInputGain;
+ private Eq mPreEq;
+ private Mbc mMbc;
+ private Eq mPostEq;
+ private Limiter mLimiter;
+
+ /**
+ * Class constructor for Channel configuration.
+ * @param inputGain value in decibels (dB) of level change applied to the audio before
+ * processing. A value of 0 dB means no change.
+ * @param preEqInUse true if PreEq stage will be used, false otherwise. This can't be
+ * changed later.
+ * @param preEqBandCount number of bands for PreEq stage. This can't be changed later.
+ * @param mbcInUse true if Mbc stage will be used, false otherwise. This can't be changed
+ * later.
+ * @param mbcBandCount number of bands for Mbc stage. This can't be changed later.
+ * @param postEqInUse true if PostEq stage will be used, false otherwise. This can't be
+ * changed later.
+ * @param postEqBandCount number of bands for PostEq stage. This can't be changed later.
+ * @param limiterInUse true if Limiter stage will be used, false otherwise. This can't be
+ * changed later.
+ */
+ public Channel (float inputGain,
+ boolean preEqInUse, int preEqBandCount,
+ boolean mbcInUse, int mbcBandCount,
+ boolean postEqInUse, int postEqBandCount,
+ boolean limiterInUse) {
+ mInputGain = inputGain;
+ mPreEq = new Eq(preEqInUse, PREEQ_DEFAULT_ENABLED, preEqBandCount);
+ mMbc = new Mbc(mbcInUse, MBC_DEFAULT_ENABLED, mbcBandCount);
+ mPostEq = new Eq(postEqInUse, POSTEQ_DEFAULT_ENABLED,
+ postEqBandCount);
+ mLimiter = new Limiter(limiterInUse,
+ LIMITER_DEFAULT_ENABLED, LIMITER_DEFAULT_LINK_GROUP,
+ LIMITER_DEFAULT_ATTACK_TIME, LIMITER_DEFAULT_RELEASE_TIME,
+ LIMITER_DEFAULT_RATIO, LIMITER_DEFAULT_THRESHOLD, LIMITER_DEFAULT_POST_GAIN);
+ }
+
+ /**
+ * Class constructor for Channel configuration
+ * @param cfg copy constructor
+ */
+ public Channel(Channel cfg) {
+ mInputGain = cfg.mInputGain;
+ mPreEq = new Eq(cfg.mPreEq);
+ mMbc = new Mbc(cfg.mMbc);
+ mPostEq = new Eq(cfg.mPostEq);
+ mLimiter = new Limiter(cfg.mLimiter);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format(" InputGain: %f\n", mInputGain));
+ sb.append("-->PreEq\n");
+ sb.append(mPreEq.toString());
+ sb.append("-->MBC\n");
+ sb.append(mMbc.toString());
+ sb.append("-->PostEq\n");
+ sb.append(mPostEq.toString());
+ sb.append("-->Limiter\n");
+ sb.append(mLimiter.toString());
+ return sb.toString();
+ }
+ /**
+ * Gets inputGain value in decibels (dB). 0 dB means no change;
+ * @return gain value in decibels (dB)
+ */
+ public float getInputGain() {
+ return mInputGain;
+ }
+ /**
+ * Sets inputGain value in decibels (dB). 0 dB means no change;
+ * @param inputGain desired gain value in decibels (dB)
+ */
+ public void setInputGain(float inputGain) {
+ mInputGain = inputGain;
+ }
+
+ /**
+ * Gets PreEq configuration stage
+ * @return PreEq configuration stage
+ */
+ public Eq getPreEq() {
+ return mPreEq;
+ }
+ /**
+ * Sets PreEq configuration stage. New PreEq stage must have the same number of bands than
+ * original PreEq stage.
+ * @param preEq configuration
+ */
+ public void setPreEq(Eq preEq) {
+ if (preEq.getBandCount() != mPreEq.getBandCount()) {
+ throw new IllegalArgumentException("PreEqBandCount changed from " +
+ mPreEq.getBandCount() + " to " + preEq.getBandCount());
+ }
+ mPreEq = new Eq(preEq);
+ }
+ /**
+ * Gets EqBand for PreEq stage for given band index.
+ * @param band index of band of interest from PreEq stage
+ * @return EqBand configuration
+ */
+ public EqBand getPreEqBand(int band) {
+ return mPreEq.getBand(band);
+ }
+ /**
+ * Sets EqBand for PreEq stage for given band index
+ * @param band index of band of interest from PreEq stage
+ * @param preEqBand configuration to be set.
+ */
+ public void setPreEqBand(int band, EqBand preEqBand) {
+ mPreEq.setBand(band, preEqBand);
+ }
+
+ /**
+ * Gets Mbc configuration stage
+ * @return Mbc configuration stage
+ */
+ public Mbc getMbc() {
+ return mMbc;
+ }
+ /**
+ * Sets Mbc configuration stage. New Mbc stage must have the same number of bands than
+ * original Mbc stage.
+ * @param mbc
+ */
+ public void setMbc(Mbc mbc) {
+ if (mbc.getBandCount() != mMbc.getBandCount()) {
+ throw new IllegalArgumentException("MbcBandCount changed from " +
+ mMbc.getBandCount() + " to " + mbc.getBandCount());
+ }
+ mMbc = new Mbc(mbc);
+ }
+ /**
+ * Gets MbcBand configuration for Mbc stage, for given band index.
+ * @param band index of band of interest from Mbc stage
+ * @return MbcBand configuration
+ */
+ public MbcBand getMbcBand(int band) {
+ return mMbc.getBand(band);
+ }
+ /**
+ * Sets MbcBand for Mbc stage for given band index
+ * @param band index of band of interest from Mbc Stage
+ * @param mbcBand configuration to be set
+ */
+ public void setMbcBand(int band, MbcBand mbcBand) {
+ mMbc.setBand(band, mbcBand);
+ }
+
+ /**
+ * Gets PostEq configuration stage
+ * @return PostEq configuration stage
+ */
+ public Eq getPostEq() {
+ return mPostEq;
+ }
+ /**
+ * Sets PostEq configuration stage. New PostEq stage must have the same number of bands than
+ * original PostEq stage.
+ * @param postEq configuration
+ */
+ public void setPostEq(Eq postEq) {
+ if (postEq.getBandCount() != mPostEq.getBandCount()) {
+ throw new IllegalArgumentException("PostEqBandCount changed from " +
+ mPostEq.getBandCount() + " to " + postEq.getBandCount());
+ }
+ mPostEq = new Eq(postEq);
+ }
+ /**
+ * Gets EqBand for PostEq stage for given band index.
+ * @param band index of band of interest from PostEq stage
+ * @return EqBand configuration
+ */
+ public EqBand getPostEqBand(int band) {
+ return mPostEq.getBand(band);
+ }
+ /**
+ * Sets EqBand for PostEq stage for given band index
+ * @param band index of band of interest from PostEq stage
+ * @param postEqBand configuration to be set.
+ */
+ public void setPostEqBand(int band, EqBand postEqBand) {
+ mPostEq.setBand(band, postEqBand);
+ }
+
+ /**
+ * Gets Limiter configuration stage
+ * @return Limiter configuration stage
+ */
+ public Limiter getLimiter() {
+ return mLimiter;
+ }
+ /**
+ * Sets Limiter configuration stage.
+ * @param limiter configuration stage.
+ */
+ public void setLimiter(Limiter limiter) {
+ mLimiter = new Limiter(limiter);
+ }
+ }
+
+ /**
+ * Class for Config object, used by DynamicsProcessing to configure and update the audio effect.
+ * use Builder to instantiate objects of this type.
+ */
+ public final static class Config {
+ private final int mVariant;
+ private final int mChannelCount;
+ private final boolean mPreEqInUse;
+ private final int mPreEqBandCount;
+ private final boolean mMbcInUse;
+ private final int mMbcBandCount;
+ private final boolean mPostEqInUse;
+ private final int mPostEqBandCount;
+ private final boolean mLimiterInUse;
+ private final float mPreferredFrameDuration;
+ private final Channel[] mChannel;
+
+ /**
+ * @hide
+ * Class constructor for config. None of these parameters can be changed later.
+ * @param variant index of variant used for effect engine. See
+ * {@link #VARIANT_FAVOR_FREQUENCY_RESOLUTION} and {@link #VARIANT_FAVOR_TIME_RESOLUTION}.
+ * @param frameDurationMs preferred frame duration in milliseconds (ms).
+ * @param channelCount Number of channels to be configured.
+ * @param preEqInUse true if PreEq stage will be used, false otherwise.
+ * @param preEqBandCount number of bands for PreEq stage.
+ * @param mbcInUse true if Mbc stage will be used, false otherwise.
+ * @param mbcBandCount number of bands for Mbc stage.
+ * @param postEqInUse true if PostEq stage will be used, false otherwise.
+ * @param postEqBandCount number of bands for PostEq stage.
+ * @param limiterInUse true if Limiter stage will be used, false otherwise.
+ * @param channel array of Channel objects to be used for this configuration.
+ */
+ public Config(int variant, float frameDurationMs, int channelCount,
+ boolean preEqInUse, int preEqBandCount,
+ boolean mbcInUse, int mbcBandCount,
+ boolean postEqInUse, int postEqBandCount,
+ boolean limiterInUse,
+ Channel[] channel) {
+ mVariant = variant;
+ mPreferredFrameDuration = frameDurationMs;
+ mChannelCount = channelCount;
+ mPreEqInUse = preEqInUse;
+ mPreEqBandCount = preEqBandCount;
+ mMbcInUse = mbcInUse;
+ mMbcBandCount = mbcBandCount;
+ mPostEqInUse = postEqInUse;
+ mPostEqBandCount = postEqBandCount;
+ mLimiterInUse = limiterInUse;
+
+ mChannel = new Channel[mChannelCount];
+ //check if channelconfig is null or has less channels than channel count.
+ //options: fill the missing with default options.
+ // or fail?
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ if (ch < channel.length) {
+ mChannel[ch] = new Channel(channel[ch]); //copy create
+ } else {
+ //create a new one from scratch? //fail?
+ }
+ }
+ }
+ //a version that will scale to necessary number of channels
+ /**
+ * @hide
+ * Class constructor for Configuration.
+ * @param channelCount limit configuration to this number of channels. if channelCount is
+ * greater than number of channels in cfg, the constructor will duplicate the last channel
+ * found as many times as necessary to create a Config with channelCount number of channels.
+ * If channelCount is less than channels in cfg, the extra channels in cfg will be ignored.
+ * @param cfg copy constructor paremter.
+ */
+ public Config(int channelCount, Config cfg) {
+ mVariant = cfg.mVariant;
+ mPreferredFrameDuration = cfg.mPreferredFrameDuration;
+ mChannelCount = cfg.mChannelCount;
+ mPreEqInUse = cfg.mPreEqInUse;
+ mPreEqBandCount = cfg.mPreEqBandCount;
+ mMbcInUse = cfg.mMbcInUse;
+ mMbcBandCount = cfg.mMbcBandCount;
+ mPostEqInUse = cfg.mPostEqInUse;
+ mPostEqBandCount = cfg.mPostEqBandCount;
+ mLimiterInUse = cfg.mLimiterInUse;
+
+ if (mChannelCount != cfg.mChannel.length) {
+ throw new IllegalArgumentException("configuration channel counts differ " +
+ mChannelCount + " !=" + cfg.mChannel.length);
+ }
+ if (channelCount < 1) {
+ throw new IllegalArgumentException("channel resizing less than 1 not allowed");
+ }
+
+ mChannel = new Channel[channelCount];
+ for (int ch = 0; ch < channelCount; ch++) {
+ if (ch < mChannelCount) {
+ mChannel[ch] = new Channel(cfg.mChannel[ch]);
+ } else {
+ //duplicate last
+ mChannel[ch] = new Channel(cfg.mChannel[mChannelCount-1]);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Class constructor for Config
+ * @param cfg Configuration object copy constructor
+ */
+ public Config(Config cfg) {
+ this(cfg.mChannelCount, cfg);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("Variant: %d\n", mVariant));
+ sb.append(String.format("PreferredFrameDuration: %f\n", mPreferredFrameDuration));
+ sb.append(String.format("ChannelCount: %d\n", mChannelCount));
+ sb.append(String.format("PreEq inUse: %b, bandCount:%d\n",mPreEqInUse,
+ mPreEqBandCount));
+ sb.append(String.format("Mbc inUse: %b, bandCount: %d\n",mMbcInUse, mMbcBandCount));
+ sb.append(String.format("PostEq inUse: %b, bandCount: %d\n", mPostEqInUse,
+ mPostEqBandCount));
+ sb.append(String.format("Limiter inUse: %b\n", mLimiterInUse));
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ sb.append(String.format("==Channel %d\n", ch));
+ sb.append(mChannel[ch].toString());
+ }
+ return sb.toString();
+ }
+ private void checkChannel(int channelIndex) {
+ if (channelIndex < 0 || channelIndex >= mChannel.length) {
+ throw new IllegalArgumentException("ChannelIndex out of bounds");
+ }
+ }
+
+ //getters and setters
+ /**
+ * Gets variant for effect engine See {@link #VARIANT_FAVOR_FREQUENCY_RESOLUTION} and
+ * {@link #VARIANT_FAVOR_TIME_RESOLUTION}.
+ * @return variant of effect engine
+ */
+ public int getVariant() {
+ return mVariant;
+ }
+ /**
+ * Gets preferred frame duration in milliseconds (ms).
+ * @return preferred frame duration in milliseconds (ms)
+ */
+ public float getPreferredFrameDuration() {
+ return mPreferredFrameDuration;
+ }
+ /**
+ * Gets if preEq stage is in use
+ * @return true if preEq stage is in use;
+ */
+ public boolean isPreEqInUse() {
+ return mPreEqInUse;
+ }
+ /**
+ * Gets number of bands configured for the PreEq stage.
+ * @return number of bands configured for the PreEq stage.
+ */
+ public int getPreEqBandCount() {
+ return mPreEqBandCount;
+ }
+ /**
+ * Gets if Mbc stage is in use
+ * @return true if Mbc stage is in use;
+ */
+ public boolean isMbcInUse() {
+ return mMbcInUse;
+ }
+ /**
+ * Gets number of bands configured for the Mbc stage.
+ * @return number of bands configured for the Mbc stage.
+ */
+ public int getMbcBandCount() {
+ return mMbcBandCount;
+ }
+ /**
+ * Gets if PostEq stage is in use
+ * @return true if PostEq stage is in use;
+ */
+ public boolean isPostEqInUse() {
+ return mPostEqInUse;
+ }
+ /**
+ * Gets number of bands configured for the PostEq stage.
+ * @return number of bands configured for the PostEq stage.
+ */
+ public int getPostEqBandCount() {
+ return mPostEqBandCount;
+ }
+ /**
+ * Gets if Limiter stage is in use
+ * @return true if Limiter stage is in use;
+ */
+ public boolean isLimiterInUse() {
+ return mLimiterInUse;
+ }
+
+ //channel
+ /**
+ * Gets the Channel configuration object by using the channel index
+ * @param channelIndex of desired Channel object
+ * @return Channel configuration object
+ */
+ public Channel getChannelByChannelIndex(int channelIndex) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex];
+ }
+
+ /**
+ * Sets the chosen Channel object in the selected channelIndex
+ * Note that all the stages should have the same number of bands than the existing Channel
+ * object.
+ * @param channelIndex index of channel to be replaced
+ * @param channel Channel configuration object to be set
+ */
+ public void setChannelTo(int channelIndex, Channel channel) {
+ checkChannel(channelIndex);
+ //check all things are compatible
+ if (mMbcBandCount != channel.getMbc().getBandCount()) {
+ throw new IllegalArgumentException("MbcBandCount changed from " +
+ mMbcBandCount + " to " + channel.getPreEq().getBandCount());
+ }
+ if (mPreEqBandCount != channel.getPreEq().getBandCount()) {
+ throw new IllegalArgumentException("PreEqBandCount changed from " +
+ mPreEqBandCount + " to " + channel.getPreEq().getBandCount());
+ }
+ if (mPostEqBandCount != channel.getPostEq().getBandCount()) {
+ throw new IllegalArgumentException("PostEqBandCount changed from " +
+ mPostEqBandCount + " to " + channel.getPostEq().getBandCount());
+ }
+ mChannel[channelIndex] = new Channel(channel);
+ }
+
+ /**
+ * Sets ALL channels to the chosen Channel object. Note that all the stages should have the
+ * same number of bands than the existing ones.
+ * @param channel Channel configuration object to be set.
+ */
+ public void setAllChannelsTo(Channel channel) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ setChannelTo(ch, channel);
+ }
+ }
+
+ //===channel params
+ /**
+ * Gets inputGain value in decibels (dB) for channel indicated by channelIndex
+ * @param channelIndex index of channel of interest
+ * @return inputGain value in decibels (dB). 0 dB means no change.
+ */
+ public float getInputGainByChannelIndex(int channelIndex) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getInputGain();
+ }
+ /**
+ * Sets the inputGain value in decibels (dB) for the channel indicated by channelIndex.
+ * @param channelIndex index of channel of interest
+ * @param inputGain desired value in decibels (dB).
+ */
+ public void setInputGainByChannelIndex(int channelIndex, float inputGain) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setInputGain(inputGain);
+ }
+ /**
+ * Sets the inputGain value in decibels (dB) for ALL channels
+ * @param inputGain desired value in decibels (dB)
+ */
+ public void setInputGainAllChannelsTo(float inputGain) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setInputGain(inputGain);
+ }
+ }
+
+ //=== PreEQ
+ /**
+ * Gets PreEq stage from channel indicated by channelIndex
+ * @param channelIndex index of channel of interest
+ * @return PreEq stage configuration object
+ */
+ public Eq getPreEqByChannelIndex(int channelIndex) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getPreEq();
+ }
+ /**
+ * Sets the PreEq stage configuration for the channel indicated by channelIndex. Note that
+ * new preEq stage must have the same number of bands than original preEq stage
+ * @param channelIndex index of channel to be set
+ * @param preEq desired PreEq configuration to be set
+ */
+ public void setPreEqByChannelIndex(int channelIndex, Eq preEq) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setPreEq(preEq);
+ }
+ /**
+ * Sets the PreEq stage configuration for ALL channels. Note that new preEq stage must have
+ * the same number of bands than original preEq stages.
+ * @param preEq desired PreEq configuration to be set
+ */
+ public void setPreEqAllChannelsTo(Eq preEq) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setPreEq(preEq);
+ }
+ }
+ public EqBand getPreEqBandByChannelIndex(int channelIndex, int band) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getPreEqBand(band);
+ }
+ public void setPreEqBandByChannelIndex(int channelIndex, int band, EqBand preEqBand) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setPreEqBand(band, preEqBand);
+ }
+ public void setPreEqBandAllChannelsTo(int band, EqBand preEqBand) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setPreEqBand(band, preEqBand);
+ }
+ }
+
+ //=== MBC
+ public Mbc getMbcByChannelIndex(int channelIndex) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getMbc();
+ }
+ public void setMbcByChannelIndex(int channelIndex, Mbc mbc) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setMbc(mbc);
+ }
+ public void setMbcAllChannelsTo(Mbc mbc) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setMbc(mbc);
+ }
+ }
+ public MbcBand getMbcBandByChannelIndex(int channelIndex, int band) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getMbcBand(band);
+ }
+ public void setMbcBandByChannelIndex(int channelIndex, int band, MbcBand mbcBand) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setMbcBand(band, mbcBand);
+ }
+ public void setMbcBandAllChannelsTo(int band, MbcBand mbcBand) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setMbcBand(band, mbcBand);
+ }
+ }
+
+ //=== PostEQ
+ public Eq getPostEqByChannelIndex(int channelIndex) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getPostEq();
+ }
+ public void setPostEqByChannelIndex(int channelIndex, Eq postEq) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setPostEq(postEq);
+ }
+ public void setPostEqAllChannelsTo(Eq postEq) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setPostEq(postEq);
+ }
+ }
+ public EqBand getPostEqBandByChannelIndex(int channelIndex, int band) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getPostEqBand(band);
+ }
+ public void setPostEqBandByChannelIndex(int channelIndex, int band, EqBand postEqBand) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setPostEqBand(band, postEqBand);
+ }
+ public void setPostEqBandAllChannelsTo(int band, EqBand postEqBand) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setPostEqBand(band, postEqBand);
+ }
+ }
+
+ //Limiter
+ public Limiter getLimiterByChannelIndex(int channelIndex) {
+ checkChannel(channelIndex);
+ return mChannel[channelIndex].getLimiter();
+ }
+ public void setLimiterByChannelIndex(int channelIndex, Limiter limiter) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setLimiter(limiter);
+ }
+ public void setLimiterAllChannelsTo(Limiter limiter) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setLimiter(limiter);
+ }
+ }
+
+ public final static class Builder {
+ private int mVariant;
+ private int mChannelCount;
+ private boolean mPreEqInUse;
+ private int mPreEqBandCount;
+ private boolean mMbcInUse;
+ private int mMbcBandCount;
+ private boolean mPostEqInUse;
+ private int mPostEqBandCount;
+ private boolean mLimiterInUse;
+ private float mPreferredFrameDuration = CONFIG_PREFERRED_FRAME_DURATION_MS;
+ private Channel[] mChannel;
+
+ public Builder(int variant, int channelCount,
+ boolean preEqInUse, int preEqBandCount,
+ boolean mbcInUse, int mbcBandCount,
+ boolean postEqInUse, int postEqBandCount,
+ boolean limiterInUse) {
+ mVariant = variant;
+ mChannelCount = channelCount;
+ mPreEqInUse = preEqInUse;
+ mPreEqBandCount = preEqBandCount;
+ mMbcInUse = mbcInUse;
+ mMbcBandCount = mbcBandCount;
+ mPostEqInUse = postEqInUse;
+ mPostEqBandCount = postEqBandCount;
+ mLimiterInUse = limiterInUse;
+ mChannel = new Channel[mChannelCount];
+ for (int ch = 0; ch < mChannelCount; ch++) {
+ this.mChannel[ch] = new Channel(CHANNEL_DEFAULT_INPUT_GAIN,
+ this.mPreEqInUse, this.mPreEqBandCount,
+ this.mMbcInUse, this.mMbcBandCount,
+ this.mPostEqInUse, this.mPostEqBandCount,
+ this.mLimiterInUse);
+ }
+ }
+
+ private void checkChannel(int channelIndex) {
+ if (channelIndex < 0 || channelIndex >= mChannel.length) {
+ throw new IllegalArgumentException("ChannelIndex out of bounds");
+ }
+ }
+
+ public Builder setPreferredFrameDuration(float frameDuration) {
+ if (frameDuration < 0) {
+ throw new IllegalArgumentException("Expected positive frameDuration");
+ }
+ mPreferredFrameDuration = frameDuration;
+ return this;
+ }
+
+ public Builder setInputGainByChannelIndex(int channelIndex, float inputGain) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setInputGain(inputGain);
+ return this;
+ }
+ public Builder setInputGainAllChannelsTo(float inputGain) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ mChannel[ch].setInputGain(inputGain);
+ }
+ return this;
+ }
+
+ public Builder setChannelTo(int channelIndex, Channel channel) {
+ checkChannel(channelIndex);
+ //check all things are compatible
+ if (mMbcBandCount != channel.getMbc().getBandCount()) {
+ throw new IllegalArgumentException("MbcBandCount changed from " +
+ mMbcBandCount + " to " + channel.getPreEq().getBandCount());
+ }
+ if (mPreEqBandCount != channel.getPreEq().getBandCount()) {
+ throw new IllegalArgumentException("PreEqBandCount changed from " +
+ mPreEqBandCount + " to " + channel.getPreEq().getBandCount());
+ }
+ if (mPostEqBandCount != channel.getPostEq().getBandCount()) {
+ throw new IllegalArgumentException("PostEqBandCount changed from " +
+ mPostEqBandCount + " to " + channel.getPostEq().getBandCount());
+ }
+ mChannel[channelIndex] = new Channel(channel);
+ return this;
+ }
+ public Builder setAllChannelsTo(Channel channel) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ setChannelTo(ch, channel);
+ }
+ return this;
+ }
+
+ public Builder setPreEqByChannelIndex(int channelIndex, Eq preEq) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setPreEq(preEq);
+ return this;
+ }
+ public Builder setPreEqAllChannelsTo(Eq preEq) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ setPreEqByChannelIndex(ch, preEq);
+ }
+ return this;
+ }
+
+ public Builder setMbcByChannelIndex(int channelIndex, Mbc mbc) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setMbc(mbc);
+ return this;
+ }
+ public Builder setMbcAllChannelsTo(Mbc mbc) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ setMbcByChannelIndex(ch, mbc);
+ }
+ return this;
+ }
+
+ public Builder setPostEqByChannelIndex(int channelIndex, Eq postEq) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setPostEq(postEq);
+ return this;
+ }
+ public Builder setPostEqAllChannelsTo(Eq postEq) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ setPostEqByChannelIndex(ch, postEq);
+ }
+ return this;
+ }
+
+ public Builder setLimiterByChannelIndex(int channelIndex, Limiter limiter) {
+ checkChannel(channelIndex);
+ mChannel[channelIndex].setLimiter(limiter);
+ return this;
+ }
+ public Builder setLimiterAllChannelsTo(Limiter limiter) {
+ for (int ch = 0; ch < mChannel.length; ch++) {
+ setLimiterByChannelIndex(ch, limiter);
+ }
+ return this;
+ }
+
+ public Config build() {
+ return new Config(mVariant, mPreferredFrameDuration, mChannelCount,
+ mPreEqInUse, mPreEqBandCount,
+ mMbcInUse, mMbcBandCount,
+ mPostEqInUse, mPostEqBandCount,
+ mLimiterInUse, mChannel);
+ }
+ }
+ }
+ //=== CHANNEL
+ public Channel getChannelByChannelIndex(int channelIndex) {
+ return mConfig.getChannelByChannelIndex(channelIndex);
+ }
+
+ public void setChannelTo(int channelIndex, Channel channel) {
+ mConfig.setChannelTo(channelIndex, channel);
+ }
+
+ public void setAllChannelsTo(Channel channel) {
+ mConfig.setAllChannelsTo(channel);
+ }
+
+ //=== channel params
+ public float getInputGainByChannelIndex(int channelIndex) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getInputGainByChannelIndex(channelIndex);
+ }
+ public void setInputGainbyChannel(int channelIndex, float inputGain) {
+ mConfig.setInputGainByChannelIndex(channelIndex, inputGain);
+ //TODO: communicate change to engine
+ }
+ public void setInputGainAllChannelsTo(float inputGain) {
+ mConfig.setInputGainAllChannelsTo(inputGain);
+ //TODO: communicate change to engine
+ }
+
+ //=== PreEQ
+ public Eq getPreEqByChannelIndex(int channelIndex) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getPreEqByChannelIndex(channelIndex);
+ }
+
+ public void setPreEqByChannelIndex(int channelIndex, Eq preEq) {
+ mConfig.setPreEqByChannelIndex(channelIndex, preEq);
+ //TODO: communicate change to engine
+ }
+
+ public void setPreEqAllChannelsTo(Eq preEq) {
+ mConfig.setPreEqAllChannelsTo(preEq);
+ //TODO: communicate change to engine
+ }
+
+ public EqBand getPreEqBandByChannelIndex(int channelIndex, int band) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getPreEqBandByChannelIndex(channelIndex, band);
+ }
+
+ public void setPreEqBandByChannelIndex(int channelIndex, int band, EqBand preEqBand) {
+ mConfig.setPreEqBandByChannelIndex(channelIndex, band, preEqBand);
+ //TODO: communicate change to engine
+ }
+
+ public void setPreEqBandAllChannelsTo(int band, EqBand preEqBand) {
+ mConfig.setPreEqBandAllChannelsTo(band, preEqBand);
+ //TODO: communicate change to engine
+ }
+
+ //=== MBC
+ public Mbc getMbcByChannelIndex(int channelIndex) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getMbcByChannelIndex(channelIndex);
+ }
+
+ public void setMbcByChannelIndex(int channelIndex, Mbc mbc) {
+ mConfig.setMbcByChannelIndex(channelIndex, mbc);
+ //TODO: communicate change to engine
+ }
+
+ public void setMbcAllChannelsTo(Mbc mbc) {
+ mConfig.setMbcAllChannelsTo(mbc);
+ //TODO: communicate change to engine
+ }
+
+ public MbcBand getMbcBandByChannelIndex(int channelIndex, int band) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getMbcBandByChannelIndex(channelIndex, band);
+ }
+
+ public void setMbcBandByChannelIndex(int channelIndex, int band, MbcBand mbcBand) {
+ mConfig.setMbcBandByChannelIndex(channelIndex, band, mbcBand);
+ //TODO: communicate change to engine
+ }
+
+ public void setMbcBandAllChannelsTo(int band, MbcBand mbcBand) {
+ mConfig.setMbcBandAllChannelsTo(band, mbcBand);
+ //TODO: communicate change to engine
+ }
+
+ //== PostEq
+ public Eq getPostEqByChannelIndex(int channelIndex) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getPostEqByChannelIndex(channelIndex);
+ }
+
+ public void setPostEqByChannelIndex(int channelIndex, Eq postEq) {
+ mConfig.setPostEqByChannelIndex(channelIndex, postEq);
+ //TODO: communicate change to engine
+ }
+
+ public void setPostEqAllChannelsTo(Eq postEq) {
+ mConfig.setPostEqAllChannelsTo(postEq);
+ //TODO: communicate change to engine
+ }
+
+ public EqBand getPostEqBandByChannelIndex(int channelIndex, int band) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getPostEqBandByChannelIndex(channelIndex, band);
+ }
+
+ public void setPostEqBandByChannelIndex(int channelIndex, int band, EqBand postEqBand) {
+ mConfig.setPostEqBandByChannelIndex(channelIndex, band, postEqBand);
+ //TODO: communicate change to engine
+ }
+
+ public void setPostEqBandAllChannelsTo(int band, EqBand postEqBand) {
+ mConfig.setPostEqBandAllChannelsTo(band, postEqBand);
+ //TODO: communicate change to engine
+ }
+
+ //==== Limiter
+ public Limiter getLimiterByChannelIndex(int channelIndex) {
+ //TODO: return info from engine instead of cached config
+ return mConfig.getLimiterByChannelIndex(channelIndex);
+ }
+
+ public void setLimiterByChannelIndex(int channelIndex, Limiter limiter) {
+ mConfig.setLimiterByChannelIndex(channelIndex, limiter);
+ //TODO: communicate change to engine
+ }
+
+ public void setLimiterAllChannelsTo(Limiter limiter) {
+ mConfig.setLimiterAllChannelsTo(limiter);
+ //TODO: communicate change to engine
+ }
+
+ /**
+ * Gets the number of channels in the effect engine
+ * @return number of channels currently in use by the effect engine
+ */
+ public int getChannelCount() {
+ return getOneInt(PARAM_GET_CHANNEL_COUNT);
+ }
+
+ private void setEngineArchitecture(int variant, boolean preEqInUse, int preEqBandCount,
+ boolean mbcInUse, int mbcBandCount, boolean postEqInUse, int postEqBandCount,
+ boolean limiterInUse) {
+ int[] values = { variant, (preEqInUse ? 1 : 0), preEqBandCount,
+ (mbcInUse ? 1 : 0), mbcBandCount, (postEqInUse ? 1 : 0), postEqBandCount,
+ (limiterInUse ? 1 : 0)};
+ //TODO: enable later setIntArray(PARAM_SET_ENGINE_ARCHITECTURE, values);
+ }
+
+ //****** convenience methods:
+ //
+ private int getOneInt(int paramGet) {
+ int[] param = new int[1];
+ int[] result = new int[1];
+
+ param[0] = paramGet;
+ checkStatus(getParameter(param, result));
+ return result[0];
+ }
+
+ private int getTwoInt(int paramGet, int paramA) {
+ int[] param = new int[2];
+ int[] result = new int[1];
+
+ param[0] = paramGet;
+ param[1] = paramA;
+ checkStatus(getParameter(param, result));
+ return result[0];
+ }
+
+ private int getThreeInt(int paramGet, int paramA, int paramB) {
+ //have to use bytearrays, with more than 2 parameters.
+ byte[] paramBytes = concatArrays(intToByteArray(paramGet),
+ intToByteArray(paramA),
+ intToByteArray(paramB));
+ byte[] resultBytes = new byte[4]; //single int
+
+ checkStatus(getParameter(paramBytes, resultBytes));
+
+ return byteArrayToInt(resultBytes);
+ }
+
+ private void setOneInt(int paramSet, int valueSet) {
+ int[] param = new int[1];
+ int[] value = new int[1];
+
+ param[0] = paramSet;
+ value[0] = valueSet;
+ checkStatus(setParameter(param, value));
+ }
+
+ private void setTwoInt(int paramSet, int paramA, int valueSet) {
+ int[] param = new int[2];
+ int[] value = new int[1];
+
+ param[0] = paramSet;
+ param[1] = paramA;
+ value[0] = valueSet;
+ checkStatus(setParameter(param, value));
+ }
+
+ private void setThreeInt(int paramSet, int paramA, int paramB, int valueSet) {
+ //have to use bytearrays, with more than 2 parameters.
+ byte[] paramBytes = concatArrays(intToByteArray(paramSet),
+ intToByteArray(paramA),
+ intToByteArray(paramB));
+ byte[] valueBytes = intToByteArray(valueSet);
+
+ checkStatus(setParameter(paramBytes, valueBytes));
+ }
+
+ private void setOneFloat(int paramSet, float valueSet) {
+ int[] param = new int[1];
+ byte[] value;
+
+ param[0] = paramSet;
+ value = floatToByteArray(valueSet);
+ checkStatus(setParameter(param, value));
+ }
+
+ private void setTwoFloat(int paramSet, int paramA, float valueSet) {
+ int[] param = new int[2];
+ byte[] value;
+
+ param[0] = paramSet;
+ param[1] = paramA;
+ value = floatToByteArray(valueSet);
+ checkStatus(setParameter(param, value));
+ }
+
+ private void setThreeFloat(int paramSet, int paramA, int paramB, float valueSet) {
+ //have to use bytearrays, with more than 2 parameters.
+ byte[] paramBytes = concatArrays(intToByteArray(paramSet),
+ intToByteArray(paramA),
+ intToByteArray(paramB));
+ byte[] valueBytes = floatToByteArray(valueSet);
+
+ checkStatus(setParameter(paramBytes, valueBytes));
+ }
+ private byte[] intArrayToByteArray(int[] values) {
+ int expectedBytes = values.length * 4;
+ ByteBuffer converter = ByteBuffer.allocate(expectedBytes);
+ converter.order(ByteOrder.nativeOrder());
+ for (int k = 0; k < values.length; k++) {
+ converter.putFloat(values[k]);
+ }
+ return converter.array();
+ }
+ private void setIntArray(int paramSet, int[] paramArray) {
+ //have to use bytearrays, with more than 2 parameters.
+ byte[] paramBytes = intToByteArray(paramSet);
+ byte[] valueBytes = intArrayToByteArray(paramArray);
+
+ checkStatus(setParameter(paramBytes, valueBytes));
+ }
+
+ private float getOneFloat(int paramGet) {
+ int[] param = new int[1];
+ byte[] result = new byte[4];
+
+ param[0] = paramGet;
+ checkStatus(getParameter(param, result));
+ return byteArrayToFloat(result);
+ }
+
+ private float getTwoFloat(int paramGet, int paramA) {
+ int[] param = new int[2];
+ byte[] result = new byte[4];
+
+ param[0] = paramGet;
+ param[1] = paramA;
+ checkStatus(getParameter(param, result));
+ return byteArrayToFloat(result);
+ }
+
+ private float getThreeFloat(int paramGet, int paramA, int paramB) {
+ //have to use bytearrays, with more than 2 parameters.
+ byte[] paramBytes = concatArrays(intToByteArray(paramGet),
+ intToByteArray(paramA),
+ intToByteArray(paramB));
+ byte[] resultBytes = new byte[4]; //single float
+
+ checkStatus(getParameter(paramBytes, resultBytes));
+
+ return byteArrayToFloat(resultBytes);
+ }
+
+ private float[] getOneFloatArray(int paramGet, int expectedSize) {
+ int[] param = new int[1];
+ byte[] result = new byte[4 * expectedSize];
+
+ param[0] = paramGet;
+ checkStatus(getParameter(param, result));
+ float[] returnArray = new float[expectedSize];
+ for (int k = 0; k < expectedSize; k++) {
+ returnArray[k] = byteArrayToFloat(result, 4 * k);
+ }
+ return returnArray;
+ }
+ /**
+ * @hide
+ * The OnParameterChangeListener interface defines a method called by the DynamicsProcessing
+ * when a parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * DynamicsProcessing engine.
+ * @param effect the DynamicsProcessing on which the interface is registered.
+ * @param param ID of the modified parameter. See {@link #PARAM_GENERIC_PARAM1} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(DynamicsProcessing effect, int param, int value);
+ }
+
+ /**
+ * helper method to update effect architecture parameters
+ */
+ private void updateEffectArchitecture() {
+ mChannelCount = getChannelCount();
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ // only notify when the parameter was successfully change
+ if (status != AudioEffect.SUCCESS) {
+ return;
+ }
+ OnParameterChangeListener l = null;
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ int v = Integer.MIN_VALUE;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 4) {
+ v = byteArrayToInt(value, 0);
+ }
+ if (p != -1 && v != Integer.MIN_VALUE) {
+ l.onParameterChange(DynamicsProcessing.this, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ mParamListener = listener;
+ }
+ }
+
+ /**
+ * @hide
+ * The Settings class regroups the DynamicsProcessing parameters. It is used in
+ * conjunction with the getProperties() and setProperties() methods to backup and restore
+ * all parameters in a single call.
+ */
+
+ public static class Settings {
+ public int channelCount;
+ public float[] inputGain;
+
+ public Settings() {
+ }
+
+ /**
+ * Settings class constructor from a key=value; pairs formatted string. The string is
+ * typically returned by Settings.toString() method.
+ * @throws IllegalArgumentException if the string is not correctly formatted.
+ */
+ public Settings(String settings) {
+ StringTokenizer st = new StringTokenizer(settings, "=;");
+ //int tokens = st.countTokens();
+ if (st.countTokens() != 3) {
+ throw new IllegalArgumentException("settings: " + settings);
+ }
+ String key = st.nextToken();
+ if (!key.equals("DynamicsProcessing")) {
+ throw new IllegalArgumentException(
+ "invalid settings for DynamicsProcessing: " + key);
+ }
+ try {
+ key = st.nextToken();
+ if (!key.equals("channelCount")) {
+ throw new IllegalArgumentException("invalid key name: " + key);
+ }
+ channelCount = Short.parseShort(st.nextToken());
+ if (channelCount > CHANNEL_COUNT_MAX) {
+ throw new IllegalArgumentException("too many channels Settings:" + settings);
+ }
+ if (st.countTokens() != channelCount*1) { //check expected parameters.
+ throw new IllegalArgumentException("settings: " + settings);
+ }
+ //check to see it is ok the size
+ inputGain = new float[channelCount];
+ for (int ch = 0; ch < channelCount; ch++) {
+ key = st.nextToken();
+ if (!key.equals(ch +"_inputGain")) {
+ throw new IllegalArgumentException("invalid key name: " + key);
+ }
+ inputGain[ch] = Float.parseFloat(st.nextToken());
+ }
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("invalid value for key: " + key);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String str = new String (
+ "DynamicsProcessing"+
+ ";channelCount="+Integer.toString(channelCount));
+ for (int ch = 0; ch < channelCount; ch++) {
+ str = str.concat(";"+ch+"_inputGain="+Float.toString(inputGain[ch]));
+ }
+ return str;
+ }
+ };
+
+
+ /**
+ * @hide
+ * Gets the DynamicsProcessing properties. This method is useful when a snapshot of current
+ * effect settings must be saved by the application.
+ * @return a DynamicsProcessing.Settings object containing all current parameters values
+ */
+ public DynamicsProcessing.Settings getProperties() {
+ Settings settings = new Settings();
+
+ //TODO: just for testing, we are calling the getters one by one, this is
+ // supposed to be done in a single (or few calls) and get all the parameters at once.
+
+ settings.channelCount = getChannelCount();
+
+ if (settings.channelCount > CHANNEL_COUNT_MAX) {
+ throw new IllegalArgumentException("too many channels Settings:" + settings);
+ }
+
+ { // get inputGainmB per channel
+ settings.inputGain = new float [settings.channelCount];
+ for (int ch = 0; ch < settings.channelCount; ch++) {
+//TODO:with config settings.inputGain[ch] = getInputGain(ch);
+ }
+ }
+ return settings;
+ }
+
+ /**
+ * @hide
+ * Sets the DynamicsProcessing properties. This method is useful when bass boost settings
+ * have to be applied from a previous backup.
+ * @param settings a DynamicsProcessing.Settings object containing the properties to apply
+ */
+ public void setProperties(DynamicsProcessing.Settings settings) {
+
+ if (settings.channelCount != settings.inputGain.length ||
+ settings.channelCount != mChannelCount) {
+ throw new IllegalArgumentException("settings invalid channel count: "
+ + settings.channelCount);
+ }
+
+ //TODO: for now calling multiple times.
+ for (int ch = 0; ch < mChannelCount; ch++) {
+//TODO: use config setInputGain(ch, settings.inputGain[ch]);
+ }
+ }
+}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index adeb834..39cdcf0 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -163,6 +163,19 @@
/** @hide */
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final AudioMix that = (AudioMix) o;
+ return (this.mRouteFlags == that.mRouteFlags)
+ && (this.mRule == that.mRule)
+ && (this.mMixType == that.mMixType)
+ && (this.mFormat == that.mFormat);
+ }
+
+ /** @hide */
+ @Override
public int hashCode() {
return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
}
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 5f12742..866b574 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -135,11 +135,31 @@
}
}
+ private static boolean areCriteriaEquivalent(ArrayList<AudioMixMatchCriterion> cr1,
+ ArrayList<AudioMixMatchCriterion> cr2) {
+ if (cr1 == null || cr2 == null) return false;
+ if (cr1 == cr2) return true;
+ if (cr1.size() != cr2.size()) return false;
+ //TODO iterate over rules to check they contain the same criterion
+ return (cr1.hashCode() == cr2.hashCode());
+ }
+
private final int mTargetMixType;
int getTargetMixType() { return mTargetMixType; }
private final ArrayList<AudioMixMatchCriterion> mCriteria;
ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; }
+ /** @hide */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final AudioMixingRule that = (AudioMixingRule) o;
+ return (this.mTargetMixType == that.mTargetMixType)
+ && (areCriteriaEquivalent(this.mCriteria, that.mCriteria));
+ }
+
@Override
public int hashCode() {
return Objects.hash(mTargetMixType, mCriteria);
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 343bbda..11107e2 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -42,6 +42,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.List;
/**
* @hide
@@ -256,6 +257,89 @@
}
}
+ /**
+ * @hide
+ * Update the current configuration of the set of audio mixes by adding new ones, while
+ * keeping the policy registered.
+ * This method can only be called on a registered policy.
+ * @param mixes the list of {@link AudioMix} to add
+ * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
+ * otherwise.
+ */
+ @SystemApi
+ public int attachMixes(@NonNull List<AudioMix> mixes) {
+ if (mixes == null) {
+ throw new IllegalArgumentException("Illegal null list of AudioMix");
+ }
+ synchronized (mLock) {
+ if (mStatus != POLICY_STATUS_REGISTERED) {
+ throw new IllegalStateException("Cannot alter unregistered AudioPolicy");
+ }
+ final ArrayList<AudioMix> zeMixes = new ArrayList<AudioMix>(mixes.size());
+ for (AudioMix mix : mixes) {
+ if (mix == null) {
+ throw new IllegalArgumentException("Illegal null AudioMix in attachMixes");
+ } else {
+ zeMixes.add(mix);
+ }
+ }
+ final AudioPolicyConfig cfg = new AudioPolicyConfig(zeMixes);
+ IAudioService service = getService();
+ try {
+ final int status = service.addMixForPolicy(cfg, this.cb());
+ if (status == AudioManager.SUCCESS) {
+ mConfig.add(zeMixes);
+ }
+ return status;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in attachMixes", e);
+ return AudioManager.ERROR;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Update the current configuration of the set of audio mixes by removing some, while
+ * keeping the policy registered.
+ * This method can only be called on a registered policy.
+ * @param mixes the list of {@link AudioMix} to remove
+ * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
+ * otherwise.
+ */
+ @SystemApi
+ public int detachMixes(@NonNull List<AudioMix> mixes) {
+ if (mixes == null) {
+ throw new IllegalArgumentException("Illegal null list of AudioMix");
+ }
+ synchronized (mLock) {
+ if (mStatus != POLICY_STATUS_REGISTERED) {
+ throw new IllegalStateException("Cannot alter unregistered AudioPolicy");
+ }
+ final ArrayList<AudioMix> zeMixes = new ArrayList<AudioMix>(mixes.size());
+ for (AudioMix mix : mixes) {
+ if (mix == null) {
+ throw new IllegalArgumentException("Illegal null AudioMix in detachMixes");
+ // TODO also check mix is currently contained in list of mixes
+ } else {
+ zeMixes.add(mix);
+ }
+ }
+ final AudioPolicyConfig cfg = new AudioPolicyConfig(zeMixes);
+ IAudioService service = getService();
+ try {
+ final int status = service.removeMixForPolicy(cfg, this.cb());
+ if (status == AudioManager.SUCCESS) {
+ mConfig.remove(zeMixes);
+ }
+ return status;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in detachMixes", e);
+ return AudioManager.ERROR;
+ }
+ }
+ }
+
public void setRegistration(String regId) {
synchronized (mLock) {
mRegistrationId = regId;
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index cafa5a8..f725cac 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -16,6 +16,7 @@
package android.media.audiopolicy;
+import android.annotation.NonNull;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioPatch;
@@ -24,6 +25,8 @@
import android.os.Parcelable;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.Objects;
@@ -35,11 +38,16 @@
private static final String TAG = "AudioPolicyConfig";
- protected ArrayList<AudioMix> mMixes;
+ protected final ArrayList<AudioMix> mMixes;
protected int mDuckingPolicy = AudioPolicy.FOCUS_POLICY_DUCKING_IN_APP;
private String mRegistrationId = null;
+ /** counter for the mixes that are / have been in the list of AudioMix
+ * e.g. register 4 mixes (counter is 3), remove 1 (counter is 3), add 1 (counter is 4)
+ */
+ private int mMixCounter = 0;
+
protected AudioPolicyConfig(AudioPolicyConfig conf) {
mMixes = conf.mMixes;
}
@@ -201,20 +209,39 @@
return;
}
mRegistrationId = regId == null ? "" : regId;
- int mixIndex = 0;
for (AudioMix mix : mMixes) {
- if (!mRegistrationId.isEmpty()) {
- if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
- AudioMix.ROUTE_FLAG_LOOP_BACK) {
- mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
- + mixIndex++);
- } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) ==
- AudioMix.ROUTE_FLAG_RENDER) {
- mix.setRegistration(mix.mDeviceAddress);
- }
- } else {
- mix.setRegistration("");
+ setMixRegistration(mix);
+ }
+ }
+
+ private void setMixRegistration(@NonNull final AudioMix mix) {
+ if (!mRegistrationId.isEmpty()) {
+ if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
+ AudioMix.ROUTE_FLAG_LOOP_BACK) {
+ mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
+ + mMixCounter);
+ } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) ==
+ AudioMix.ROUTE_FLAG_RENDER) {
+ mix.setRegistration(mix.mDeviceAddress);
}
+ } else {
+ mix.setRegistration("");
+ }
+ mMixCounter++;
+ }
+
+ @GuardedBy("mMixes")
+ protected void add(@NonNull ArrayList<AudioMix> mixes) {
+ for (AudioMix mix : mixes) {
+ setMixRegistration(mix);
+ mMixes.add(mix);
+ }
+ }
+
+ @GuardedBy("mMixes")
+ protected void remove(@NonNull ArrayList<AudioMix> mixes) {
+ for (AudioMix mix : mixes) {
+ mMixes.remove(mix);
}
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index e7fcc7f..d079b7a 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -343,7 +343,6 @@
* Called when a {@link MediaSession2} is created.
* @hide
*/
- // TODO(jaewan): System API
public boolean createSession2(@NonNull SessionToken2 token) {
if (token == null) {
return false;
@@ -356,10 +355,10 @@
return false;
}
- /** Called when a {@link MediaSession2} is destroyed.
+ /**
+ * Called when a {@link MediaSession2} is destroyed.
* @hide
*/
- // TODO(jaewan): System API
public void destroySession2(@NonNull SessionToken2 token) {
if (token == null) {
return;
@@ -381,9 +380,7 @@
* using the {@link NotificationListenerService} APIs.
*
* @return list of tokens
- * @hide
*/
- // TODO(jaewan): Unhide
public List<SessionToken2> getActiveSessionTokens() {
try {
List<Bundle> bundles = mService.getSessionTokens(
@@ -404,9 +401,7 @@
* using the {@link NotificationListenerService} APIs.
*
* @return list of tokens
- * @hide
*/
- // TODO(jaewan): Unhide
public List<SessionToken2> getSessionServiceTokens() {
try {
List<Bundle> bundles = mService.getSessionTokens(
@@ -429,9 +424,7 @@
* @return list of tokens
* @see #getActiveSessionTokens
* @see #getSessionServiceTokens
- * @hide
*/
- // TODO(jaewan): Unhide
public List<SessionToken2> getAllSessionTokens() {
try {
List<Bundle> bundles = mService.getSessionTokens(
@@ -452,9 +445,7 @@
*
* @param executor executor to run this command
* @param listener The listener to add.
- * @hide
*/
- // TODO(jaewan): Unhide
public void addOnSessionTokensChangedListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnSessionTokensChangedListener listener) {
addOnSessionTokensChangedListener(UserHandle.myUserId(), executor, listener);
@@ -501,9 +492,7 @@
* Stop receiving session token updates on the specified listener.
*
* @param listener The listener to remove.
- * @hide
*/
- // TODO(jaewan): Unhide
public void removeOnSessionTokensChangedListener(
@NonNull OnSessionTokensChangedListener listener) {
if (listener == null) {
@@ -660,9 +649,7 @@
/**
* Listens for changes to the {@link #getAllSessionTokens()}. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
- * @hide
*/
- // TODO(jaewan): Unhide
public interface OnSessionTokensChangedListener {
void onSessionTokensChanged(@NonNull List<SessionToken2> tokens);
}
diff --git a/media/java/android/media/update/MediaControlView2Provider.java b/media/java/android/media/update/MediaControlView2Provider.java
index ebde3fef..8e69653 100644
--- a/media/java/android/media/update/MediaControlView2Provider.java
+++ b/media/java/android/media/update/MediaControlView2Provider.java
@@ -16,10 +16,10 @@
package android.media.update;
-import android.annotation.SystemApi;
+import android.media.SessionToken2;
import android.media.session.MediaController;
import android.util.AttributeSet;
-import android.view.View;
+import android.widget.MediaControlView2;
/**
* Interface for connecting the public API to an updatable implementation.
@@ -34,11 +34,19 @@
*
* @hide
*/
-// TODO @SystemApi
+// TODO: @SystemApi
public interface MediaControlView2Provider extends ViewGroupProvider {
void initialize(AttributeSet attrs, int defStyleAttr, int defStyleRes);
+ void setMediaSessionToken_impl(SessionToken2 token);
+ void setOnFullScreenListener_impl(MediaControlView2.OnFullScreenListener l);
+ /**
+ * @hide TODO: remove
+ */
void setController_impl(MediaController controller);
+ /**
+ * @hide
+ */
void setButtonVisibility_impl(int button, int visibility);
void requestPlayButtonFocus_impl();
}
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index 8d9efd5..8d036be 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -16,7 +16,7 @@
package android.media.update;
-import android.annotation.SystemApi;
+import android.annotation.NonNull;
import android.app.PendingIntent;
import android.media.AudioAttributes;
import android.media.MediaController2.PlaybackInfo;
@@ -59,12 +59,18 @@
void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb);
List<MediaItem2> getPlaylist_impl();
- void removePlaylistItem_impl(MediaItem2 index);
void addPlaylistItem_impl(int index, MediaItem2 item);
+ void replacePlaylistItem_impl(int index, MediaItem2 item);
+ void removePlaylistItem_impl(MediaItem2 item);
PlaylistParams getPlaylistParams_impl();
void setPlaylistParams_impl(PlaylistParams params);
PlaybackState2 getPlaybackState_impl();
+ int getPlayerState_impl();
+ long getPosition_impl();
+ float getPlaybackSpeed_impl();
+ long getBufferedPosition_impl();
+ MediaItem2 getCurrentPlaylistItem_impl();
interface PlaybackInfoProvider {
int getPlaybackType_impl();
diff --git a/media/java/android/media/update/MediaItem2Provider.java b/media/java/android/media/update/MediaItem2Provider.java
index 2970f0e..b494f9e 100644
--- a/media/java/android/media/update/MediaItem2Provider.java
+++ b/media/java/android/media/update/MediaItem2Provider.java
@@ -17,13 +17,14 @@
package android.media.update;
import android.media.DataSourceDesc;
+import android.media.MediaItem2;
+import android.media.MediaItem2.Builder;
import android.media.MediaMetadata2;
import android.os.Bundle;
/**
* @hide
*/
-// TODO(jaewan): SystemApi
public interface MediaItem2Provider {
Bundle toBundle_impl();
String toString_impl();
@@ -34,4 +35,11 @@
MediaMetadata2 getMetadata_impl();
String getMediaId_impl();
DataSourceDesc getDataSourceDesc_impl();
+
+ interface BuilderProvider {
+ Builder setMediaId_impl(String mediaId);
+ Builder setMetadata_impl(MediaMetadata2 metadata);
+ Builder setDataSourceDesc_impl(DataSourceDesc dataSourceDesc);
+ MediaItem2 build_impl();
+ }
}
diff --git a/media/java/android/media/update/MediaLibraryService2Provider.java b/media/java/android/media/update/MediaLibraryService2Provider.java
index 7489f76..9a0d693 100644
--- a/media/java/android/media/update/MediaLibraryService2Provider.java
+++ b/media/java/android/media/update/MediaLibraryService2Provider.java
@@ -16,16 +16,12 @@
package android.media.update;
-import android.annotation.SystemApi;
-import android.media.MediaLibraryService2.MediaLibrarySession;
-import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
import android.media.MediaSession2.ControllerInfo;
import android.os.Bundle;
/**
* @hide
*/
-// TODO: @SystemApi
public interface MediaLibraryService2Provider extends MediaSessionService2Provider {
// Nothing new for now
diff --git a/media/java/android/media/update/MediaMetadata2Provider.java b/media/java/android/media/update/MediaMetadata2Provider.java
index b6e5c8a..22463e9 100644
--- a/media/java/android/media/update/MediaMetadata2Provider.java
+++ b/media/java/android/media/update/MediaMetadata2Provider.java
@@ -11,7 +11,6 @@
/**
* @hide
*/
-// TODO(jaewan): SystemApi
public interface MediaMetadata2Provider {
boolean containsKey_impl(String key);
CharSequence getText_impl(String key);
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index fc1f671..d0ec104 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -16,11 +16,13 @@
package android.media.update;
+import android.annotation.NonNull;
import android.app.PendingIntent;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
-import android.media.MediaPlayerInterface;
-import android.media.MediaPlayerInterface.EventCallback;
+import android.media.MediaPlayerBase;
+import android.media.MediaPlayerBase.PlayerEventCallback;
+import android.media.MediaPlaylistController;
import android.media.MediaSession2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
@@ -40,34 +42,36 @@
/**
* @hide
*/
-// TODO: @SystemApi
public interface MediaSession2Provider extends TransportControlProvider {
void close_impl();
- void setPlayer_impl(MediaPlayerInterface player);
- void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider);
- MediaPlayerInterface getPlayer_impl();
+ void setPlayer_impl(MediaPlayerBase player, MediaPlaylistController mplc,
+ VolumeProvider2 volumeProvider);
+ MediaPlayerBase getPlayer_impl();
SessionToken2 getToken_impl();
List<ControllerInfo> getConnectedControllers_impl();
void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
void setAudioFocusRequest_impl(int focusGain);
-
void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands);
- void notifyMetadataChanged_impl();
void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
ResultReceiver receiver);
void sendCustomCommand_impl(Command command, Bundle args);
void setPlaylist_impl(List<MediaItem2> playlist);
+ void addPlaylistItem_impl(int index, MediaItem2 item);
+ void removePlaylistItem_impl(MediaItem2 item);
+ void editPlaylistItem_impl(MediaItem2 item);
+ void replacePlaylistItem_impl(int index, MediaItem2 item);
List<MediaItem2> getPlaylist_impl();
+ MediaItem2 getCurrentPlaylistItem_impl();
void setPlaylistParams_impl(PlaylistParams params);
PlaylistParams getPlaylistParams_impl();
-
- void registerPlayerEventCallback_impl(Executor executor, EventCallback callback);
- void unregisterPlayerEventCallback_impl(EventCallback callback);
+ void notifyError_impl(int errorCode, Bundle extras);
+ void registerPlayerEventCallback_impl(Executor executor, PlayerEventCallback callback);
+ void unregisterPlayerEventCallback_impl(PlayerEventCallback callback);
interface CommandProvider {
int getCommandCode_impl();
String getCustomCommand_impl();
- Bundle getExtra_impl();
+ Bundle getExtras_impl();
Bundle toBundle_impl();
boolean equals_impl(Object ob);
@@ -87,7 +91,7 @@
Command getCommand_impl();
int getIconResId_impl();
String getDisplayName_impl();
- Bundle getExtra_impl();
+ Bundle getExtras_impl();
boolean isEnabled_impl();
interface BuilderProvider {
@@ -95,7 +99,7 @@
Builder setIconResId_impl(int resId);
Builder setDisplayName_impl(String displayName);
Builder setEnabled_impl(boolean enabled);
- Builder setExtra_impl(Bundle extra);
+ Builder setExtras_impl(Bundle extras);
CommandButton build_impl();
}
}
@@ -116,7 +120,8 @@
}
interface BuilderBaseProvider<T extends MediaSession2, C extends SessionCallback> {
- void setVolumeProvider_impl(VolumeProvider2 volumeProvider);
+ void setPlayer_impl(MediaPlayerBase player, MediaPlaylistController mplc,
+ VolumeProvider2 volumeProvider);
void setSessionActivity_impl(PendingIntent pi);
void setId_impl(String id);
void setSessionCallback_impl(Executor executor, C callback);
diff --git a/media/java/android/media/update/MediaSessionService2Provider.java b/media/java/android/media/update/MediaSessionService2Provider.java
index 42e7587..8697e70 100644
--- a/media/java/android/media/update/MediaSessionService2Provider.java
+++ b/media/java/android/media/update/MediaSessionService2Provider.java
@@ -16,7 +16,6 @@
package android.media.update;
-import android.annotation.SystemApi;
import android.app.Notification;
import android.content.Intent;
import android.media.MediaSession2;
@@ -29,7 +28,7 @@
*/
public interface MediaSessionService2Provider {
MediaSession2 getSession_impl();
- MediaNotification onUpdateNotification_impl(PlaybackState2 state);
+ MediaNotification onUpdateNotification_impl();
// Service
void onCreate_impl();
diff --git a/media/java/android/media/update/PlaybackState2Provider.java b/media/java/android/media/update/PlaybackState2Provider.java
index 93f769c..66b8fa5 100644
--- a/media/java/android/media/update/PlaybackState2Provider.java
+++ b/media/java/android/media/update/PlaybackState2Provider.java
@@ -21,7 +21,6 @@
/**
* @hide
*/
-// TODO(jaewan): @SystemApi
public interface PlaybackState2Provider {
String toString_impl();
diff --git a/media/java/android/media/update/Rating2Provider.java b/media/java/android/media/update/Rating2Provider.java
index 8966196..28ad273 100644
--- a/media/java/android/media/update/Rating2Provider.java
+++ b/media/java/android/media/update/Rating2Provider.java
@@ -22,7 +22,6 @@
/**
* @hide
*/
-// TODO(jaewan): @SystemApi
public interface Rating2Provider {
String toString_impl();
boolean equals_impl(Object obj);
@@ -34,4 +33,4 @@
boolean isThumbUp_impl();
float getStarRating_impl();
float getPercentRating_impl();
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 29a30343..843fa71 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -28,10 +28,8 @@
import android.media.MediaLibraryService2;
import android.media.MediaLibraryService2.LibraryRoot;
import android.media.MediaLibraryService2.MediaLibrarySession;
-import android.media.MediaLibraryService2.MediaLibrarySessionBuilder;
-import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
+import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import android.media.MediaMetadata2;
-import android.media.MediaPlayerInterface;
import android.media.MediaSession2;
import android.media.MediaSession2.CommandButton.Builder;
import android.media.MediaSession2.PlaylistParams;
@@ -44,7 +42,7 @@
import android.media.VolumeProvider2;
import android.media.update.MediaLibraryService2Provider.LibraryRootProvider;
import android.media.update.MediaSession2Provider.BuilderBaseProvider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider.BuilderProvider;
+import android.media.update.MediaSession2Provider.CommandButtonProvider;
import android.media.update.MediaSession2Provider.CommandGroupProvider;
import android.media.update.MediaSession2Provider.CommandProvider;
import android.media.update.MediaSession2Provider.ControllerInfoProvider;
@@ -86,9 +84,10 @@
PlaylistParams playlistParams, int repeatMode, int shuffleMode,
MediaMetadata2 playlistMetadata);
PlaylistParams fromBundle_PlaylistParams(Context context, Bundle bundle);
- BuilderProvider createMediaSession2CommandButtonBuilder(Context context, Builder builder);
+ CommandButtonProvider.BuilderProvider createMediaSession2CommandButtonBuilder(Context context,
+ MediaSession2.CommandButton.Builder instance);
BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
- Context context, MediaSession2.Builder instance, MediaPlayerInterface player);
+ Context context, MediaSession2.Builder instance);
MediaController2Provider createMediaController2(Context context, MediaController2 instance,
SessionToken2 token, Executor executor, ControllerCallback callback);
@@ -103,17 +102,17 @@
MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance);
BuilderBaseProvider<MediaLibrarySession, MediaLibrarySessionCallback>
createMediaLibraryService2Builder(
- Context context, MediaLibrarySessionBuilder instance, MediaPlayerInterface player,
+ MediaLibraryService2 service, MediaLibrarySession.Builder instance,
Executor callbackExecutor, MediaLibrarySessionCallback callback);
LibraryRootProvider createMediaLibraryService2LibraryRoot(Context context, LibraryRoot instance,
String rootId, Bundle extras);
SessionToken2Provider createSessionToken2(Context context, SessionToken2 instance,
String packageName, String serviceName, int uid);
- SessionToken2 SessionToken2_fromBundle(Context context, Bundle bundle);
+ SessionToken2 fromBundle_SessionToken2(Context context, Bundle bundle);
- MediaItem2Provider createMediaItem2(Context context, MediaItem2 mediaItem2,
- String mediaId, DataSourceDesc dsd, MediaMetadata2 metadata, int flags);
+ MediaItem2Provider.BuilderProvider createMediaItem2Builder(
+ Context context, MediaItem2.Builder instance, int flags);
MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle);
VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance,
@@ -121,9 +120,9 @@
MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle);
MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- Context context, MediaMetadata2.Builder builder);
+ Context context, MediaMetadata2.Builder instance);
MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- Context context, MediaMetadata2.Builder builder, MediaMetadata2 source);
+ Context context, MediaMetadata2.Builder instance, MediaMetadata2 source);
Rating2 newUnratedRating_Rating2(Context context, int ratingStyle);
Rating2 fromBundle_Rating2(Context context, Bundle bundle);
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
index 44f82b29..9af8ada 100644
--- a/media/java/android/media/update/TransportControlProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -16,6 +16,7 @@
package android.media.update;
+import android.media.MediaItem2;
import android.media.PlaybackState2;
/**
@@ -32,7 +33,7 @@
void fastForward_impl();
void rewind_impl();
void seekTo_impl(long pos);
- void setCurrentPlaylistItem_impl(int index);
+ void skipToPlaylistItem_impl(MediaItem2 item);
PlaybackState2 getPlaybackState_impl();
}
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 4333c96..11b3560 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -18,8 +18,11 @@
import android.annotation.SystemApi;
import android.media.AudioAttributes;
+import android.media.DataSourceDesc;
+import android.media.MediaItem2;
import android.media.MediaMetadata2;
-import android.media.MediaPlayerInterface;
+import android.media.MediaPlayerBase;
+import android.media.SessionToken2;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
import android.media.session.MediaSession;
@@ -53,7 +56,11 @@
void setMediaControlView2_impl(MediaControlView2 mediaControlView, long intervalMs);
void setMediaMetadata_impl(MediaMetadata2 metadata);
+ /**
+ * @hide TODO: remove
+ */
MediaController getMediaController_impl();
+ SessionToken2 getMediaSessionToken_impl();
MediaControlView2 getMediaControlView2_impl();
MediaMetadata2 getMediaMetadata_impl();
void setSubtitleEnabled_impl(boolean enable);
@@ -65,14 +72,32 @@
/**
* @hide
*/
- void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerInterface player);
+ void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerBase player);
+ /**
+ * @hide
+ */
// TODO: remove setRouteAttributes_impl with MediaSession.Callback once MediaSession2 is ready.
void setRouteAttributes_impl(List<String> routeCategories, MediaSession.Callback sessionPlayer);
+
+ /**
+ * @hide TODO: remove
+ */
void setVideoPath_impl(String path);
+ /**
+ * @hide TODO: remove
+ */
void setVideoUri_impl(Uri uri);
+ /**
+ * @hide TODO: remove
+ */
void setVideoUri_impl(Uri uri, Map<String, String> headers);
+ void setMediaItem_impl(MediaItem2 mediaItem);
+ void setDataSource_impl(DataSourceDesc dsd);
void setViewType_impl(int viewType);
int getViewType_impl();
+ /**
+ * @hide TODO: remove
+ */
void setCustomActions_impl(List<PlaybackState.CustomAction> actionList,
Executor executor, VideoView2.OnCustomActionListener listener);
/**
@@ -80,5 +105,8 @@
*/
@VisibleForTesting
void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l);
+ /**
+ * @hide TODO: remove
+ */
void setFullScreenRequestListener_impl(VideoView2.OnFullScreenRequestListener l);
}
diff --git a/media/java/android/media/update/VolumeProvider2Provider.java b/media/java/android/media/update/VolumeProvider2Provider.java
index 5657af6..5b5cfd3 100644
--- a/media/java/android/media/update/VolumeProvider2Provider.java
+++ b/media/java/android/media/update/VolumeProvider2Provider.java
@@ -18,7 +18,6 @@
/**
* @hide
*/
-// TODO(jaewan): @SystemApi
public interface VolumeProvider2Provider {
int getControlType_impl();
int getMaxVolume_impl();
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 3c8af8a..44e5d61 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -31,6 +31,7 @@
shared_libs: [
"libandroid_runtime",
"libnativehelper",
+ "libnativewindow",
"libutils",
"libbinder",
"libmedia",
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 885bf03..f5311764 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -33,11 +33,14 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <grallocusage/GrallocUsageConversion.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <stdint.h>
#include <inttypes.h>
+#include <android/hardware_buffer_jni.h>
#define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext"
#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mNativeBuffer"
@@ -797,6 +800,14 @@
}
}
+static jobject Image_getHardwareBuffer(JNIEnv* env, jobject thiz) {
+ BufferItem* buffer = Image_getBufferItem(env, thiz);
+ AHardwareBuffer* b = AHardwareBuffer_from_GraphicBuffer(buffer->mGraphicBuffer.get());
+ // don't user the public AHardwareBuffer_toHardwareBuffer() because this would force us
+ // to link against libandroid.so
+ return android_hardware_HardwareBuffer_createFromAHardwareBuffer(env, b);
+}
+
} // extern "C"
// ----------------------------------------------------------------------------
@@ -814,10 +825,12 @@
static const JNINativeMethod gImageMethods[] = {
{"nativeCreatePlanes", "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
- (void*)Image_createSurfacePlanes },
- {"nativeGetWidth", "()I", (void*)Image_getWidth },
- {"nativeGetHeight", "()I", (void*)Image_getHeight },
- {"nativeGetFormat", "(I)I", (void*)Image_getFormat },
+ (void*)Image_createSurfacePlanes },
+ {"nativeGetWidth", "()I", (void*)Image_getWidth },
+ {"nativeGetHeight", "()I", (void*)Image_getHeight },
+ {"nativeGetFormat", "(I)I", (void*)Image_getFormat },
+ {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;",
+ (void*)Image_getHardwareBuffer },
};
int register_android_media_ImageReader(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 022198b..a1022c0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -36,7 +36,6 @@
#include <gui/Surface.h>
-#include <media/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -46,6 +45,7 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/PersistentSurface.h>
+#include <mediadrm/ICrypto.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/window.h>
@@ -1011,7 +1011,7 @@
sp<IDescrambler> descrambler;
if (descramblerBinderObj != NULL) {
- descrambler = JDescrambler::GetDescrambler(env, descramblerBinderObj);
+ descrambler = GetDescrambler(env, descramblerBinderObj);
}
err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index 1b3c24f..2d9051f 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -26,9 +26,9 @@
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
-#include <media/ICrypto.h>
-#include <media/IMediaDrmService.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IMediaDrmService.h>
namespace android {
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index add47463..aa79ce0 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -25,18 +25,64 @@
#include <android/hardware/cas/native/1.0/BpHwDescrambler.h>
#include <android/hardware/cas/native/1.0/BnHwDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <binder/MemoryDealer.h>
#include <hidl/HidlSupport.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/cas/DescramblerAPI.h>
#include <nativehelper/ScopedLocalRef.h>
namespace android {
+class IMemory;
+class MemoryDealer;
+namespace hardware {
+class HidlMemory;
+};
using hardware::fromHeap;
+using hardware::HidlMemory;
+using hardware::hidl_string;
+using hardware::hidl_vec;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
+
+struct JDescrambler : public RefBase {
+ JDescrambler(JNIEnv *env, jobject descramberBinderObj);
+
+ status_t descramble(
+ uint32_t key,
+ ssize_t totalLength,
+ const hidl_vec<SubSample>& subSamples,
+ const void *srcPtr,
+ jint srcOffset,
+ void *dstPtr,
+ jint dstOffset,
+ Status *status,
+ uint32_t *bytesWritten,
+ hidl_string *detailedError);
+
+
+protected:
+ virtual ~JDescrambler();
+
+private:
+ sp<IDescrambler> mDescrambler;
+ sp<IMemory> mMem;
+ sp<MemoryDealer> mDealer;
+ sp<HidlMemory> mHidlMemory;
+ SharedBuffer mDescramblerSrcBuffer;
+
+ Mutex mSharedMemLock;
+
+ bool ensureBufferCapacity(size_t neededSize);
+
+ DISALLOW_EVIL_CONSTRUCTORS(JDescrambler);
+};
struct fields_t {
jfieldID context;
+ jbyte flagPesHeader;
};
static fields_t gFields;
@@ -111,8 +157,7 @@
mDealer.clear();
}
-// static
-sp<IDescrambler> JDescrambler::GetDescrambler(JNIEnv *env, jobject obj) {
+sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj) {
if (obj != NULL) {
sp<hardware::IBinder> hwBinder =
JHwRemoteBinder::GetNativeContext(env, obj)->getBinder();
@@ -155,7 +200,7 @@
}
status_t JDescrambler::descramble(
- jbyte key,
+ uint32_t key,
ssize_t totalLength,
const hidl_vec<SubSample>& subSamples,
const void *srcPtr,
@@ -228,6 +273,12 @@
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
CHECK(gFields.context != NULL);
+
+ jfieldID fieldPesHeader = env->GetStaticFieldID(
+ clazz.get(), "SCRAMBLE_FLAG_PES_HEADER", "B");
+ CHECK(fieldPesHeader != NULL);
+
+ gFields.flagPesHeader = env->GetStaticByteField(clazz.get(), fieldPesHeader);
}
static void android_media_MediaDescrambler_native_setup(
@@ -323,7 +374,7 @@
}
static jint android_media_MediaDescrambler_native_descramble(
- JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
+ JNIEnv *env, jobject thiz, jbyte key, jbyte flags, jint numSubSamples,
jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
jobject srcBuf, jint srcOffset, jint srcLimit,
jobject dstBuf, jint dstOffset, jint dstLimit) {
@@ -364,12 +415,18 @@
return -1;
}
+ uint32_t scramblingControl = (uint32_t)key;
+
+ if (flags & gFields.flagPesHeader) {
+ scramblingControl |= DescramblerPlugin::kScrambling_Flag_PesHeader;
+ }
+
Status status;
uint32_t bytesWritten;
hidl_string detailedError;
err = descrambler->descramble(
- key, totalLength, subSamples,
+ scramblingControl, totalLength, subSamples,
srcPtr, srcOffset, dstPtr, dstOffset,
&status, &bytesWritten, &detailedError);
@@ -401,7 +458,7 @@
(void *)android_media_MediaDescrambler_native_init },
{ "native_setup", "(Landroid/os/IHwBinder;)V",
(void *)android_media_MediaDescrambler_native_setup },
- { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
+ { "native_descramble", "(BBI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
(void *)android_media_MediaDescrambler_native_descramble },
};
diff --git a/media/jni/android_media_MediaDescrambler.h b/media/jni/android_media_MediaDescrambler.h
index 2354dc2..0ae4187 100644
--- a/media/jni/android_media_MediaDescrambler.h
+++ b/media/jni/android_media_MediaDescrambler.h
@@ -19,57 +19,19 @@
#include "jni.h"
-#include <android/hardware/cas/native/1.0/IDescrambler.h>
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Mutex.h>
+#include <utils/RefBase.h>
namespace android {
-class IMemory;
-class MemoryDealer;
namespace hardware {
-class HidlMemory;
-};
-using hardware::HidlMemory;
-using hardware::hidl_string;
-using hardware::hidl_vec;
-using namespace hardware::cas::V1_0;
-using namespace hardware::cas::native::V1_0;
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
-struct JDescrambler : public RefBase {
- JDescrambler(JNIEnv *env, jobject descramberBinderObj);
-
- status_t descramble(
- jbyte key,
- ssize_t totalLength,
- const hidl_vec<SubSample>& subSamples,
- const void *srcPtr,
- jint srcOffset,
- void *dstPtr,
- jint dstOffset,
- Status *status,
- uint32_t *bytesWritten,
- hidl_string *detailedError);
-
- static sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj);
-
-protected:
- virtual ~JDescrambler();
-
-private:
- sp<IDescrambler> mDescrambler;
- sp<IMemory> mMem;
- sp<MemoryDealer> mDealer;
- sp<HidlMemory> mHidlMemory;
- SharedBuffer mDescramblerSrcBuffer;
-
- Mutex mSharedMemLock;
-
- bool ensureBufferCapacity(size_t neededSize);
-
- DISALLOW_EVIL_CONSTRUCTORS(JDescrambler);
-};
+sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj);
} // namespace android
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 3518392..4c20f05 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -31,10 +31,10 @@
#include <binder/Parcel.h>
#include <binder/PersistableBundle.h>
#include <cutils/properties.h>
-#include <media/IDrm.h>
-#include <media/IMediaDrmService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IMediaDrmService.h>
using ::android::os::PersistableBundle;
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 2258c78..b0936fb 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -471,7 +471,7 @@
// This will fail if the media player has not been initialized yet. This
// can be the case if setDisplay() on MediaPlayer2Impl.java has been called
// before setDataSource(). The redundant call to setVideoSurfaceTexture()
- // in prepare/prepareAsync covers for this case.
+ // in prepare/prepare covers for this case.
mp->setVideoSurfaceTexture(new ANativeWindowWrapper(anw));
}
@@ -536,7 +536,7 @@
}
static void
-android_media_MediaPlayer2_prepareAsync(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer2_prepare(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -1480,7 +1480,7 @@
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface},
{"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
{"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
- {"prepareAsync", "()V", (void *)android_media_MediaPlayer2_prepareAsync},
+ {"prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"_stop", "()V", (void *)android_media_MediaPlayer2_stop},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer2_getVideoWidth},
diff --git a/media/lib/remotedisplay/Android.mk b/media/lib/remotedisplay/Android.mk
index e88c0f1..63f9f91 100644
--- a/media/lib/remotedisplay/Android.mk
+++ b/media/lib/remotedisplay/Android.mk
@@ -42,3 +42,24 @@
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.media.remotedisplay.stubs-gen
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
+LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.media.remotedisplay.stubs_intermediates/src
+LOCAL_DROIDDOC_OPTIONS:= \
+ -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
+ -stubpackages com.android.media.remotedisplay \
+ -nodocs
+LOCAL_UNINSTALLABLE_MODULE := true
+include $(BUILD_DROIDDOC)
+com_android_media_remotedisplay_gen_stamp := $(full_target)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.media.remotedisplay.stubs
+LOCAL_SDK_VERSION := current
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_media_remotedisplay_gen_stamp)
+com_android_media_remotedisplay_gen_stamp :=
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/media/lib/remotedisplay/README.txt b/media/lib/remotedisplay/README.txt
index 5738dbe..1a52c4d 100644
--- a/media/lib/remotedisplay/README.txt
+++ b/media/lib/remotedisplay/README.txt
@@ -1,8 +1,17 @@
-This library (com.android.media.remotedisplay.jar) is a shared java library
+There are two libraries defined in this directory:
+First, com.android.media.remotedisplay.jar is a shared java library
containing classes required by unbundled remote display providers.
+Second, com.android.media.remotedisplay.stubs.jar is a stub for the shared
+library which provides build-time APIs to the unbundled clients.
+
+At runtime, the shared library is added to the classloader of the app via the
+<uses-library> tag. And since Java always tries to load a class from the
+parent classloader, regardless of whether the stub library is linked to the
+app statically or dynamically, the real classes are loaded from the shared
+library.
--- Rules of this library ---
-o This library is effectively a PUBLIC API for unbundled remote display providers
+o The stub library is effectively a PUBLIC API for unbundled remote display providers
that may be distributed outside the system image. So it MUST BE API STABLE.
You can add but not remove. The rules are the same as for the
public platform SDK API.
diff --git a/media/lib/signer/Android.mk b/media/lib/signer/Android.mk
index 69ca4d2..54aa968 100644
--- a/media/lib/signer/Android.mk
+++ b/media/lib/signer/Android.mk
@@ -42,3 +42,24 @@
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.mediadrm.signer.stubs-gen
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
+LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.mediadrm.signer.stubs_intermediates/src
+LOCAL_DROIDDOC_OPTIONS:= \
+ -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
+ -stubpackages com.android.mediadrm.signer \
+ -nodocs
+LOCAL_UNINSTALLABLE_MODULE := true
+include $(BUILD_DROIDDOC)
+com_android_mediadrm_signer_gen_stamp := $(full_target)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.mediadrm.signer.stubs
+LOCAL_SDK_VERSION := current
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_mediadrm_signer_gen_stamp)
+com_android_mediadrm_signer_gen_stamp :=
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/media/lib/signer/README.txt b/media/lib/signer/README.txt
index 362ab8e..55df3fc 100644
--- a/media/lib/signer/README.txt
+++ b/media/lib/signer/README.txt
@@ -1,10 +1,19 @@
-This library (com.android.mediadrm.signer.jar) is a shared java library
+There are two libraries defined in this directory:
+First, com.android.mediadrm.signer.jar is a shared java library
containing classes required by unbundled apps running on devices that use
the certficate provisioning and private key signing capabilities provided
by the MediaDrm API.
+Second, com.android.mediadrm.signer.stubs.jar is a stub for the shared library
+which provides build-time APIs to the unbundled clients.
+
+At runtime, the shared library is added to the classloader of the app via the
+<uses-library> tag. And since Java always tries to load a class from the
+parent classloader, regardless of whether the stub library is linked to the
+app statically or dynamically, the real classes are loaded from the shared
+library.
--- Rules of this library ---
-o This library is effectively a PUBLIC API for unbundled CAST receivers
+o The stub library is effectively a PUBLIC API for unbundled CAST receivers
that may be distributed outside the system image. So it MUST BE API STABLE.
You can add but not remove. The rules are the same as for the
public platform SDK API.
diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.mk b/media/mca/samples/CameraEffectsRecordingSample/Android.mk
index d3c4336..c81f2fc 100644
--- a/media/mca/samples/CameraEffectsRecordingSample/Android.mk
+++ b/media/mca/samples/CameraEffectsRecordingSample/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := CameraEffectsRecordingSample
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk
index 394f542..648af4e 100644
--- a/media/mca/tests/Android.mk
+++ b/media/mca/tests/Android.mk
@@ -11,6 +11,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CameraEffectsTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_INSTRUMENTATION_FOR := CameraEffectsRecordingSample
diff --git a/media/packages/BluetoothMidiService/Android.mk b/media/packages/BluetoothMidiService/Android.mk
index 0565925..6f262bf 100644
--- a/media/packages/BluetoothMidiService/Android.mk
+++ b/media/packages/BluetoothMidiService/Android.mk
@@ -7,6 +7,7 @@
$(call all-java-files-under,src)
LOCAL_PACKAGE_NAME := BluetoothMidiService
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk
index 25b4fe4..a066950 100644
--- a/media/tests/EffectsTest/Android.mk
+++ b/media/tests/EffectsTest/Android.mk
@@ -6,5 +6,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := EffectsTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 145cde6..fb473f0 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -13,5 +13,6 @@
android-ex-camera2
LOCAL_PACKAGE_NAME := mediaframeworktest
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk
index 616e600..6375ed3 100644
--- a/media/tests/MtpTests/Android.mk
+++ b/media/tests/MtpTests/Android.mk
@@ -8,5 +8,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_PACKAGE_NAME := MtpTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/media/tests/NativeMidiDemo/Android.mk b/media/tests/NativeMidiDemo/Android.mk
index 6b08f6b..316858f 100644
--- a/media/tests/NativeMidiDemo/Android.mk
+++ b/media/tests/NativeMidiDemo/Android.mk
@@ -19,6 +19,7 @@
LOCAL_PACKAGE_NAME := NativeMidiDemo
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_SRC_FILES := $(call all-java-files-under, java)
diff --git a/media/tests/ScoAudioTest/Android.mk b/media/tests/ScoAudioTest/Android.mk
index ab12865..2ad91a4 100644
--- a/media/tests/ScoAudioTest/Android.mk
+++ b/media/tests/ScoAudioTest/Android.mk
@@ -2,6 +2,7 @@
include $(CLEAR_VARS)
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/media/tests/SoundPoolTest/Android.mk b/media/tests/SoundPoolTest/Android.mk
index 7f947c0..9ca33c8 100644
--- a/media/tests/SoundPoolTest/Android.mk
+++ b/media/tests/SoundPoolTest/Android.mk
@@ -6,5 +6,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SoundPoolTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/native/android/storage_manager.cpp b/native/android/storage_manager.cpp
index 137b72c..bf15b8d 100644
--- a/native/android/storage_manager.cpp
+++ b/native/android/storage_manager.cpp
@@ -21,7 +21,7 @@
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
diff --git a/packages/BackupRestoreConfirmation/Android.mk b/packages/BackupRestoreConfirmation/Android.mk
index b84c07f..532d272 100644
--- a/packages/BackupRestoreConfirmation/Android.mk
+++ b/packages/BackupRestoreConfirmation/Android.mk
@@ -22,6 +22,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := BackupRestoreConfirmation
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/BackupRestoreConfirmation/res/values-bs/strings.xml b/packages/BackupRestoreConfirmation/res/values-bs/strings.xml
index e4852ed..bc52b06 100644
--- a/packages/BackupRestoreConfirmation/res/values-bs/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-bs/strings.xml
@@ -21,7 +21,7 @@
<string name="backup_confirm_text" msgid="1878021282758896593">"Zatraženo je pravljenje potpune rezervne kopije svih podataka na povezani računar. Da li želite da dozvolite to?\n\nPrekinite radnju ukoliko to niste sami zatražili."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Napravi sigurnosnu kopiju mojih podataka"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Nemoj napraviti rezervnu kopiju"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"Sa povezanog računara je upućen zahtjev za potpuno obnavljanje svih podataka. Želite li to dozvoliti?\n\nUkoliko niste uputili zahtjev za obnavljanje, prekinite radnju. Ovim će zamijeniti svi podaci koji su trenutno na uređaju!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Sa povezanog računara je upućen zahtjev za potpuno vraćanje svih podataka. Želite li to dozvoliti?\n\nUkoliko niste uputili zahtjev za vraćanje, prekinite radnju. Ovim će zamijeniti svi podaci koji su trenutno na uređaju!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Vrati moje podatke"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Ne vraćaj"</string>
<string name="current_password_text" msgid="8268189555578298067">"Ispod unesite svoju trenutnu lozinku za sigurnosnu kopiju:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-or/strings.xml b/packages/BackupRestoreConfirmation/res/values-or/strings.xml
index 1661824..77f3efb 100644
--- a/packages/BackupRestoreConfirmation/res/values-or/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-or/strings.xml
@@ -29,8 +29,7 @@
<string name="device_encryption_backup_text" msgid="5866590762672844664">"ଦୟାକରି, ତଳେ ନିଜର ଡିଭାଇସ୍ ଏନକ୍ରିପ୍ସନ୍ ପାସ୍ୱର୍ଡ ଦିଅନ୍ତୁ। ବ୍ୟାକଅପ୍ ଆର୍କାଇଭ୍ ଏନ୍କ୍ରିପ୍ଟ କରିବା ପାଇଁ ମଧ୍ୟ ଏହା ବ୍ୟବହୃତ ହେବ।"</string>
<string name="backup_enc_password_text" msgid="4981585714795233099">"ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍ ଡାଟାକୁ ଏନକ୍ରୀପ୍ଟ ବ୍ୟବହାର କରିବା ପାଇଁ ଏକ ପାସୱର୍ଡ ଦିଅନ୍ତୁ। ଯଦି ଏହାକୁ ଖାଲି ଛାଡ଼ି ଦିଆଯାଏ, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ପାସୱର୍ଡ ବ୍ୟବହାର କରାଯିବ।"</string>
<string name="backup_enc_password_optional" msgid="1350137345907579306">"ଯଦି ଆପଣ ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍କୁ ଏନ୍କ୍ରିପ୍ଟ କରିବାକୁ ଚାହାନ୍ତି, ତେବେ ତଳେ ଗୋଟିଏ ପାସ୍ୱର୍ଡ ଦିଅନ୍ତୁ:"</string>
- <!-- no translation found for backup_enc_password_required (7889652203371654149) -->
- <skip />
+ <string name="backup_enc_password_required" msgid="7889652203371654149">"ଆପଣଙ୍କ ଡିଭାଇସ୍କୁ ଏନକ୍ରିପ୍ଟ କରାଯାଇଥିବାରୁ ଆପଣଙ୍କୁ ନିଜ ବ୍ୟାକଅପକୁ ଏନକ୍ରିପ୍ଟ କରିବାକୁ ଦରକାର ପଡ଼ିବ। ଦୟାକରି ତଳେ ପାସ୍ୱର୍ଡ ଲେଖନ୍ତୁ:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"ଯଦି ରିଷ୍ଟୋର୍ ଡାଟା ଏନକ୍ରିପ୍ଟ ହୋଇଯାଇଥାଏ, ତେବେ ତଳେ ପାସ୍ୱର୍ଡ ଲେଖନ୍ତୁ:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"ବ୍ୟାକଅପ୍ ଆରମ୍ଭ କରୁଛି..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"ବ୍ୟାକଅପ୍ ସମାପ୍ତ ହେଲା"</string>
diff --git a/packages/CaptivePortalLogin/res/values-or/strings.xml b/packages/CaptivePortalLogin/res/values-or/strings.xml
new file mode 100644
index 0000000..b7c8321
--- /dev/null
+++ b/packages/CaptivePortalLogin/res/values-or/strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
+ <string name="action_use_network" msgid="6076184727448466030">"ଏହି ନେଟ୍ୱର୍କ ଯେପରି ଅଛି, ସେହିପରି ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="action_do_not_use_network" msgid="4577366536956516683">"ଏହି ନେଟ୍ୱର୍କକୁ ବ୍ୟବହାର କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="action_bar_label" msgid="917235635415966620">"ନେଟ୍ୱର୍କରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for action_bar_title (5645564790486983117) -->
+ <skip />
+ <string name="ssl_error_warning" msgid="6653188881418638872">"ଆପଣ ଯୋଗ ଦେବାକୁ ଚେଷ୍ଟା କରୁଥିବା ନେଟ୍ୱର୍କର ସୁରକ୍ଷା ସମସ୍ୟା ଅଛି।"</string>
+ <string name="ssl_error_example" msgid="647898534624078900">"ଉଦାହରଣସ୍ୱରୂପ, ଲଗଇନ୍ ପୃଷ୍ଠା ଦେଖାଯାଇଥିବା ସଂସ୍ଥାର ନହୋଇଥାଇପାରେ।"</string>
+ <string name="ssl_error_continue" msgid="6492718244923937110">"ବ୍ରାଉଜର୍ ଜରିଆରେ ଯେମିତିବି ହେଉ ଜାରି ରଖନ୍ତୁ"</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values-as/strings.xml b/packages/CarrierDefaultApp/res/values-as/strings.xml
new file mode 100644
index 0000000..61171bc
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values-as/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
+ <string name="android_system_label" msgid="2797790869522345065">"ম\'বাইল সেৱা প্ৰদান কৰা কোম্পানী"</string>
+ <string name="portal_notification_id" msgid="5155057562457079297">"ম\'বাইল ডেটা শেষ হৈছে"</string>
+ <string name="no_data_notification_id" msgid="668400731803969521">"আপোনাৰ ম\'বাইল ডেটা সেৱা নিষ্ক্ৰিয় কৰা হৈছে"</string>
+ <string name="portal_notification_detail" msgid="2295729385924660881">"%s ৱেবছাইটটোলৈ যাবলৈ টিপক"</string>
+ <string name="no_data_notification_detail" msgid="3112125343857014825">"অনুগ্ৰহ কৰি আপোনাৰ সেৱা প্ৰদানকাৰী %sৰ সৈতে যোগাযোগ কৰক"</string>
+ <!-- no translation found for no_mobile_data_connection_title (7449525772416200578) -->
+ <skip />
+ <!-- no translation found for no_mobile_data_connection (544980465184147010) -->
+ <skip />
+ <!-- no translation found for mobile_data_status_notification_channel_name (833999690121305708) -->
+ <skip />
+ <string name="action_bar_label" msgid="4290345990334377177">"ম\'বাইল নেটৱৰ্কত ছাইন ইন কৰক"</string>
+ <string name="ssl_error_warning" msgid="3127935140338254180">"আপুনি সংযোগ কৰিবলৈ বিচৰা নেটৱৰ্কটোত সুৰক্ষাজনিত সমস্যা আছে।"</string>
+ <string name="ssl_error_example" msgid="6188711843183058764">"উদাহৰণ স্বৰূপে, আপোনাক দেখুওৱা লগ ইনৰ পৃষ্ঠাটো প্ৰতিষ্ঠানটোৰ নিজা নহ\'বও পাৰে।"</string>
+ <string name="ssl_error_continue" msgid="1138548463994095584">"তথাপিও ব্ৰাউজাৰৰ জৰিয়তে অব্যাহত ৰাখক"</string>
+</resources>
diff --git a/packages/CompanionDeviceManager/Android.mk b/packages/CompanionDeviceManager/Android.mk
index f730356..7ec6e11 100644
--- a/packages/CompanionDeviceManager/Android.mk
+++ b/packages/CompanionDeviceManager/Android.mk
@@ -21,6 +21,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CompanionDeviceManager
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index 7e23ee1..16ef59f 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -41,7 +41,8 @@
private static final boolean DEBUG = false;
private static final String LOG_TAG = "DeviceChooserActivity";
- private ListView mDeviceListView;
+ View mLoadingIndicator = null;
+ ListView mDeviceListView;
private View mPairButton;
private View mCancelButton;
@@ -80,8 +81,9 @@
onSelectionUpdate();
}
});
- mDeviceListView.addFooterView(getProgressBar(), null, false);
+ mDeviceListView.addFooterView(mLoadingIndicator = getProgressBar(), null, false);
}
+ getService().mActivity = this;
mCancelButton = findViewById(R.id.button_cancel);
mCancelButton.setOnClickListener(v -> cancel());
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 1e26231..a5f0f24 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -22,6 +22,7 @@
import static com.android.internal.util.ArrayUtils.isEmpty;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
import static com.android.internal.util.CollectionUtils.size;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -50,6 +51,7 @@
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.wifi.WifiManager;
+import android.os.Handler;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -63,7 +65,9 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -73,6 +77,8 @@
private static final boolean DEBUG = false;
private static final String LOG_TAG = "DeviceDiscoveryService";
+ private static final long SCAN_TIMEOUT = 20000;
+
static DeviceDiscoveryService sInstance;
private BluetoothAdapter mBluetoothAdapter;
@@ -93,6 +99,8 @@
IFindDeviceCallback mFindCallback;
ICompanionDeviceDiscoveryServiceCallback mServiceCallback;
+ boolean mIsScanning = false;
+ @Nullable DeviceChooserActivity mActivity = null;
private final ICompanionDeviceDiscoveryService mBinder =
new ICompanionDeviceDiscoveryService.Stub() {
@@ -196,6 +204,10 @@
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
}
+ mIsScanning = true;
+ Handler.getMain().sendMessageDelayed(
+ obtainMessage(DeviceDiscoveryService::stopScan, this),
+ SCAN_TIMEOUT);
}
private boolean shouldScan(List<? extends DeviceFilter> mediumSpecificFilters) {
@@ -219,6 +231,15 @@
private void stopScan() {
if (DEBUG) Log.i(LOG_TAG, "stopScan()");
+ if (!mIsScanning) return;
+ mIsScanning = false;
+
+ DeviceChooserActivity activity = mActivity;
+ if (activity != null) {
+ activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator);
+ mActivity = null;
+ }
+
mBluetoothAdapter.cancelDiscovery();
if (mBluetoothBroadcastReceiver != null) {
unregisterReceiver(mBluetoothBroadcastReceiver);
diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk
index 0de2c1f..01c8768 100644
--- a/packages/DefaultContainerService/Android.mk
+++ b/packages/DefaultContainerService/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := DefaultContainerService
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JNI_SHARED_LIBRARIES := libdefcontainer_jni
diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk
index a825581..605a75d 100644
--- a/packages/EasterEgg/Android.mk
+++ b/packages/EasterEgg/Android.mk
@@ -21,6 +21,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := EasterEgg
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/packages/ExtServices/Android.mk b/packages/ExtServices/Android.mk
index d0c2b9f..467d7ed 100644
--- a/packages/ExtServices/Android.mk
+++ b/packages/ExtServices/Android.mk
@@ -21,6 +21,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ExtServices
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
diff --git a/packages/ExtServices/tests/Android.mk b/packages/ExtServices/tests/Android.mk
index 1eb5847..0a95b85 100644
--- a/packages/ExtServices/tests/Android.mk
+++ b/packages/ExtServices/tests/Android.mk
@@ -18,6 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ExtServicesUnitTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_INSTRUMENTATION_FOR := ExtServices
diff --git a/packages/ExtShared/Android.mk b/packages/ExtShared/Android.mk
index d8052df..7dbf79f 100644
--- a/packages/ExtShared/Android.mk
+++ b/packages/ExtShared/Android.mk
@@ -21,6 +21,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ExtShared
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index db825ff4..9e99313 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := ExternalStorageProvider
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/ExternalStorageProvider/res/values-as/strings.xml b/packages/ExternalStorageProvider/res/values-as/strings.xml
index 425c43a..278b84e 100644
--- a/packages/ExternalStorageProvider/res/values-as/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-as/strings.xml
@@ -17,8 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"বাহ্যিক সঞ্চয়াগাৰ"</string>
- <!-- no translation found for storage_description (8541974407321172792) -->
- <skip />
+ <string name="storage_description" msgid="8541974407321172792">"স্থানীয় সঞ্চয়াগাৰ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"আভ্যন্তৰীণ সঞ্চয়াগাৰ"</string>
<string name="root_documents" msgid="4051252304075469250">"নথিপত্রসমূহ"</string>
</resources>
diff --git a/packages/FakeOemFeatures/Android.mk b/packages/FakeOemFeatures/Android.mk
index d96bb3d..43de8e5 100644
--- a/packages/FakeOemFeatures/Android.mk
+++ b/packages/FakeOemFeatures/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := FakeOemFeatures
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/FusedLocation/Android.mk b/packages/FusedLocation/Android.mk
index 7406eaf4..d795870 100644
--- a/packages/FusedLocation/Android.mk
+++ b/packages/FusedLocation/Android.mk
@@ -22,6 +22,7 @@
LOCAL_JAVA_LIBRARIES := com.android.location.provider
LOCAL_PACKAGE_NAME := FusedLocation
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk
index e7190dc..6de1f1d 100644
--- a/packages/InputDevices/Android.mk
+++ b/packages/InputDevices/Android.mk
@@ -22,6 +22,7 @@
LOCAL_JAVA_LIBRARIES :=
LOCAL_PACKAGE_NAME := InputDevices
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index a9e9b2e..2d62a07 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -4,6 +4,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MtpDocumentsProvider
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := media
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk
index f0d4878..6504af1 100644
--- a/packages/MtpDocumentsProvider/perf_tests/Android.mk
+++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk
@@ -5,6 +5,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
LOCAL_CERTIFICATE := media
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
index ba346f4..11daac3 100644
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ b/packages/MtpDocumentsProvider/tests/Android.mk
@@ -6,6 +6,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
LOCAL_CERTIFICATE := media
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/packages/Osu/Android.mk b/packages/Osu/Android.mk
index 1d45aa9..63c7578 100644
--- a/packages/Osu/Android.mk
+++ b/packages/Osu/Android.mk
@@ -14,6 +14,7 @@
LOCAL_JAVA_LIBRARIES := telephony-common ims-common bouncycastle conscrypt
LOCAL_PACKAGE_NAME := Osu
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/Osu2/Android.mk b/packages/Osu2/Android.mk
index 05586f0..063ac7e 100644
--- a/packages/Osu2/Android.mk
+++ b/packages/Osu2/Android.mk
@@ -9,6 +9,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Osu2
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/Osu2/tests/Android.mk b/packages/Osu2/tests/Android.mk
index afc743d..23db7a9 100644
--- a/packages/Osu2/tests/Android.mk
+++ b/packages/Osu2/tests/Android.mk
@@ -25,6 +25,7 @@
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_PACKAGE_NAME := OsuTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_INSTRUMENTATION_FOR := Osu2
diff --git a/packages/PrintRecommendationService/Android.mk b/packages/PrintRecommendationService/Android.mk
index 66cb057..1220349 100644
--- a/packages/PrintRecommendationService/Android.mk
+++ b/packages/PrintRecommendationService/Android.mk
@@ -21,9 +21,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := PrintRecommendationService
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
-LOCAL_SDK_VERSION := system_current
-
include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index 6feb8a6..e356f38 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -26,6 +26,7 @@
src/com/android/printspooler/renderer/IPdfEditor.aidl
LOCAL_PACKAGE_NAME := PrintSpooler
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni
LOCAL_STATIC_ANDROID_LIBRARIES := \
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index e45c091..bfe4bfe 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -24,17 +24,13 @@
<string name="label_paper_size" msgid="908654383827777759">"କାଗଜର ଆକାର"</string>
<string name="label_paper_size_summary" msgid="5668204981332138168">"କାଗଜର ଆକାର:"</string>
<string name="label_color" msgid="1108690305218188969">"ରଙ୍ଗ"</string>
- <!-- no translation found for label_duplex (5370037254347072243) -->
- <skip />
+ <string name="label_duplex" msgid="5370037254347072243">"ଦୁଇ-ତରଫା"</string>
<string name="label_orientation" msgid="2853142581990496477">"ଓରିଏଣ୍ଟେଶନ୍"</string>
- <!-- no translation found for label_pages (7768589729282182230) -->
- <skip />
+ <string name="label_pages" msgid="7768589729282182230">"ପୃଷ୍ଠା"</string>
<!-- no translation found for destination_default_text (5422708056807065710) -->
<skip />
- <!-- no translation found for template_all_pages (3322235982020148762) -->
- <skip />
- <!-- no translation found for template_page_range (428638530038286328) -->
- <skip />
+ <string name="template_all_pages" msgid="3322235982020148762">"ସମସ୍ତ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+ <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ର ରେଞ୍ଜ"</string>
<string name="pages_range_example" msgid="8558694453556945172">"ଯେପରିକି 1—5,8,11—13"</string>
<string name="print_preview" msgid="8010217796057763343">"ପ୍ରିଣ୍ଟ ଝଲକ"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"ଝଲକ ଦେଖିବା ପାଇଁ PDF ଭ୍ୟୁଅର୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
@@ -45,21 +41,14 @@
<string name="print_dialog" msgid="32628687461331979">"ପ୍ରିଣ୍ଟ ଡାୟଲଗ୍"</string>
<!-- no translation found for current_page_template (5145005201131935302) -->
<skip />
- <!-- no translation found for page_description_template (6831239682256197161) -->
- <skip />
- <!-- no translation found for summary_template (8899734908625669193) -->
- <skip />
- <!-- no translation found for expand_handle (7282974448109280522) -->
- <skip />
- <!-- no translation found for collapse_handle (6886637989442507451) -->
- <skip />
+ <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g>ରୁ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> ପୃଷ୍ଠା"</string>
+ <string name="summary_template" msgid="8899734908625669193">"ସାରାଂଶ, କପୀ <xliff:g id="COPIES">%1$s</xliff:g>, କାଗଜ ଆକାର <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
+ <string name="expand_handle" msgid="7282974448109280522">"ହ୍ୟାଣ୍ଡେଲ୍ ବଡ଼ କରନ୍ତୁ"</string>
+ <string name="collapse_handle" msgid="6886637989442507451">"ହ୍ୟାଣ୍ଡେଲ୍ ଛୋଟ କରନ୍ତୁ"</string>
<string name="print_button" msgid="645164566271246268">"ପ୍ରିଣ୍ଟ କରନ୍ତୁ"</string>
- <!-- no translation found for savetopdf_button (2976186791686924743) -->
- <skip />
- <!-- no translation found for print_options_expanded (6944679157471691859) -->
- <skip />
- <!-- no translation found for print_options_collapsed (7455930445670414332) -->
- <skip />
+ <string name="savetopdf_button" msgid="2976186791686924743">"PDFରେ ସେଭ୍ କରନ୍ତୁ"</string>
+ <string name="print_options_expanded" msgid="6944679157471691859">"ପ୍ରିଣ୍ଟ ବିକଳ୍ପକୁ ବଡ଼ କରାଯାଇଛି"</string>
+ <string name="print_options_collapsed" msgid="7455930445670414332">"ପ୍ରିଣ୍ଟ ବିକଳ୍ପକୁ ଛୋଟ କରାଯାଇଛି"</string>
<string name="search" msgid="5421724265322228497">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
<string name="all_printers_label" msgid="3178848870161526399">"ସମସ୍ତ ପ୍ରିଣ୍ଟର୍"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"ସେବା ଯୋଡ଼ନ୍ତୁ"</string>
@@ -68,7 +57,10 @@
<string name="print_add_printer" msgid="1088656468360653455">"ପ୍ରିଣ୍ଟର୍ ଯୋଡ଼ନ୍ତୁ"</string>
<string name="print_select_printer" msgid="7388760939873368698">"ପ୍ରିଣ୍ଟର୍ ଚୟନ କରନ୍ତୁ"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"ପ୍ରିଣ୍ଟର୍ ଭୁଲିଯାଆନ୍ତୁ"</string>
- <!-- no translation found for print_search_result_count_utterance (6997663738361080868) -->
+ <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>ଟି ପ୍ରିଣ୍ଟର୍ ମିଳିଲା</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>ଟି ପ୍ରିଣ୍ଟର୍ ମିଳିଲା</item>
+ </plurals>
<!-- no translation found for printer_extended_description_template (1366699227703381874) -->
<skip />
<!-- no translation found for printer_info_desc (7181988788991581654) -->
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
index 149be74..161a600 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ b/packages/PrintSpooler/tests/outofprocess/Android.mk
@@ -20,10 +20,11 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib
LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index c78f454..a75b147 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -553,7 +553,7 @@
<string name="select_private_dns_configuration_title">Private DNS</string>
<string name="select_private_dns_configuration_dialog_title">Select Private DNS Mode</string>
<string name="private_dns_mode_off">Off</string>
- <string name="private_dns_mode_opportunistic">Opportunistic</string>
+ <string name="private_dns_mode_opportunistic">Automatic</string>
<string name="private_dns_mode_provider">Private DNS provider hostname</string>
<string name="private_dns_mode_provider_hostname_hint">Enter hostname of DNS provider</string>
@@ -876,47 +876,53 @@
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
- <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
- <string name="power_remaining_duration_only">About <xliff:g id="time">%1$s</xliff:g> left</string>
- <!-- [CHAR_LIMIT=60] Label for estimated remaining duration of battery discharging -->
- <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time">%1$s</xliff:g> left based on your usage</string>
- <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
- <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string>
+ <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
+ <string name="power_remaining_duration_only">About <xliff:g id="time">%1$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
+ <string name="power_discharging_duration">About <xliff:g id="time">%1$s</xliff:g> left (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <!-- [CHAR_LIMIT=60] Label for estimated remaining duration of battery discharging -->
+ <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time">%1$s</xliff:g> left based on your usage</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
+ <string name="power_discharging_duration_enhanced">About <xliff:g id="time">%1$s</xliff:g> left based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+ <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
- <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
- <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery -->
+ <string name="power_discharge_by_enhanced">Will last until about about <xliff:g id="time">%1$s</xliff:g> based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery with no percentage -->
+ <string name="power_discharge_by_only_enhanced">Will last until about about <xliff:g id="time">%1$s</xliff:g> based on your usage</string>
+ <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
+ <string name="power_discharge_by">Will last until about about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
+ <string name="power_discharge_by_only">Will last until about about <xliff:g id="time">%1$s</xliff:g></string>
- <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount -->
- <string name="power_remaining_less_than_duration_only">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining</string>
- <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount with the percentage -->
- <string name="power_remaining_less_than_duration"><xliff:g id="level">%1$s</xliff:g> - Less than <xliff:g id="threshold">%2$s</xliff:g> remaining</string>
+ <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount -->
+ <string name="power_remaining_less_than_duration_only">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining</string>
+ <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount with the percentage -->
+ <string name="power_remaining_less_than_duration">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining (<xliff:g id="level">%2$s</xliff:g>)</string>
- <!-- Used to let users know that they have more than some amount of battery life remaining with percentage. ex: 75% - more than 1 day remaining [CHAR LIMIT = 80] -->
- <string name="power_remaining_more_than_subtext"><xliff:g id="level">%1$s</xliff:g>more than <xliff:g id="time_remaining">%2$s</xliff:g> remaining</string>
- <!-- Used to let users know that they have more than some amount of battery life remaining. ex: more than 1 day remaining [CHAR LIMIT = 40] -->
- <string name="power_remaining_only_more_than_subtext">more than <xliff:g id="time_remaining">%1$s</xliff:g> remaining</string>
+ <!-- Used to let users know that they have more than some amount of battery life remaining with percentage. ex: 75% - more than 1 day remaining [CHAR LIMIT = 80] -->
+ <string name="power_remaining_more_than_subtext">More than <xliff:g id="time_remaining">%1$s</xliff:g> remaining (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <!-- Used to let users know that they have more than some amount of battery life remaining. ex: more than 1 day remaining [CHAR LIMIT = 40] -->
+ <string name="power_remaining_only_more_than_subtext">More than <xliff:g id="time_remaining">%1$s</xliff:g> remaining</string>
- <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
- <string name="power_remaining_duration_only_shutdown_imminent" product="default">phone may shutdown soon</string>
- <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet">tablet may shutdown soon</string>
- <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
- <string name="power_remaining_duration_only_shutdown_imminent" product="device">device may shutdown soon</string>
-
- <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
- <string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g> - about <xliff:g id="time">%2$s</xliff:g> left</string>
- <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
- <string name="power_discharging_duration_enhanced"><xliff:g id="level">%1$s</xliff:g> - about <xliff:g id="time">%2$s</xliff:g> left based on your usage</string>
-
- <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
- <string name="power_remaining_duration_shutdown_imminent" product="default"><xliff:g id="level">%1$s</xliff:g> - phone may shutdown soon</string>
- <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
- <string name="power_remaining_duration_shutdown_imminent" product="tablet"><xliff:g id="level">%1$s</xliff:g> - tablet may shutdown soon</string>
- <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
- <string name="power_remaining_duration_shutdown_imminent" product="device"><xliff:g id="level">%1$s</xliff:g> - device may shutdown soon</string>
+ <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+ <string name="power_remaining_duration_only_shutdown_imminent" product="default">Phone may shutdown soon</string>
+ <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+ <string name="power_remaining_duration_only_shutdown_imminent" product="tablet">Tablet may shutdown soon</string>
+ <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+ <string name="power_remaining_duration_only_shutdown_imminent" product="device">Device may shutdown soon</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+ <string name="power_remaining_duration_shutdown_imminent" product="default">Phone may shutdown soon (<xliff:g id="level">%1$s</xliff:g>)</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+ <string name="power_remaining_duration_shutdown_imminent" product="tablet">Tablet may shutdown soon (<xliff:g id="level">%1$s</xliff:g>)</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+ <string name="power_remaining_duration_shutdown_imminent" product="device">Device may shutdown soon (<xliff:g id="level">%1$s</xliff:g>)</string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
<string name="power_charging"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="state">%2$s</xliff:g></string>
+ <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
+ <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until fully charged</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 9947dec..61e113b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -142,7 +142,7 @@
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
- Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_badge);
+ Drawable drawable = UserIconDrawable.getManagedUserBadgeDrawable(context);
drawable.setBounds(0, 0, iconSize, iconSize);
return drawable;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index d14b53b..660521e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -37,7 +37,16 @@
* Updates the current status of preference (summary, switch state, etc)
*/
public void updateState(Preference preference) {
-
+ if (preference == null) {
+ return;
+ }
+ final CharSequence summary = getSummary();
+ if (summary == null) {
+ // Default getSummary returns null. If subclass didn't override this, there is nothing
+ // we need to do.
+ return;
+ }
+ preference.setSummary(summary);
}
/**
@@ -72,9 +81,9 @@
/**
- * @return a String for the summary of the preference.
+ * @return a {@link CharSequence} for the summary of the preference.
*/
- public String getSummary() {
+ public CharSequence getSummary() {
return null;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
index f68c04f..d3dc8aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
@@ -17,6 +17,8 @@
package com.android.settingslib.development;
import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -26,8 +28,9 @@
* All Preference Controllers that are a part of the developer options page should inherit this
* class.
*/
-public abstract class DeveloperOptionsPreferenceController extends
- AbstractPreferenceController {
+public abstract class DeveloperOptionsPreferenceController extends AbstractPreferenceController {
+
+ protected Preference mPreference;
public DeveloperOptionsPreferenceController(Context context) {
super(context);
@@ -43,6 +46,12 @@
return true;
}
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
/**
* Called when developer options is enabled
*/
@@ -65,12 +74,14 @@
* Called when developer options is enabled and the preference is available
*/
protected void onDeveloperOptionsSwitchEnabled() {
+ mPreference.setEnabled(true);
}
/**
* Called when developer options is disabled and the preference is available
*/
protected void onDeveloperOptionsSwitchDisabled() {
+ mPreference.setEnabled(false);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java b/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java
new file mode 100644
index 0000000..3d55c4f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.settingslib.utils;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArrayMap;
+
+
+/**
+ * Icon cache to avoid multiple loads on the same icon.
+ */
+public class IconCache {
+ private final Context mContext;
+ @VisibleForTesting
+ final ArrayMap<Icon, Drawable> mMap = new ArrayMap<>();
+
+ public IconCache(Context context) {
+ mContext = context;
+ }
+
+ public Drawable getIcon(Icon icon) {
+ if (icon == null) {
+ return null;
+ }
+ Drawable drawable = mMap.get(icon);
+ if (drawable == null) {
+ drawable = icon.loadDrawable(mContext);
+ updateIcon(icon, drawable);
+ }
+ return drawable;
+ }
+
+ public void updateIcon(Icon icon, Drawable drawable) {
+ mMap.put(icon, drawable);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
index 346ca66..8b3da39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -17,22 +17,30 @@
package com.android.settingslib.utils;
import android.content.Context;
+import android.icu.text.DateFormat;
import android.icu.text.MeasureFormat;
import android.icu.text.MeasureFormat.FormatWidth;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
import android.support.annotation.Nullable;
import android.text.TextUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
-import com.android.settingslib.utils.StringUtil;
+import java.time.Clock;
+import java.time.Instant;
+import java.util.Calendar;
+import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
/** Utility class for keeping power related strings consistent**/
public class PowerUtil {
+
private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7);
private static final long FIFTEEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(15);
private static final long ONE_DAY_MILLIS = TimeUnit.DAYS.toMillis(1);
+ private static final long TWO_DAYS_MILLIS = TimeUnit.DAYS.toMillis(2);
+ private static final long ONE_HOUR_MILLIS = TimeUnit.HOURS.toMillis(1);
/**
* This method produces the text used in various places throughout the system to describe the
@@ -57,11 +65,15 @@
FIFTEEN_MINUTES_MILLIS,
false /* withSeconds */);
return getUnderFifteenString(context, timeString, percentageString);
+ } else if (drainTimeMs >= TWO_DAYS_MILLIS) {
+ // just say more than two day if over 48 hours
+ return getMoreThanTwoDaysString(context, percentageString);
} else if (drainTimeMs >= ONE_DAY_MILLIS) {
- // just say more than one day if over 24 hours
- return getMoreThanOneDayString(context, percentageString);
+ // show remaining days & hours if more than a day
+ return getMoreThanOneDayString(context, drainTimeMs,
+ percentageString, basedOnUsage);
} else {
- // show a regular time remaining string
+ // show the time of day we think you'll run out
return getRegularTimeRemainingString(context, drainTimeMs,
percentageString, basedOnUsage);
}
@@ -83,34 +95,18 @@
? context.getString(R.string.power_remaining_less_than_duration_only, timeString)
: context.getString(
R.string.power_remaining_less_than_duration,
- percentageString,
- timeString);
+ timeString,
+ percentageString);
}
- private static String getMoreThanOneDayString(Context context, String percentageString) {
- final Locale currentLocale = context.getResources().getConfiguration().getLocales().get(0);
- final MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.SHORT);
-
- final Measure daysMeasure = new Measure(1, MeasureUnit.DAY);
-
- return TextUtils.isEmpty(percentageString)
- ? context.getString(R.string.power_remaining_only_more_than_subtext,
- frmt.formatMeasures(daysMeasure))
- : context.getString(
- R.string.power_remaining_more_than_subtext,
- percentageString,
- frmt.formatMeasures(daysMeasure));
- }
-
- private static String getRegularTimeRemainingString(Context context, long drainTimeMs,
+ private static String getMoreThanOneDayString(Context context, long drainTimeMs,
String percentageString, boolean basedOnUsage) {
- // round to the nearest 15 min to not appear oversly precise
- final long roundedTimeMs = roundToNearestThreshold(drainTimeMs,
- FIFTEEN_MINUTES_MILLIS);
+ final long roundedTimeMs = roundToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS);
CharSequence timeString = StringUtil.formatElapsedTime(context,
roundedTimeMs,
false /* withSeconds */);
+
if (TextUtils.isEmpty(percentageString)) {
int id = basedOnUsage
? R.string.power_remaining_duration_only_enhanced
@@ -120,7 +116,48 @@
int id = basedOnUsage
? R.string.power_discharging_duration_enhanced
: R.string.power_discharging_duration;
- return context.getString(id, percentageString, timeString);
+ return context.getString(id, timeString, percentageString);
+ }
+ }
+
+ private static String getMoreThanTwoDaysString(Context context, String percentageString) {
+ final Locale currentLocale = context.getResources().getConfiguration().getLocales().get(0);
+ final MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.SHORT);
+
+ final Measure daysMeasure = new Measure(2, MeasureUnit.DAY);
+
+ return TextUtils.isEmpty(percentageString)
+ ? context.getString(R.string.power_remaining_only_more_than_subtext,
+ frmt.formatMeasures(daysMeasure))
+ : context.getString(
+ R.string.power_remaining_more_than_subtext,
+ frmt.formatMeasures(daysMeasure),
+ percentageString);
+ }
+
+ private static String getRegularTimeRemainingString(Context context, long drainTimeMs,
+ String percentageString, boolean basedOnUsage) {
+ // Get the time of day we think device will die rounded to the nearest 15 min.
+ final long roundedTimeOfDayMs =
+ roundToNearestThreshold(
+ System.currentTimeMillis() + drainTimeMs,
+ FIFTEEN_MINUTES_MILLIS);
+
+ // convert the time to a properly formatted string.
+ DateFormat fmt = DateFormat.getTimeInstance(DateFormat.SHORT);
+ Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs));
+ CharSequence timeString = fmt.format(date);
+
+ if (TextUtils.isEmpty(percentageString)) {
+ int id = basedOnUsage
+ ? R.string.power_discharge_by_only_enhanced
+ : R.string.power_discharge_by_only;
+ return context.getString(id, timeString);
+ } else {
+ int id = basedOnUsage
+ ? R.string.power_discharge_by_enhanced
+ : R.string.power_discharge_by;
+ return context.getString(id, timeString, percentageString);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
index 45fdd78..68be2b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -33,74 +33,74 @@
/** Utility class for generally useful string methods **/
public class StringUtil {
- public static final int SECONDS_PER_MINUTE = 60;
- public static final int SECONDS_PER_HOUR = 60 * 60;
- public static final int SECONDS_PER_DAY = 24 * 60 * 60;
+ public static final int SECONDS_PER_MINUTE = 60;
+ public static final int SECONDS_PER_HOUR = 60 * 60;
+ public static final int SECONDS_PER_DAY = 24 * 60 * 60;
- /**
- * Returns elapsed time for the given millis, in the following format:
- * 2d 5h 40m 29s
- * @param context the application context
- * @param millis the elapsed time in milli seconds
- * @param withSeconds include seconds?
- * @return the formatted elapsed time
- */
- public static CharSequence formatElapsedTime(Context context, double millis,
- boolean withSeconds) {
- SpannableStringBuilder sb = new SpannableStringBuilder();
- int seconds = (int) Math.floor(millis / 1000);
- if (!withSeconds) {
- // Round up.
- seconds += 30;
- }
+ /**
+ * Returns elapsed time for the given millis, in the following format:
+ * 2d 5h 40m 29s
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
+ * @param withSeconds include seconds?
+ * @return the formatted elapsed time
+ */
+ public static CharSequence formatElapsedTime(Context context, double millis,
+ boolean withSeconds) {
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+ int seconds = (int) Math.floor(millis / 1000);
+ if (!withSeconds) {
+ // Round up.
+ seconds += 30;
+ }
- int days = 0, hours = 0, minutes = 0;
- if (seconds >= SECONDS_PER_DAY) {
- days = seconds / SECONDS_PER_DAY;
- seconds -= days * SECONDS_PER_DAY;
- }
- if (seconds >= SECONDS_PER_HOUR) {
- hours = seconds / SECONDS_PER_HOUR;
- seconds -= hours * SECONDS_PER_HOUR;
- }
- if (seconds >= SECONDS_PER_MINUTE) {
- minutes = seconds / SECONDS_PER_MINUTE;
- seconds -= minutes * SECONDS_PER_MINUTE;
- }
+ int days = 0, hours = 0, minutes = 0;
+ if (seconds >= SECONDS_PER_DAY) {
+ days = seconds / SECONDS_PER_DAY;
+ seconds -= days * SECONDS_PER_DAY;
+ }
+ if (seconds >= SECONDS_PER_HOUR) {
+ hours = seconds / SECONDS_PER_HOUR;
+ seconds -= hours * SECONDS_PER_HOUR;
+ }
+ if (seconds >= SECONDS_PER_MINUTE) {
+ minutes = seconds / SECONDS_PER_MINUTE;
+ seconds -= minutes * SECONDS_PER_MINUTE;
+ }
- final ArrayList<Measure> measureList = new ArrayList(4);
- if (days > 0) {
- measureList.add(new Measure(days, MeasureUnit.DAY));
- }
- if (hours > 0) {
- measureList.add(new Measure(hours, MeasureUnit.HOUR));
- }
- if (minutes > 0) {
- measureList.add(new Measure(minutes, MeasureUnit.MINUTE));
- }
- if (withSeconds && seconds > 0) {
- measureList.add(new Measure(seconds, MeasureUnit.SECOND));
- }
- if (measureList.size() == 0) {
- // Everything addable was zero, so nothing was added. We add a zero.
- measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE));
- }
- final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]);
+ final ArrayList<Measure> measureList = new ArrayList(4);
+ if (days > 0) {
+ measureList.add(new Measure(days, MeasureUnit.DAY));
+ }
+ if (hours > 0) {
+ measureList.add(new Measure(hours, MeasureUnit.HOUR));
+ }
+ if (minutes > 0) {
+ measureList.add(new Measure(minutes, MeasureUnit.MINUTE));
+ }
+ if (withSeconds && seconds > 0) {
+ measureList.add(new Measure(seconds, MeasureUnit.SECOND));
+ }
+ if (measureList.size() == 0) {
+ // Everything addable was zero, so nothing was added. We add a zero.
+ measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE));
+ }
+ final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]);
- final Locale locale = context.getResources().getConfiguration().locale;
- final MeasureFormat measureFormat = MeasureFormat.getInstance(
- locale, FormatWidth.NARROW);
- sb.append(measureFormat.formatMeasures(measureArray));
+ final Locale locale = context.getResources().getConfiguration().locale;
+ final MeasureFormat measureFormat = MeasureFormat.getInstance(
+ locale, FormatWidth.NARROW);
+ sb.append(measureFormat.formatMeasures(measureArray));
- if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) {
- // Add ttsSpan if it only have minute value, because it will be read as "meters"
- final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes)
- .setUnit("minute").build();
- sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
+ if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) {
+ // Add ttsSpan if it only have minute value, because it will be read as "meters"
+ final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes)
+ .setUnit("minute").build();
+ sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
- return sb;
- }
+ return sb;
+ }
/**
* Returns relative time for the given millis in the past, in a short format such as "2 days
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index 0c3a5e9..e693551 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -33,7 +33,7 @@
public class FooterPreference extends Preference {
static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
- static final String KEY_FOOTER = "footer_preference";
+ public static final String KEY_FOOTER = "footer_preference";
public FooterPreference(Context context, AttributeSet attrs) {
super(context, attrs, TypedArrayUtils.getAttr(
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index df1a7a8..2482095 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -527,10 +527,7 @@
WifiConfiguration connectionConfig = null;
if (mLastInfo != null) {
- // TODO(sghuman): Refactor to match config network id when updating configs below, and
- // then update network info and wifi info only on match
- connectionConfig = getWifiConfigurationForNetworkId(
- mLastInfo.getNetworkId(), configs);
+ connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
}
// Rather than dropping and reacquiring the lock multiple times in this method, we lock
@@ -564,6 +561,17 @@
accessPoints.add(accessPoint);
}
+ // If there were no scan results, create an AP for the currently connected network (if
+ // it exists).
+ // TODO(sghuman): Investigate if this works for an ephemeral (auto-connected) network
+ // when there are no scan results, as it may not have a valid WifiConfiguration
+ if (accessPoints.isEmpty() && connectionConfig != null) {
+ AccessPoint activeAp = new AccessPoint(mContext, connectionConfig);
+ activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo);
+ accessPoints.add(activeAp);
+ scoresToRequest.add(NetworkKey.createFromWifiInfo(mLastInfo));
+ }
+
requestScoresForNetworkKeys(scoresToRequest);
for (AccessPoint ap : accessPoints) {
ap.update(mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 8fd4700..ca965f3 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -696,6 +696,36 @@
}
@Test
+ public void onStartShouldDisplayConnectedAccessPointWhenThereAreNoScanResults()
+ throws Exception {
+ Network mockNetwork = mock(Network.class);
+ when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork);
+
+ when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
+
+ NetworkInfo networkInfo = new NetworkInfo(
+ ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
+ networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
+ when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(networkInfo);
+
+ // Don't return any scan results
+ when(mockWifiManager.getScanResults()).thenReturn(new ArrayList<>());
+
+ WifiTracker tracker = createMockedWifiTracker();
+ startTracking(tracker);
+
+ verify(mockWifiManager).getConnectionInfo();
+ verify(mockWifiManager, times(1)).getConfiguredNetworks();
+ verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
+
+ // mStaleAccessPoints is true
+ verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+
+ assertThat(tracker.getAccessPoints().size()).isEqualTo(1);
+ assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
+ }
+
+ @Test
public void stopTrackingShouldRemoveAllPendingWork() throws Exception {
WifiTracker tracker = createMockedWifiTracker();
startTracking(tracker);
@@ -778,7 +808,7 @@
mAccessPointsChangedLatch = new CountDownLatch(1);
tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
- assertThat(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+ assertThat(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
assertThat(tracker.getAccessPoints()).isEmpty();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
index 8767923..393fd02 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
@@ -82,8 +82,17 @@
assertThat(mPreference.isVisible()).isFalse();
}
- private class TestPrefController extends AbstractPreferenceController {
+ @Test
+ public void updateState_hasSummary_shouldSetSummary() {
+ mTestPrefController.updateState(mPreference);
+
+ assertThat(mPreference.getSummary()).isEqualTo(TestPrefController.TEST_SUMMARY);
+ }
+
+ private static class TestPrefController extends AbstractPreferenceController {
private static final String KEY_PREF = "test_pref";
+ private static final CharSequence TEST_SUMMARY = "Test";
+
public boolean isAvailable;
public TestPrefController(Context context) {
@@ -104,6 +113,11 @@
public String getPreferenceKey() {
return KEY_PREF;
}
+
+ @Override
+ public CharSequence getSummary() {
+ return TEST_SUMMARY;
+ }
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java
new file mode 100644
index 0000000..7820fd2
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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.settingslib.development;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class DeveloperOptionsPreferenceControllerTest {
+
+ private static final String TEST_KEY = "Test_pref_key";
+
+ @Mock
+ private Preference mPreference;
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+
+ private DeveloperOptionsPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new DeveloperOptionsPreferenceControllerTestable();
+ doReturn(mPreference).when(mPreferenceScreen).findPreference(TEST_KEY);
+ mController.displayPreference(mPreferenceScreen);
+ }
+
+ @Test
+ public void onDeveloperOptionsEnabled_shouldEnablePreference() {
+ mController.onDeveloperOptionsEnabled();
+
+ verify(mPreference).setEnabled(true);
+ }
+
+ @Test
+ public void onDeveloperOptionsDisabled_shouldDisablePreference() {
+ mController.onDeveloperOptionsDisabled();
+
+ verify(mPreference).setEnabled(false);
+ }
+
+ private class DeveloperOptionsPreferenceControllerTestable extends
+ DeveloperOptionsPreferenceController {
+ DeveloperOptionsPreferenceControllerTestable() {
+ super(RuntimeEnvironment.application);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return TEST_KEY;
+ }
+ }
+}
+
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java
new file mode 100644
index 0000000..026ad47
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.settingslib.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class IconCacheTest {
+ private Icon mIcon;
+ private Context mContext;
+ private IconCache mIconCache;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ mIcon = mock(Icon.class);
+ Drawable drawable = mock(Drawable.class);
+ doReturn(drawable).when(mIcon).loadDrawable(mContext);
+ mIconCache = new IconCache(mContext);
+ }
+
+ @Test
+ public void testGetIcon_iconisNull() {
+ assertThat(mIconCache.getIcon(null)).isNull();
+ }
+
+ @Test
+ public void testGetIcon_iconAlreadyLoaded() {
+ mIconCache.getIcon(mIcon);
+ verify(mIcon, times(1)).loadDrawable(mContext);
+ mIconCache.getIcon(mIcon);
+ verify(mIcon, times(1)).loadDrawable(mContext);
+ }
+
+ @Test
+ public void testGetIcon_iconLoadedFirstTime() {
+ mIconCache.getIcon(mIcon);
+ assertTrue(mIconCache.mMap.containsKey(mIcon));
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index 9285148f..c42ff08 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -24,13 +24,18 @@
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import java.time.Clock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import java.time.Duration;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSettings.ShadowSystem;
+import org.robolectric.shadows.ShadowSystemClock;
@RunWith(SettingsLibRobolectricTestRunner.class)
public class PowerUtilTest {
@@ -39,8 +44,12 @@
public static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis();
public static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis();
public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
- public static final long TWO_DAYS_MILLIS = Duration.ofDays(2).toMillis();
- public static final String ONE_DAY_FORMATTED = "1 day";
+ public static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis();
+ public static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis();
+ public static final String TWO_DAYS_FORMATTED = "2 days";
+ public static final String THIRTY_HOURS_FORMATTED = "1d 6h";
+ public static final String NORMAL_CASE_EXPECTED_PREFIX = "Will last until about";
+ public static final String ENHANCED_SUFFIX = "based on your usage";
private Context mContext;
@@ -51,6 +60,7 @@
}
@Test
+ @Config(shadows = {ShadowSystemClock.class})
public void testGetBatteryRemainingStringFormatted_moreThanFifteenMinutes_withPercentage() {
String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
SEVENTEEN_MIN_MILLIS,
@@ -62,15 +72,13 @@
false /* basedOnUsage */);
// We only add special mention for the long string
- assertThat(info).isEqualTo(mContext.getString(
- R.string.power_discharging_duration_enhanced,
- TEST_BATTERY_LEVEL_10,
- FIFTEEN_MIN_FORMATTED));
+ assertThat(info).contains(NORMAL_CASE_EXPECTED_PREFIX);
+ assertThat(info).contains(ENHANCED_SUFFIX);
+ assertThat(info).contains("%");
// shortened string should not have extra text
- assertThat(info2).isEqualTo(mContext.getString(
- R.string.power_discharging_duration,
- TEST_BATTERY_LEVEL_10,
- FIFTEEN_MIN_FORMATTED));
+ assertThat(info2).contains(NORMAL_CASE_EXPECTED_PREFIX);
+ assertThat(info2).doesNotContain(ENHANCED_SUFFIX);
+ assertThat(info2).contains("%");
}
@Test
@@ -84,14 +92,14 @@
null /* percentageString */,
false /* basedOnUsage */);
- // We only add special mention for the long string
- assertThat(info).isEqualTo(mContext.getString(
- R.string.power_remaining_duration_only_enhanced,
- FIFTEEN_MIN_FORMATTED));
+ // We only have % when it is provided
+ assertThat(info).contains(NORMAL_CASE_EXPECTED_PREFIX);
+ assertThat(info).contains(ENHANCED_SUFFIX);
+ assertThat(info).doesNotContain("%");
// shortened string should not have extra text
- assertThat(info2).isEqualTo(mContext.getString(
- R.string.power_remaining_duration_only,
- FIFTEEN_MIN_FORMATTED));
+ assertThat(info2).contains(NORMAL_CASE_EXPECTED_PREFIX);
+ assertThat(info2).doesNotContain(ENHANCED_SUFFIX);
+ assertThat(info2).doesNotContain("%");
}
@@ -107,12 +115,9 @@
true /* basedOnUsage */);
// additional battery percentage in this string
- assertThat(info).isEqualTo(mContext.getString(
- R.string.power_remaining_duration_shutdown_imminent,
- TEST_BATTERY_LEVEL_10));
+ assertThat(info).isEqualTo("Phone may shutdown soon (10%)");
// shortened string should not have percentage
- assertThat(info2).isEqualTo(mContext.getString(
- R.string.power_remaining_duration_only_shutdown_imminent));
+ assertThat(info2).isEqualTo("Phone may shutdown soon");
}
@Test
@@ -127,35 +132,42 @@
true /* basedOnUsage */);
// shortened string should not have percentage
- assertThat(info).isEqualTo(mContext.getString(
- R.string.power_remaining_less_than_duration_only,
- FIFTEEN_MIN_FORMATTED));
+ assertThat(info).isEqualTo("Less than 15m remaining");
// Add percentage to string when provided
- assertThat(info2).isEqualTo(mContext.getString(
- R.string.power_remaining_less_than_duration,
- TEST_BATTERY_LEVEL_10,
- FIFTEEN_MIN_FORMATTED));
+ assertThat(info2).isEqualTo("Less than 15m remaining (10%)");
}
@Test
- public void testGetBatteryRemainingStringFormatted_moreThanOneDay_usesCorrectString() {
+ public void testGetBatteryRemainingStringFormatted_betweenOneAndTwoDays_usesCorrectString() {
String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
- TWO_DAYS_MILLIS,
+ THIRTY_HOURS_MILLIS,
null /* percentageString */,
true /* basedOnUsage */);
String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
- TWO_DAYS_MILLIS,
+ THIRTY_HOURS_MILLIS,
+ TEST_BATTERY_LEVEL_10 /* percentageString */,
+ false /* basedOnUsage */);
+
+ // We only add special mention for the long string
+ assertThat(info).isEqualTo("About 1d 6h left based on your usage");
+ // shortened string should not have extra text
+ assertThat(info2).isEqualTo("About 1d 6h left (10%)");
+ }
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_moreThanTwoDays_usesCorrectString() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ THREE_DAYS_MILLIS,
+ null /* percentageString */,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ THREE_DAYS_MILLIS,
TEST_BATTERY_LEVEL_10 /* percentageString */,
true /* basedOnUsage */);
// shortened string should not have percentage
- assertThat(info).isEqualTo(mContext.getString(
- R.string.power_remaining_only_more_than_subtext,
- ONE_DAY_FORMATTED));
+ assertThat(info).isEqualTo("More than 2 days remaining");
// Add percentage to string when provided
- assertThat(info2).isEqualTo(mContext.getString(
- R.string.power_remaining_more_than_subtext,
- TEST_BATTERY_LEVEL_10,
- ONE_DAY_FORMATTED));
+ assertThat(info2).isEqualTo("More than 2 days remaining (10%)");
}
}
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 0f2c5ab..db57fd1 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -10,6 +10,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := SettingsProvider
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index 902f1c7..bd5b1f2 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -15,6 +15,7 @@
LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_PACKAGE_NAME := SettingsProviderTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk
index a213965f..2e07ab1 100644
--- a/packages/SharedStorageBackup/Android.mk
+++ b/packages/SharedStorageBackup/Android.mk
@@ -24,6 +24,7 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PACKAGE_NAME := SharedStorageBackup
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 935d09b..5713dc6 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -15,6 +15,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_PACKAGE_NAME := Shell
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/Shell/res/values-as/strings.xml b/packages/Shell/res/values-as/strings.xml
index 8ad0358..9d6c37a 100644
--- a/packages/Shell/res/values-as/strings.xml
+++ b/packages/Shell/res/values-as/strings.xml
@@ -17,8 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"শ্বেল"</string>
- <!-- no translation found for bugreport_notification_channel (2574150205913861141) -->
- <skip />
+ <string name="bugreport_notification_channel" msgid="2574150205913861141">"বাগ সম্পৰ্কীয় প্ৰতিবেদন"</string>
<!-- no translation found for bugreport_in_progress_title (4311705936714972757) -->
<skip />
<!-- no translation found for bugreport_finished_title (4429132808670114081) -->
diff --git a/packages/Shell/res/values-or/strings.xml b/packages/Shell/res/values-or/strings.xml
index 750b5f73..bfb3b53 100644
--- a/packages/Shell/res/values-or/strings.xml
+++ b/packages/Shell/res/values-or/strings.xml
@@ -43,8 +43,7 @@
<skip />
<!-- no translation found for bugreport_confirm_dont_repeat (6179945398364357318) -->
<skip />
- <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
- <skip />
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"ବଗ୍ ରିପୋର୍ଟ"</string>
<!-- no translation found for bugreport_unreadable_text (586517851044535486) -->
<skip />
<!-- no translation found for bugreport_add_details_to_zip_failed (1302931926486712371) -->
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index 7f24a38..b93ddde 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -15,6 +15,7 @@
junit \
LOCAL_PACKAGE_NAME := ShellTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_INSTRUMENTATION_FOR := Shell
diff --git a/packages/StatementService/Android.mk b/packages/StatementService/Android.mk
index 470d824..b9b29e7 100644
--- a/packages/StatementService/Android.mk
+++ b/packages/StatementService/Android.mk
@@ -22,6 +22,7 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PACKAGE_NAME := StatementService
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PRIVILEGED_MODULE := true
LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
new file mode 100644
index 0000000..06820a6
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="3171996292755059205">"কীগাৰ্ড"</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3420548423949593123">"পিন ক\'ড লিখক"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"ছিমৰ PUK আৰু নতুন পিন ক\'ড লিখক"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"ছিমৰ PUK ক\'ড"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"নতুন ছিমৰ পিন ক\'ড"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"পাছৱৰ্ড লিখিবলৈ স্পৰ্শ কৰক"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"আনলক কৰিবলৈ পাছৱৰ্ড লিখক"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"আনলক কৰিবলৈ পিন লিখক"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ভুল পিন ক\'ড।"</string>
+ <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+ <skip />
+ <string name="keyguard_charged" msgid="2222329688813033109">"চ্চার্জ কৰা হ\'ল"</string>
+ <string name="keyguard_plugged_in" msgid="89308975354638682">"চ্চার্জ কৰি থকা হৈছে"</string>
+ <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"দ্ৰুত গতিৰে চ্চাৰ্জ কৰি থকা হৈছে"</string>
+ <string name="keyguard_plugged_in_charging_slowly" msgid="6637043106038550407">"লাহে লাহে চ্চাৰ্জ হৈ আছে"</string>
+ <string name="keyguard_low_battery" msgid="9218432555787624490">"আপোনাৰ চ্চার্জাৰ সংযোগ কৰক।"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"আনলক কৰিবলৈ মেনু টিপক।"</string>
+ <string name="keyguard_network_locked_message" msgid="6743537524631420759">"নেটৱর্ক লক কৰা অৱস্থাত আছে"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"কোনো ছিম কাৰ্ড নাই"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"টেবলেটত ছিম কার্ড নাই।"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"ফ\'নত ছিম কার্ড নাই।"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"এখন ছিম কাৰ্ড ভৰাওক।"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"ছিম কাৰ্ডখন নাই বা চিনাক্ত কৰিব নোৱাৰি। এখন ছিম কাৰ্ড ভৰাওক।"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড।"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"আপোনাৰ ছিম কাৰ্ডখন স্থায়ীভাৱে অক্ষম হৈছে।\n অন্য এখন ছিমৰ বাবে আপোনাৰ ৱায়াৰলেছ সেৱা প্ৰদানকাৰীৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="keyguard_sim_locked_message" msgid="953766009432168127">"ছিম কাৰ্ড লক কৰা হৈছে।"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"ছিম কার্ডখন PUKৰ দ্বাৰা লক কৰা হৈছে।"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"ছিম কার্ড আনলক কৰি থকা হৈছে…"</string>
+ <string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"পিনৰ ক্ষেত্ৰ"</string>
+ <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"ছিম পিনৰ ক্ষেত্ৰ"</string>
+ <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"ছিমৰ PUK ক্ষেত্ৰ"</string>
+ <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"পৰৱৰ্তী এলাৰ্ম <xliff:g id="ALARM">%1$s</xliff:g> বজাত ছেট কৰা হৈছে"</string>
+ <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"মচক"</string>
+ <!-- no translation found for disable_carrier_button_text (6914341927421916114) -->
+ <skip />
+ <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+ <skip />
+ <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+ <skip />
+ <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"এণ্টাৰ বুটাম"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"আৰ্হি পাহৰিলে নেকি"</string>
+ <string name="kg_wrong_pattern" msgid="7620081431514773802">"ভুল আৰ্হি"</string>
+ <string name="kg_wrong_password" msgid="4580683060277329277">"ভুল পাছৱৰ্ড"</string>
+ <string name="kg_wrong_pin" msgid="4785660766909463466">"ভুল পিন"</string>
+ <!-- no translation found for kg_too_many_failed_attempts_countdown (4368805541257003755) -->
+ <string name="kg_pattern_instructions" msgid="5547646893001491340">"আপোনাৰ আৰ্হি আঁকক"</string>
+ <!-- no translation found for kg_sim_pin_instructions (6389000973113699187) -->
+ <skip />
+ <!-- no translation found for kg_sim_pin_instructions_multi (1643757228644271861) -->
+ <skip />
+ <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+ <skip />
+ <string name="kg_pin_instructions" msgid="4069609316644030034">"পিন দিয়ক"</string>
+ <string name="kg_password_instructions" msgid="136952397352976538">"পাছৱৰ্ড দিয়ক"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ছিমখন বর্তমান অক্ষম অৱস্থাত আছে। অব্যাহত ৰাখিবলৈ PUK ক\'ড লিখক। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" ছিমখন বর্তমান অক্ষম অৱস্থাত আছে। অব্যাহত ৰাখিবলৈ PUK ক\'ড দিয়ক। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"আপোনাৰ পছন্দৰ পিন ক\'ড লিখক"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="3089485999116759671">"আপোনাৰ পচন্দৰ পিন ক\'ড নিশ্চিত কৰক"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"ছিম কার্ড আনলক কৰি থকা হৈছে…"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="3057533256729513335">"৪টাৰ পৰা ৮টা সংখ্যাযুক্ত এটা পিন লিখক।"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"PUK ক\'ডটো ৮টা বা তাতকৈ অধিক সংখ্যা থকা হ\'ব লাগিব।"</string>
+ <string name="kg_invalid_puk" msgid="5399287873762592502">"শুদ্ধ PUK ক\'ডটো পুনৰ দিয়ক। বাৰে বাৰে ভুল ক\'ড দিলে ছিমখন স্থায়ীভাৱে অক্ষম হ\'ব।"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"পিন ক\'ড মিলা নাই"</string>
+ <string name="kg_login_too_many_attempts" msgid="6604574268387867255">"বহুতবাৰ ভুলকৈ আর্হি অঁকা হৈছে"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"আপুনি আপোনাৰ পিন <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"আপুনি আপোনাৰ পাছৱৰ্ড <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পাছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"আপুনি আপোনাৰ আনলক আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1629351522209932316">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই টেবলেটটোত থকা সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="3921998703529189931">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ৰিছেট কৰা হ\'ব, যি কার্যই ফ\'নটোত থকা সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="4694232971224663735">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই ইয়াৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="2365964340830006961">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ফ\'নটো ৰিছেট কৰা হ\'ব, যিয়ে ইয়াৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="1365418870560228936">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="2151286957817486128">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="5464020754932560928">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="6171564974118059">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যি কার্যই ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="9154513795928824239">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="2162434417489128282">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="8966727588974691544">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যি কার্যই প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="8476407539834855">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="956706236554092172">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ টেবলেটটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"ছিমৰ ভুল পিন ক\'ড, আপোনাৰ ডিভাইচটো আনলক কৰিবলৈ আপুনি এতিয়া আপোনাৰ বাহকৰ সৈতে যোগাযোগ কৰিবই লাগিব।"</string>
+ <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
+ <item quantity="one">ছিমৰ ভুল পিন ক’ড, আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g> বাৰ প্ৰয়াস কৰিব পাৰিব।</item>
+ <item quantity="other">ছিমৰ ভুল পিন ক’ড, আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g> বাৰ প্ৰয়াস কৰিব পাৰিব।</item>
+ </plurals>
+ <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"ছিম ব্যৱহাৰযোগ্য নহয়। আপোনাৰ বাহকৰ সৈতে যোগাযোগ কৰক।"</string>
+ <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
+ <item quantity="one">ছিমৰ ভুল PUK ক\'ড, আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g> বাৰ ভুল ক’ড দিলে আপোনাৰ ছিম চিৰকালৰ বাবে ব্যৱহাৰৰ অনুপযোগী হ’ব।</item>
+ <item quantity="other">ছিমৰ ভুল PUK ক\'ড, আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g> বাৰ ভুল ক’ড দিলে আপোনাৰ ছিম চিৰকালৰ বাবে ব্যৱহাৰৰ অনুপযোগী হ’ব।</item>
+ </plurals>
+ <string name="kg_password_pin_failed" msgid="8769990811451236223">"ছিম পিনৰ জৰিয়তে আনলক কৰিব পৰা নগ\'ল!"</string>
+ <string name="kg_password_puk_failed" msgid="1331621440873439974">"ছিম PUKৰ জৰিয়তে আনলক কৰিব পৰা নগ\'ল!"</string>
+ <string name="kg_pin_accepted" msgid="7637293533973802143">"ক\'ড গ্ৰহণ কৰা হ\'ল!"</string>
+ <string name="keyguard_carrier_default" msgid="4274828292998453695">"কোনো সেৱা নাই।"</string>
+ <string name="accessibility_ime_switch_button" msgid="2695096475319405612">"ইনপুট পদ্ধতি সলনি কৰক"</string>
+ <string name="airplane_mode" msgid="3807209033737676010">"এয়াৰপ্লেন ম\'ড"</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="7246972020562621506">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত আৰ্হি দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_restart_pin" msgid="6303592361322290145">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত পিন দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_restart_password" msgid="6984641181515902406">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত পাছৱৰ্ড দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5304487696073914063">"অতিৰিক্ত সুৰক্ষাৰ বাবে আর্হি দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="8851462864335757813">"অতিৰিক্ত সুৰক্ষাৰ বাবে পিন দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="6563904839641583441">"অতিৰিক্ত সুৰক্ষাৰ বাবে পাছৱর্ড দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3398054847288438444">"প্ৰ\'ফাইল সলনি কৰোঁতে আৰ্হি দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_switch_profiles_pin" msgid="7426368139226961699">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত পিন দিয়াটো বাধ্যতামূলক"</string>
+ <string name="kg_prompt_reason_switch_profiles_password" msgid="8383831046318421845">"প্ৰ\'ফাইল সলনি কৰোঁতে পাছৱৰ্ড দিয়াটো বাধ্যতামূলক"</string>
+ <!-- no translation found for kg_prompt_reason_device_admin (3452168247888906179) -->
+ <skip />
+ <string name="kg_prompt_reason_user_request" msgid="8236951765212462286">"ডিভাইচটো মেনুৱেলভাৱে লক কৰা হৈছিল"</string>
+ <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="71299470072448533">
+ <item quantity="one">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। আর্হি নিশ্চিত কৰক।</item>
+ <item quantity="other">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। আর্হি নিশ্চিত কৰক।</item>
+ </plurals>
+ <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="34586942088144385">
+ <item quantity="one">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। পিন নিশ্চিত কৰক।</item>
+ <item quantity="other">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। পিন নিশ্চিত কৰক।</item>
+ </plurals>
+ <plurals name="kg_prompt_reason_time_password" formatted="false" msgid="257297696215346527">
+ <item quantity="one">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। পাছৱৰ্ড নিশ্চিত কৰক।</item>
+ <item quantity="other">ডিভাইচটো <xliff:g id="NUMBER_1">%d</xliff:g> ঘণ্টা ধৰি আনলক কৰা হোৱা নাই। পাছৱৰ্ড নিশ্চিত কৰক।</item>
+ </plurals>
+ <string name="fingerprint_not_recognized" msgid="348813995267914625">"চিনাক্ত কৰিব পৰা নগ\'ল"</string>
+ <!-- no translation found for kg_password_default_pin_message (6203676909479972943) -->
+ <!-- no translation found for kg_password_default_puk_message (8744416410184198352) -->
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 8a48e7b..02d0d70 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -57,15 +57,15 @@
<!-- When the lock screen is showing and the phone plugged in, and the battery
is not fully charged, say that it's charging. -->
- <string name="keyguard_plugged_in">Charging</string>
+ <string name="keyguard_plugged_in"><xliff:g id="percentage">%s</xliff:g> • Charging</string>
<!-- When the lock screen is showing and the phone plugged in, and the battery
is not fully charged, and it's plugged into a fast charger, say that it's charging fast. -->
- <string name="keyguard_plugged_in_charging_fast">Charging rapidly</string>
+ <string name="keyguard_plugged_in_charging_fast"><xliff:g id="percentage">%s</xliff:g> • Charging rapidly</string>
<!-- When the lock screen is showing and the phone plugged in, and the battery
is not fully charged, and it's plugged into a slow charger, say that it's charging slowly. -->
- <string name="keyguard_plugged_in_charging_slowly">Charging slowly</string>
+ <string name="keyguard_plugged_in_charging_slowly"><xliff:g id="percentage">%s</xliff:g> • Charging slowly</string>
<!-- When the lock screen is showing and the battery is low, warn user to plug
in the phone soon. -->
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index f635b18..3c24845 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -43,40 +43,24 @@
android:layout_gravity="center_vertical"
android:gravity="end" >
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" >
- <!-- Add an extra 8dp margin before carrier text without shifting it right -->
- <android.widget.Space
- android:layout_width="8dp"
- android:layout_height="match_parent" />
-
- <com.android.keyguard.CarrierText
- android:id="@+id/qs_carrier_text"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_vertical|start"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:textDirection="locale"
- android:singleLine="true" />
- </LinearLayout>
-
- <View
- android:id="@+id/qs_drag_handle_view"
- android:layout_width="24dp"
- android:layout_height="4dp"
- android:layout_gravity="center"
- android:background="@drawable/qs_footer_drag_handle" />
-
- <com.android.keyguard.AlphaOptimizedLinearLayout
- android:id="@+id/qs_footer_actions_container"
+ <com.android.keyguard.CarrierText
+ android:id="@+id/qs_carrier_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="32dp"
+ android:gravity="center_vertical|start"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textDirection="locale"
+ android:singleLine="true" />
+
+ <com.android.keyguard.AlphaOptimizedLinearLayout
+ android:id="@+id/qs_footer_actions_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
android:gravity="center_vertical|end" >
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
@@ -139,4 +123,11 @@
</com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
+ <View
+ android:id="@+id/qs_drag_handle_view"
+ android:layout_width="24dp"
+ android:layout_height="4dp"
+ android:layout_gravity="center"
+ android:background="@drawable/qs_footer_drag_handle" />
+
</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/quick_settings_header.xml b/packages/SystemUI/res/layout/quick_settings_header.xml
deleted file mode 100644
index 43197c4..0000000
--- a/packages/SystemUI/res/layout/quick_settings_header.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 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
- -->
-<com.android.systemui.qs.QSTooltipView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qs_header_tooltip_height"
- android:alpha="0"
- android:gravity="center_horizontal|bottom"
- android:visibility="invisible">
-
- <TextView
- android:id="@+id/header_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/quick_settings_header_onboarding_text"
- android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/colorAccent" />
-
-</com.android.systemui.qs.QSTooltipView>
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
new file mode 100644
index 0000000..89d6e99
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 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
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header_text_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_header_tooltip_height"
+ android:layout_below="@id/quick_status_bar_system_icons"
+ android:layout_marginTop="12dp">
+
+ <TextView
+ android:id="@+id/long_press_tooltip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:alpha="0"
+ android:text="@string/quick_settings_header_onboarding_text"
+ android:textAppearance="@style/TextAppearance.QS.TileLabel"
+ android:textColor="?android:attr/colorAccent"
+ android:visibility="invisible" />
+
+ <LinearLayout
+ android:id="@+id/next_alarm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:gravity="center_vertical"
+ android:visibility="invisible">
+
+ <ImageView
+ android:layout_width="@dimen/qs_header_alarm_icon_size"
+ android:layout_height="@dimen/qs_header_alarm_icon_size"
+ android:src="@drawable/stat_sys_alarm"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/next_alarm_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
+ android:textAppearance="@style/TextAppearance.QS.TileLabel" />
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index cc79d0d..ca8fcba 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -32,13 +32,20 @@
android:elevation="4dp" >
<include layout="@layout/quick_status_bar_header_system_icons" />
+
+ <!-- Status icons within the panel itself (and not in the top-most status bar) -->
<include layout="@layout/quick_qs_status_icons" />
+ <!-- Layout containing tooltips, alarm text, etc. -->
+ <include layout="@layout/quick_settings_header_info" />
+
<com.android.systemui.qs.QuickQSPanel
android:id="@+id/quick_qs_panel"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_below="@id/quick_qs_status_icons"
+ android:layout_marginStart="@dimen/qs_header_tile_margin_horizontal"
+ android:layout_marginEnd="@dimen/qs_header_tile_margin_horizontal"
android:accessibilityTraversalAfter="@+id/date_time_group"
android:accessibilityTraversalBefore="@id/expand_indicator"
android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 4614999..2e7ab7f 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
+<!-- extends FrameLayout -->
<com.android.systemui.statusbar.ExpandableNotificationRow
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -54,6 +55,7 @@
android:paddingStart="8dp"
/>
+ <!-- TODO: remove -->
<ImageButton
android:id="@+id/helper"
android:layout_width="48dp"
@@ -64,7 +66,7 @@
android:tint="#FF0000"
android:background="@drawable/ripple_drawable"
android:visibility="visible"
- />
+ />
<ViewStub
android:layout="@layout/notification_children_container"
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index ccfb034..e2ac574 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -109,8 +109,7 @@
<string name="accessibility_back" msgid="567011538994429120">"উভতি যাওক"</string>
<string name="accessibility_home" msgid="8217216074895377641">"গৃহ পৃষ্ঠাৰ বুটাম"</string>
<string name="accessibility_menu" msgid="316839303324695949">"মেনু"</string>
- <!-- no translation found for accessibility_accessibility_button (7601252764577607915) -->
- <skip />
+ <string name="accessibility_accessibility_button" msgid="7601252764577607915">"দিব্যাংগসকলৰ বাবে থকা সুবিধাসমূহ"</string>
<!-- no translation found for accessibility_rotate_button (7402949513740253006) -->
<skip />
<string name="accessibility_recent" msgid="5208608566793607626">"অৱলোকন"</string>
@@ -245,8 +244,7 @@
<string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"বন্ধ স্ক্ৰীণ।"</string>
<string name="accessibility_desc_settings" msgid="3417884241751434521">"ছেটিংসমূহ"</string>
<string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"অৱলোকন।"</string>
- <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
- <skip />
+ <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ লক স্ক্ৰীণ"</string>
<!-- no translation found for accessibility_desc_close (7479755364962766729) -->
<skip />
<string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
@@ -312,8 +310,7 @@
<!-- no translation found for accessibility_quick_settings_data_saver_changed_on (4218725402373934151) -->
<skip />
<string name="accessibility_brightness" msgid="8003681285547803095">"ডিছপ্লেৰ উজ্জ্বলতা"</string>
- <!-- no translation found for accessibility_ambient_display_charging (9084521679384069087) -->
- <skip />
+ <string name="accessibility_ambient_display_charging" msgid="9084521679384069087">"চ্চার্জ কৰি থকা হৈছে"</string>
<!-- no translation found for data_usage_disabled_dialog_3g_title (5281770593459841889) -->
<skip />
<!-- no translation found for data_usage_disabled_dialog_4g_title (1601769736881078016) -->
@@ -442,12 +439,9 @@
<skip />
<!-- no translation found for quick_settings_night_secondary_label_until (8664820079774824618) -->
<skip />
- <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
- <skip />
- <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
- <skip />
+ <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
+ <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
+ <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC সক্ষম হৈ আছে"</string>
<!-- no translation found for recents_empty_message (808480104164008572) -->
<skip />
<!-- no translation found for recents_empty_message_dismissed_all (2791312568666558651) -->
@@ -468,12 +462,9 @@
<skip />
<!-- no translation found for recents_multistack_add_stack_dialog_split_custom (4177837597513701943) -->
<skip />
- <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
- <skip />
- <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
- <skip />
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"স্ক্ৰীণখনক ওপৰফাললৈ ভাগ কৰক"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"স্ক্ৰীণখনক বাওঁফাললৈ ভাগ কৰক"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"স্ক্ৰীণখনক সোঁফাললৈ ভাগ কৰক"</string>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"চ্চার্জ হ\'ল"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"চ্চার্জ হৈ আছে"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"বেটাৰিৰ চ্চাৰ্জ সম্পূর্ণ হ\'বলৈ <xliff:g id="CHARGING_TIME">%s</xliff:g> বাকী"</string>
@@ -496,8 +487,7 @@
<string name="speed_bump_explanation" msgid="1288875699658819755">"কম জৰুৰী জাননীসমূহ তলত"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"খুলিবলৈ পুনৰাই টিপক"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"আনলক কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
- <!-- no translation found for do_disclosure_generic (5615898451805157556) -->
- <skip />
+ <string name="do_disclosure_generic" msgid="5615898451805157556">"আপোনাৰ প্ৰতিষ্ঠানে এই ডিভাইচটো পৰিচালনা কৰে"</string>
<!-- no translation found for do_disclosure_with_name (5640615509915445501) -->
<skip />
<!-- no translation found for phone_hint (4872890986869209950) -->
@@ -576,8 +566,7 @@
<string name="vpn_footer" msgid="2388611096129106812">"নেটৱৰ্ক নিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
<!-- no translation found for branded_vpn_footer (2168111859226496230) -->
<skip />
- <!-- no translation found for quick_settings_disclosure_management_monitoring (6645176135063957394) -->
- <skip />
+ <string name="quick_settings_disclosure_management_monitoring" msgid="6645176135063957394">"আপোনাৰ প্ৰতিষ্ঠানটোৱে এই ডিভাইচটো পৰিচালনা কৰে আৰু ই নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<!-- no translation found for quick_settings_disclosure_named_management_monitoring (370622174777570853) -->
<skip />
<!-- no translation found for quick_settings_disclosure_management_named_vpn (1085137869053332307) -->
@@ -594,12 +583,10 @@
<skip />
<!-- no translation found for quick_settings_disclosure_managed_profile_monitoring (5125463987558278215) -->
<skip />
- <!-- no translation found for quick_settings_disclosure_named_managed_profile_monitoring (8973606847896650284) -->
- <skip />
+ <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8973606847896650284">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>এ আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে"</string>
<!-- no translation found for quick_settings_disclosure_monitoring (679658227269205728) -->
<skip />
- <!-- no translation found for quick_settings_disclosure_vpns (8170318392053156330) -->
- <skip />
+ <string name="quick_settings_disclosure_vpns" msgid="8170318392053156330">"ডিভাইচটো ভিপিএনবোৰৰ সৈতে সংযুক্ত হৈ আছে"</string>
<!-- no translation found for quick_settings_disclosure_managed_profile_named_vpn (3494535754792751741) -->
<skip />
<!-- no translation found for quick_settings_disclosure_personal_profile_named_vpn (4467456202486569906) -->
@@ -610,66 +597,55 @@
<skip />
<string name="monitoring_title_profile_owned" msgid="6790109874733501487">"প্ৰ\'ফাইল নিৰীক্ষণ"</string>
<string name="monitoring_title" msgid="169206259253048106">"নেটৱৰ্ক নিৰীক্ষণ"</string>
- <!-- no translation found for monitoring_subtitle_vpn (876537538087857300) -->
- <skip />
+ <string name="monitoring_subtitle_vpn" msgid="876537538087857300">"ভিপিএন"</string>
<!-- no translation found for monitoring_subtitle_network_logging (3341264304793193386) -->
<skip />
<!-- no translation found for monitoring_subtitle_ca_certificate (3874151893894355988) -->
<skip />
<string name="disable_vpn" msgid="4435534311510272506">"ভিপিএন অক্ষম কৰক"</string>
<string name="disconnect_vpn" msgid="1324915059568548655">"ভিপিএন সংযোগ বিচ্ছিন্ন কৰক"</string>
- <!-- no translation found for monitoring_button_view_policies (100913612638514424) -->
- <skip />
+ <string name="monitoring_button_view_policies" msgid="100913612638514424">"নীতিসমূহ চাওক"</string>
<!-- no translation found for monitoring_description_named_management (5281789135578986303) -->
<skip />
<!-- no translation found for monitoring_description_management (4573721970278370790) -->
<skip />
- <!-- no translation found for monitoring_description_management_ca_certificate (5202023784131001751) -->
- <skip />
+ <string name="monitoring_description_management_ca_certificate" msgid="5202023784131001751">"আপোনাৰ প্ৰতিষ্ঠানে এই ডিভাইচটোত এটা প্ৰমাণপত্ৰ সম্পৰ্কীয় কৰ্তৃপক্ষ ইনষ্টল কৰিছে। আপোনাৰ সুৰক্ষিত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ বা সংশোধন কৰা হ\'ব পাৰে।"</string>
<!-- no translation found for monitoring_description_managed_profile_ca_certificate (4683248196789897964) -->
<skip />
- <!-- no translation found for monitoring_description_ca_certificate (7886985418413598352) -->
- <skip />
- <!-- no translation found for monitoring_description_management_network_logging (7184005419733060736) -->
- <skip />
+ <string name="monitoring_description_ca_certificate" msgid="7886985418413598352">"এই ডিভাইচটোত এটা প্ৰমাণপত্ৰ সম্পৰ্কীয় কৰ্তৃপক্ষ ইনষ্টল কৰা হৈছে। আপোনাৰ সুৰক্ষিত নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ বা সংশোধন কৰা হ\'ব পাৰে।"</string>
+ <string name="monitoring_description_management_network_logging" msgid="7184005419733060736">"আপোনাৰ প্ৰশাসকে নেটৱৰ্ক লগিং অন কৰিছে, যিয়ে আপোনাৰ ডিভাইচটোত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ কৰে।"</string>
<!-- no translation found for monitoring_description_named_vpn (7403457334088909254) -->
<skip />
<!-- no translation found for monitoring_description_two_named_vpns (4198511413729213802) -->
<skip />
- <!-- no translation found for monitoring_description_managed_profile_named_vpn (1427905889862420559) -->
- <skip />
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="1427905889862420559">"আপুনি <xliff:g id="VPN_APP">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে যিয়ে আপোনাৰ ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<!-- no translation found for monitoring_description_personal_profile_named_vpn (3133980926929069283) -->
<skip />
<!-- no translation found for monitoring_description_do_header_generic (96588491028288691) -->
<skip />
<!-- no translation found for monitoring_description_do_header_with_name (5511133708978206460) -->
<skip />
- <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
- <skip />
+ <string name="monitoring_description_do_body" msgid="3639594537660975895">"আপোনাৰ প্ৰশাসকে আপোনাৰ ডিভাইচৰ লগত জড়িত ছেটিংসমূহ, কৰ্প\'ৰেইট অনুমতি, এপসমূহ, ডেটা আৰু ডিভাইচৰ অৱস্থান সম্পৰ্কীয় তথ্য পৰ্যবেক্ষণ কৰাৰ লগতে পৰিচালনা কৰিব পাৰিব।"</string>
<!-- no translation found for monitoring_description_do_learn_more_separator (3785251953067436862) -->
<skip />
<!-- no translation found for monitoring_description_do_learn_more (1849514470437907421) -->
<skip />
<!-- no translation found for monitoring_description_do_body_vpn (8255218762488901796) -->
<skip />
- <!-- no translation found for monitoring_description_vpn_settings_separator (1933186756733474388) -->
- <skip />
+ <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
<!-- no translation found for monitoring_description_vpn_settings (6434859242636063861) -->
<skip />
<!-- no translation found for monitoring_description_ca_cert_settings_separator (4987350385906393626) -->
<skip />
<!-- no translation found for monitoring_description_ca_cert_settings (5489969458872997092) -->
<skip />
- <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
- <skip />
+ <string name="monitoring_description_network_logging" msgid="7223505523384076027">"আপোনাৰ প্ৰশাসকে নেটৱৰ্ক লগিং অন কৰিছে, যিয়ে আপোনাৰ ডিভাইচটোত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ কৰে।\n\nএই সম্পৰ্কে অধিক জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
<!-- no translation found for monitoring_description_vpn (4445150119515393526) -->
<skip />
- <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
- <skip />
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>য়ে আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল পৰিচালনা কৰে।\n\nআপোনাৰ প্ৰশাসকে ইমেইল, এপসমূহ আৰু আপুনি চোৱা ৱেবছাইটকে ধৰি আপোনাৰ নেটৱৰ্কৰ সকলো কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে। \n\nঅধিক তথ্যৰ বাবে আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।\n\nইয়াৰ উপৰি, আপুনি এটা ভিপিএনৰ সৈতে সংযুক্ত হৈ আছে, যিয়ে আপোনাৰ নেটৱৰ্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<!-- no translation found for legacy_vpn_name (6604123105765737830) -->
<skip />
- <!-- no translation found for monitoring_description_app (1828472472674709532) -->
- <skip />
+ <string name="monitoring_description_app" msgid="1828472472674709532">"আপুনি <xliff:g id="APPLICATION">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে যিয়ে আপোনাৰ ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<!-- no translation found for monitoring_description_app_personal (484599052118316268) -->
<skip />
<!-- no translation found for branded_monitoring_description_app_personal (2669518213949202599) -->
@@ -697,12 +673,10 @@
<!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
<skip />
<string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্ৰীণ পিন কৰা হ\'ল"</string>
- <!-- no translation found for screen_pinning_description (8909878447196419623) -->
- <skip />
+ <string name="screen_pinning_description" msgid="8909878447196419623">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'পিছলৈ যাওক\' আৰু \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
<skip />
- <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
- <skip />
+ <string name="screen_pinning_description_accessible" msgid="426190689254018656">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
<skip />
<!-- no translation found for screen_pinning_toast (2266705122951934150) -->
@@ -724,20 +698,14 @@
<skip />
<!-- no translation found for stream_system (7493299064422163147) -->
<skip />
- <!-- no translation found for stream_ring (8213049469184048338) -->
- <skip />
- <!-- no translation found for stream_music (9086982948697544342) -->
- <skip />
+ <string name="stream_ring" msgid="8213049469184048338">"ৰিং"</string>
+ <string name="stream_music" msgid="9086982948697544342">"মিডিয়া"</string>
<!-- no translation found for stream_alarm (5209444229227197703) -->
<skip />
- <!-- no translation found for stream_notification (2563720670905665031) -->
- <skip />
- <!-- no translation found for stream_bluetooth_sco (2055645746402746292) -->
- <skip />
- <!-- no translation found for stream_dtmf (2447177903892477915) -->
- <skip />
- <!-- no translation found for stream_accessibility (301136219144385106) -->
- <skip />
+ <string name="stream_notification" msgid="2563720670905665031">"জাননী"</string>
+ <string name="stream_bluetooth_sco" msgid="2055645746402746292">"ব্লুটুথ"</string>
+ <string name="stream_dtmf" msgid="2447177903892477915">"ডুৱেল মাল্টি ট\'ন ফ্ৰিকুৱেন্সী"</string>
+ <string name="stream_accessibility" msgid="301136219144385106">"দিব্যাংগসকলৰ বাবে থকা সুবিধাসমূহ"</string>
<!-- no translation found for ring_toggle_title (3281244519428819576) -->
<skip />
<!-- no translation found for volume_ringer_status_normal (4273142424125855384) -->
@@ -752,12 +720,16 @@
<skip />
<!-- no translation found for volume_stream_content_description_mute (3625049841390467354) -->
<skip />
- <!-- no translation found for volume_stream_content_description_vibrate_a11y (6427727603978431301) -->
- <skip />
- <!-- no translation found for volume_stream_content_description_mute_a11y (8995013018414535494) -->
- <skip />
+ <string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s। কম্পন অৱস্থাত ছেট কৰিবলৈ টিপক।"</string>
+ <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
<!-- no translation found for volume_dialog_title (7272969888820035876) -->
<skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<!-- no translation found for output_title (5355078100792942802) -->
<skip />
<!-- no translation found for output_calls_title (8717692905017206161) -->
@@ -784,8 +756,7 @@
<skip />
<!-- no translation found for overview (4018602013895926956) -->
<skip />
- <!-- no translation found for demo_mode (2532177350215638026) -->
- <skip />
+ <string name="demo_mode" msgid="2532177350215638026">"ছিষ্টেমৰ UI প্ৰদৰ্শন ম\'ড"</string>
<!-- no translation found for enable_demo_mode (4844205668718636518) -->
<skip />
<!-- no translation found for show_demo_mode (2018336697782464029) -->
@@ -864,8 +835,7 @@
<skip />
<!-- no translation found for power_notification_controls_description (4372459941671353358) -->
<skip />
- <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
- <skip />
+ <string name="notification_header_default_channel" msgid="7506845022070889909">"জাননীসমূহ"</string>
<!-- no translation found for notification_channel_disabled (344536703863700565) -->
<skip />
<!-- no translation found for inline_blocking_helper (3055064577771478591) -->
@@ -894,16 +864,11 @@
<skip />
<!-- no translation found for inline_undo (558916737624706010) -->
<skip />
- <!-- no translation found for notification_menu_accessibility (2046162834248888553) -->
- <skip />
- <!-- no translation found for notification_menu_gear_description (2204480013726775108) -->
- <skip />
- <!-- no translation found for notification_menu_snooze_description (3653669438131034525) -->
- <skip />
- <!-- no translation found for snooze_undo (6074877317002985129) -->
- <skip />
- <!-- no translation found for snoozed_for_time (2390718332980204462) -->
- <skip />
+ <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="notification_menu_gear_description" msgid="2204480013726775108">"জাননীৰ নিয়ন্ত্ৰণসমূহ"</string>
+ <string name="notification_menu_snooze_description" msgid="3653669438131034525">"জাননীক স্নুজ কৰাৰ বিকল্পসমূহ"</string>
+ <string name="snooze_undo" msgid="6074877317002985129">"আনডু কৰক"</string>
+ <string name="snoozed_for_time" msgid="2390718332980204462">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>ৰ বাবে স্নুজ কৰক"</string>
<!-- no translation found for snoozeHourOptions (2124335842674413030) -->
<!-- no translation found for snoozeMinuteOptions (4127251700591510196) -->
<!-- no translation found for battery_panel_title (7944156115535366613) -->
@@ -1028,24 +993,18 @@
<skip />
<!-- no translation found for nav_bar (1993221402773877607) -->
<skip />
- <!-- no translation found for nav_bar_layout (3664072994198772020) -->
- <skip />
- <!-- no translation found for left_nav_bar_button_type (8555981238887546528) -->
- <skip />
- <!-- no translation found for right_nav_bar_button_type (2481056627065649656) -->
- <skip />
- <!-- no translation found for nav_bar_default (8587114043070993007) -->
- <skip />
- <!-- no translation found for nav_bar_buttons:0 (1545641631806817203) -->
- <!-- no translation found for nav_bar_buttons:1 (5742013440802239414) -->
+ <string name="nav_bar_layout" msgid="3664072994198772020">"লেআউট"</string>
+ <string name="left_nav_bar_button_type" msgid="8555981238887546528">"বাওঁ বুটামৰ অতিৰিক্ত প্ৰকাৰ"</string>
+ <string name="right_nav_bar_button_type" msgid="2481056627065649656">"সোঁ বুটামৰ অতিৰিক্ত প্ৰকাৰ"</string>
+ <string name="nav_bar_default" msgid="8587114043070993007">"ডিফ\'ল্ট"</string>
<!-- no translation found for nav_bar_buttons:2 (1951959982985094069) -->
- <!-- no translation found for nav_bar_buttons:3 (8175437057325747277) -->
- <!-- no translation found for nav_bar_layouts:0 (8077901629964902399) -->
- <!-- no translation found for nav_bar_layouts:1 (8256205964297588988) -->
- <!-- no translation found for nav_bar_layouts:2 (8719936228094005878) -->
- <!-- no translation found for nav_bar_layouts:3 (586019486955594690) -->
- <!-- no translation found for menu_ime (4998010205321292416) -->
- <skip />
+ <string-array name="nav_bar_layouts">
+ <item msgid="8077901629964902399">"সাধাৰণ"</item>
+ <item msgid="8256205964297588988">"ঘন"</item>
+ <item msgid="8719936228094005878">"বাওঁফালে হালি যোৱা"</item>
+ <item msgid="586019486955594690">"সোঁফালে হালি যোৱা"</item>
+ </string-array>
+ <string name="menu_ime" msgid="4998010205321292416">"কীব\'ৰ্ড সলনি কৰাৰ সুবিধা"</string>
<!-- no translation found for save (2311877285724540644) -->
<skip />
<string name="reset" msgid="2448168080964209908">"ৰিছেট কৰক"</string>
@@ -1055,14 +1014,10 @@
<skip />
<!-- no translation found for accessibility_key (5701989859305675896) -->
<skip />
- <!-- no translation found for left_keycode (2010948862498918135) -->
- <skip />
- <!-- no translation found for right_keycode (708447961000848163) -->
- <skip />
- <!-- no translation found for left_icon (3096287125959387541) -->
- <skip />
- <!-- no translation found for right_icon (3952104823293824311) -->
- <skip />
+ <string name="left_keycode" msgid="2010948862498918135">"বাওঁ কীক\'ড"</string>
+ <string name="right_keycode" msgid="708447961000848163">"সোঁ কীক\'ড"</string>
+ <string name="left_icon" msgid="3096287125959387541">"বাওঁ আইকন"</string>
+ <string name="right_icon" msgid="3952104823293824311">"সোঁ আইকন"</string>
<!-- no translation found for drag_to_add_tiles (7058945779098711293) -->
<skip />
<!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
@@ -1149,22 +1104,18 @@
<skip />
<!-- no translation found for accessibility_quick_settings_page (5032979051755200721) -->
<skip />
- <!-- no translation found for tuner_lock_screen (5755818559638850294) -->
- <skip />
+ <string name="tuner_lock_screen" msgid="5755818559638850294">"লক স্ক্ৰীণ"</string>
<!-- no translation found for pip_phone_expand (5889780005575693909) -->
<skip />
- <!-- no translation found for pip_phone_minimize (1079119422589131792) -->
- <skip />
- <!-- no translation found for pip_phone_close (8416647892889710330) -->
- <skip />
+ <string name="pip_phone_minimize" msgid="1079119422589131792">"সৰু কৰক"</string>
+ <string name="pip_phone_close" msgid="8416647892889710330">"বন্ধ কৰক"</string>
<!-- no translation found for pip_phone_settings (8080777499521528521) -->
<skip />
<!-- no translation found for pip_phone_dismiss_hint (6351678169095923899) -->
<skip />
<!-- no translation found for pip_menu_title (4707292089961887657) -->
<skip />
- <!-- no translation found for pip_notification_title (3204024940158161322) -->
- <skip />
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> চিত্ৰৰ ভিতৰৰ চিত্ৰত আছে"</string>
<!-- no translation found for pip_notification_message (5619512781514343311) -->
<skip />
<!-- no translation found for pip_play (1417176722760265888) -->
@@ -1181,60 +1132,36 @@
<skip />
<!-- no translation found for thermal_shutdown_dialog_message (566347880005304139) -->
<skip />
- <!-- no translation found for high_temp_title (4589508026407318374) -->
- <skip />
- <!-- no translation found for high_temp_notif_message (5642466103153429279) -->
- <skip />
- <!-- no translation found for high_temp_dialog_message (6840700639374113553) -->
- <skip />
- <!-- no translation found for lockscreen_shortcut_left (2182769107618938629) -->
- <skip />
- <!-- no translation found for lockscreen_shortcut_right (3328683699505226536) -->
- <skip />
- <!-- no translation found for lockscreen_unlock_left (2043092136246951985) -->
- <skip />
- <!-- no translation found for lockscreen_unlock_right (1529992940510318775) -->
- <skip />
- <!-- no translation found for lockscreen_none (4783896034844841821) -->
- <skip />
- <!-- no translation found for tuner_launch_app (1527264114781925348) -->
- <skip />
- <!-- no translation found for tuner_other_apps (4726596850501162493) -->
- <skip />
- <!-- no translation found for tuner_circle (2340998864056901350) -->
- <skip />
- <!-- no translation found for tuner_plus (6792960658533229675) -->
- <skip />
- <!-- no translation found for tuner_minus (4806116839519226809) -->
- <skip />
- <!-- no translation found for tuner_left (8404287986475034806) -->
- <skip />
- <!-- no translation found for tuner_right (6222734772467850156) -->
- <skip />
- <!-- no translation found for tuner_menu (191640047241552081) -->
- <skip />
- <!-- no translation found for tuner_app (3507057938640108777) -->
- <skip />
- <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
- <skip />
+ <string name="high_temp_title" msgid="4589508026407318374">"ফ\'নটো গৰম হ\'বলৈ ধৰিছে"</string>
+ <string name="high_temp_notif_message" msgid="5642466103153429279">"ফ\'নটো ঠাণ্ডা হৈ থকা সময়ত কিছুমান সুবিধা উপলব্ধ নহ\'ব"</string>
+ <string name="high_temp_dialog_message" msgid="6840700639374113553">"আপোনাৰ ফ\'নটোৱে নিজে নিজে ঠাণ্ডা হ\'বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ফ\'নটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nফ\'নটো সম্পূৰ্ণভাৱে ঠাণ্ডা হোৱাৰ পিছত ই আগৰ নিচিনাকৈয়েই চলিব।"</string>
+ <string name="lockscreen_shortcut_left" msgid="2182769107618938629">"বাওঁ শ্বৰ্টকাট"</string>
+ <string name="lockscreen_shortcut_right" msgid="3328683699505226536">"সোঁ শ্বৰ্টকাট"</string>
+ <string name="lockscreen_unlock_left" msgid="2043092136246951985">"বাওঁ শ্বৰ্টকাটটোৱেও আনলক কৰিব"</string>
+ <string name="lockscreen_unlock_right" msgid="1529992940510318775">"সোঁ শ্বৰ্টকাটটোৱেও আনলক কৰিব"</string>
+ <string name="lockscreen_none" msgid="4783896034844841821">"একো বাছনি কৰা হোৱা নাই"</string>
+ <string name="tuner_launch_app" msgid="1527264114781925348">"<xliff:g id="APP">%1$s</xliff:g>ক লঞ্চ কৰক"</string>
+ <string name="tuner_other_apps" msgid="4726596850501162493">"অন্যান্য এপসমূহ"</string>
+ <string name="tuner_circle" msgid="2340998864056901350">"পৰিচিত মানুহৰ গোট"</string>
+ <string name="tuner_plus" msgid="6792960658533229675">"যোগ চিহ্ন"</string>
+ <string name="tuner_minus" msgid="4806116839519226809">"বিয়োগ চিহ্ন"</string>
+ <string name="tuner_left" msgid="8404287986475034806">"বাওঁ"</string>
+ <string name="tuner_right" msgid="6222734772467850156">"সোঁ"</string>
+ <string name="tuner_menu" msgid="191640047241552081">"মেনু"</string>
+ <string name="tuner_app" msgid="3507057938640108777">"<xliff:g id="APP">%1$s</xliff:g> এপ্"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"সতৰ্কবাণীসমূহ"</string>
<!-- no translation found for notification_channel_battery (5786118169182888462) -->
<skip />
- <!-- no translation found for notification_channel_screenshot (6314080179230000938) -->
- <skip />
- <!-- no translation found for notification_channel_general (4525309436693914482) -->
- <skip />
- <!-- no translation found for notification_channel_storage (3077205683020695313) -->
- <skip />
- <!-- no translation found for instant_apps (6647570248119804907) -->
- <skip />
- <!-- no translation found for instant_apps_message (8116608994995104836) -->
- <skip />
+ <string name="notification_channel_screenshot" msgid="6314080179230000938">"স্ক্ৰীণশ্বটসমূহ"</string>
+ <string name="notification_channel_general" msgid="4525309436693914482">"সাধাৰণ বার্তাসমূহ"</string>
+ <string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়াগাৰ"</string>
+ <string name="instant_apps" msgid="6647570248119804907">"তাৎক্ষণিক এপসমূহ"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"তাৎক্ষণিক এপসমূহক ইনষ্টল কৰাৰ প্ৰয়োজন নাই।"</string>
<!-- no translation found for app_info (6856026610594615344) -->
<skip />
<!-- no translation found for go_to_web (2650669128861626071) -->
<skip />
- <!-- no translation found for mobile_data (7094582042819250762) -->
- <skip />
+ <string name="mobile_data" msgid="7094582042819250762">"ম\'বাইল ডেটা"</string>
<!-- no translation found for wifi_is_off (1838559392210456893) -->
<skip />
<!-- no translation found for bt_is_off (2640685272289706392) -->
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 674d912..76b0c3f 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -537,6 +537,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s। নিঃশব্দ করতে ট্যাপ করুন।"</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s ভলিউম নিয়ন্ত্রণ"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"মিডিয়া আউটপুট"</string>
<string name="output_calls_title" msgid="8717692905017206161">"ফোন কল আউটপুট"</string>
<string name="output_none_found" msgid="5544982839808921091">"কোনও ডিভাইস খুঁজে পাওয়া যায়নি"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 3257983..5d63af8 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -542,6 +542,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Dodirnite da postavite vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Dodirnite da isključite zvuk."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"Kontrole glasnoće za %s"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Izlaz za medijske fajlove"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Izlaz za telefonske pozive"</string>
<string name="output_none_found" msgid="5544982839808921091">"Nije pronađen nijedan uređaj"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 619d54b..df2a74e 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -103,8 +103,7 @@
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
@@ -274,8 +273,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
<string name="start_dreams" msgid="5640361424498338327">"Screen saver"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Press & hold on the icons for more options"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
@@ -537,6 +535,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s volume controls"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Media output"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
<string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 64fb3d3..4c05e96 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -103,8 +103,7 @@
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
@@ -274,8 +273,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
<string name="start_dreams" msgid="5640361424498338327">"Screen saver"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Press & hold on the icons for more options"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
@@ -537,6 +535,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s volume controls"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Media output"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
<string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 619d54b..df2a74e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -103,8 +103,7 @@
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
@@ -274,8 +273,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
<string name="start_dreams" msgid="5640361424498338327">"Screen saver"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Press & hold on the icons for more options"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
@@ -537,6 +535,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s volume controls"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Media output"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
<string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 619d54b..df2a74e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -103,8 +103,7 @@
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
@@ -274,8 +273,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
<string name="start_dreams" msgid="5640361424498338327">"Screen saver"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Press & hold on the icons for more options"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
@@ -537,6 +535,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap to mute."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s volume controls"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Media output"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Phone call output"</string>
<string name="output_none_found" msgid="5544982839808921091">"No devices found"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 96fe4d7..3b9a49f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -103,8 +103,7 @@
<string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar diseño de tarea nueva"</string>
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor de huellas digitales"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icono de huella digital"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icono de aplicación"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área de mensaje de ayuda"</string>
@@ -276,8 +275,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Caja para postres"</string>
<string name="start_dreams" msgid="5640361424498338327">"Salvapantallas"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Mantén pulsados los iconos para ver más opciones"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molestar"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo prioritarias"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Solo alarmas"</string>
@@ -539,6 +537,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Toca para activar la vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Toca para silenciar."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"Controles de volumen %s"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Salida multimedia"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Salida de llamadas"</string>
<string name="output_none_found" msgid="5544982839808921091">"No se ha podido encontrar ningún dispositivo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 70d3a5b..9aae67f 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -105,8 +105,7 @@
<string name="camera_label" msgid="7261107956054836961">"פתח את המצלמה"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"בחר פריסה חדשה להצגת משימות"</string>
<string name="cancel" msgid="6442560571259935130">"ביטול"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"יש לגעת בחיישן טביעות האצבע"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"סמל טביעת אצבע"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"סמל אפליקציה"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"אזור הודעת עזרה"</string>
@@ -278,8 +277,7 @@
<string name="dessert_case" msgid="1295161776223959221">"מזנון קינוחים"</string>
<string name="start_dreams" msgid="5640361424498338327">"שומר מסך"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"יש להקיש על הסמלים ולהחזיק אותם להצגת אפשרויות נוספות"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"נא לא להפריע"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"עדיפות בלבד"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"התראות בלבד"</string>
@@ -543,6 +541,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. הקש כדי להעביר למצב רטט."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. הקש כדי להשתיק."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"בקרי עוצמת שמע של %s"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"פלט מדיה"</string>
<string name="output_calls_title" msgid="8717692905017206161">"פלט שיחת טלפון"</string>
<string name="output_none_found" msgid="5544982839808921091">"לא נמצאו מכשירים"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 476a9a7b..a35ccba 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -105,8 +105,7 @@
<string name="camera_label" msgid="7261107956054836961">"atidaryti fotoaparatą"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Pasirinkti naują užduoties išdėstymą"</string>
<string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Palieskite kontrolinio kodo jutiklį"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Kontrolinio kodo piktograma"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Programos piktograma"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Pagalbos pranešimo sritis"</string>
@@ -278,8 +277,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Desertų dėklas"</string>
<string name="start_dreams" msgid="5640361424498338327">"Ekrano užsklanda"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Eternetas"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Paspauskite ir palaikykite piktogramas, kad būtų parodyta daugiau parinkčių"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Netrukdyti"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tik prioritetiniai įvykiai"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Tik signalai"</string>
@@ -543,6 +541,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Palieskite, kad nustatytumėte vibravimą."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Palieskite, kad nutildytumėte."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"Garsumo valdikliai: %s"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Medijos išvestis"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Telefono skambučių išvestis"</string>
<string name="output_none_found" msgid="5544982839808921091">"Įrenginių nerasta"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 41d9a92..0e4d375 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -103,8 +103,7 @@
<string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"အလုပ်သစ်စီစဥ်မှုကို ရွေးပါ။"</string>
<string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"လက်ဗွေ သင်္ကေတ"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"အပလီကေးရှင်း သင်္ကေတ"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"အကူအညီမက်ဆေ့ဂျ် နေရာ"</string>
@@ -274,8 +273,7 @@
<string name="dessert_case" msgid="1295161776223959221">"မုန့်ထည့်သော ပုံး"</string>
<string name="start_dreams" msgid="5640361424498338327">"ဖန်သားပြင်အသုံးပြုမှု ချွေတာမှုစနစ်"</string>
<string name="ethernet_label" msgid="7967563676324087464">"အီသာနက်"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"နောက်ထပ် ရွေးချယ်စရာများအတွက် သင်္ကေတပုံများကို ဖိထားပါ"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"မနှောင့်ယှက်ရ"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ဦးစားပေးများသာ"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"နှိုးစက်များသာ"</string>
@@ -537,6 +535,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s။ အသံတိတ်ရန် တို့ပါ။"</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"%s အသံအတိုးအလျှော့ ခလုတ်များ"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"မီဒီယာ အထွက်"</string>
<string name="output_calls_title" msgid="8717692905017206161">"ဖုန်းလိုင်း အထွက်"</string>
<string name="output_none_found" msgid="5544982839808921091">"မည်သည့် စက်ပစ္စည်းမျှ မတွေ့ပါ"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3d8fa3a..c35c8a7 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -23,8 +23,7 @@
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"ଖାଲି କରନ୍ତୁ"</string>
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"ତାଲିକାରୁ ବାହାର କରନ୍ତୁ"</string>
<string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ଆପ୍ ସୂଚନା"</string>
- <!-- no translation found for status_bar_no_recent_apps (7374907845131203189) -->
- <skip />
+ <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"ଆପଣଙ୍କ ସମ୍ପ୍ରତି ସ୍କ୍ରୀନ୍ ଏଠାରେ ଦେଖାଯାଉଛି"</string>
<string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"କିଛି ସମୟ ପୂର୍ବରୁ ଇନଷ୍ଟଲ୍ ହୋଇଥିବା ଆପ୍ଗୁଡ଼ିକୁ ଖାରଜ କରନ୍ତୁ"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
<item quantity="other">ଓଭର୍ଭ୍ୟୁରେ %d ସ୍କ୍ରୀନ୍</item>
@@ -36,8 +35,7 @@
<string name="battery_low_title" msgid="6456385927409742437">"ବ୍ୟାଟେରୀ କମ୍ ଅଛି"</string>
<!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
<skip />
- <!-- no translation found for battery_low_percent_format (2900940511201380775) -->
- <skip />
+ <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବାକି ଅଛି"</string>
<!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
<skip />
<!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
@@ -50,8 +48,7 @@
<string name="battery_low_why" msgid="4553600287639198111">"ସେଟିଙ୍ଗ"</string>
<!-- no translation found for battery_saver_confirmation_title (2052100465684817154) -->
<skip />
- <!-- no translation found for battery_saver_confirmation_ok (7507968430447930257) -->
- <skip />
+ <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ଅନ୍ କରନ୍ତୁ"</string>
<!-- no translation found for battery_saver_start_action (8187820911065797519) -->
<skip />
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ସେଟିଙ୍ଗ"</string>
@@ -81,8 +78,7 @@
<string name="usb_debugging_title" msgid="4513918393387141949">"USB ଡିବଗିଙ୍ଗ କରିବେ?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"କମ୍ପ୍ୟୁଟର୍ର RSA କୀ\' ଆଙ୍ଗୁଠି ଚିହ୍ନ ହେଉଛି:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"ସବୁବେଳେ ଏହି କମ୍ପ୍ୟୁଟର୍ରୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
- <!-- no translation found for usb_debugging_secondary_user_title (6353808721761220421) -->
- <skip />
+ <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"USBରେ ଡିବଗ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<!-- no translation found for usb_debugging_secondary_user_message (6067122453571699801) -->
<skip />
<string name="compat_mode_on" msgid="6623839244840638213">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
@@ -116,29 +112,21 @@
<skip />
<!-- no translation found for accessibility_rotate_button (7402949513740253006) -->
<skip />
- <!-- no translation found for accessibility_recent (5208608566793607626) -->
- <skip />
+ <string name="accessibility_recent" msgid="5208608566793607626">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"କ୍ୟାମେରା"</string>
<string name="accessibility_phone_button" msgid="6738112589538563574">"ଫୋନ୍"</string>
- <!-- no translation found for accessibility_voice_assist_button (487611083884852965) -->
- <skip />
- <!-- no translation found for accessibility_unlock_button (128158454631118828) -->
- <skip />
+ <string name="accessibility_voice_assist_button" msgid="487611083884852965">"ଭଏସ୍ ସହାୟକ"</string>
+ <string name="accessibility_unlock_button" msgid="128158454631118828">"ଅନଲକ୍ କରନ୍ତୁ"</string>
<!-- no translation found for accessibility_waiting_for_fingerprint (4808860050517462885) -->
<skip />
<!-- no translation found for accessibility_unlock_without_fingerprint (7541705575183694446) -->
<skip />
- <!-- no translation found for unlock_label (8779712358041029439) -->
- <skip />
- <!-- no translation found for phone_label (2320074140205331708) -->
- <skip />
- <!-- no translation found for voice_assist_label (3956854378310019854) -->
- <skip />
- <!-- no translation found for camera_label (7261107956054836961) -->
- <skip />
- <!-- no translation found for recents_caption_resize (3517056471774958200) -->
- <skip />
+ <string name="unlock_label" msgid="8779712358041029439">"ଅନଲକ୍"</string>
+ <string name="phone_label" msgid="2320074140205331708">"ଫୋନ୍ ଖୋଲନ୍ତୁ"</string>
+ <string name="voice_assist_label" msgid="3956854378310019854">"ଭଏସ୍ ସହାୟକ ଖୋଲନ୍ତୁ"</string>
+ <string name="camera_label" msgid="7261107956054836961">"କ୍ୟାମେରା ଖୋଲନ୍ତୁ"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"ନୂଆ ଟାସ୍କ ଲେଆଉଟ୍ ଚୟନ କରନ୍ତୁ"</string>
<string name="cancel" msgid="6442560571259935130">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
<!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
<skip />
@@ -167,10 +155,8 @@
<string name="accessibility_data_two_bars" msgid="6166018492360432091">"ଡାଟାର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_data_three_bars" msgid="9167670452395038520">"ଡାଟାର ତିନୋଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_data_signal_full" msgid="2708384608124519369">"ଡାଟା ସିଗ୍ନାଲ୍ ପୂର୍ଣ୍ଣ ଅଛି।"</string>
- <!-- no translation found for accessibility_wifi_name (7202151365171148501) -->
- <skip />
- <!-- no translation found for accessibility_bluetooth_name (8441517146585531676) -->
- <skip />
+ <string name="accessibility_wifi_name" msgid="7202151365171148501">"<xliff:g id="WIFI">%s</xliff:g> ସହିତ ସଂଯୁକ୍ତ।"</string>
+ <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string>
<!-- no translation found for accessibility_cast_name (4026393061247081201) -->
<skip />
<string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX ନାହିଁ।"</string>
@@ -178,10 +164,8 @@
<string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAXର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAXର ତିନୋଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAXର ସିଗ୍ନାଲ୍ ସମ୍ପୂର୍ଣ୍ଣ ଅଛି।"</string>
- <!-- no translation found for accessibility_ethernet_disconnected (5896059303377589469) -->
- <skip />
- <!-- no translation found for accessibility_ethernet_connected (2692130313069182636) -->
- <skip />
+ <string name="accessibility_ethernet_disconnected" msgid="5896059303377589469">"ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ ହୋଇଛି।"</string>
+ <string name="accessibility_ethernet_connected" msgid="2692130313069182636">"ଇଥରନେଟ୍ ସଂଯୁକ୍ତ ହୋଇଛି।"</string>
<string name="accessibility_no_signal" msgid="7064645320782585167">"କୌଣସି ସିଗ୍ନାଲ୍ ନାହିଁ।"</string>
<string name="accessibility_not_connected" msgid="6395326276213402883">"ସଂଯୁକ୍ତ ହୋଇନାହିଁ।"</string>
<string name="accessibility_zero_bars" msgid="3806060224467027887">"କୌଣସି ବାର୍ ନାହିଁ।"</string>
@@ -221,8 +205,7 @@
<skip />
<!-- no translation found for accessibility_no_sims (3957997018324995781) -->
<skip />
- <!-- no translation found for accessibility_carrier_network_change_mode (4017301580441304305) -->
- <skip />
+ <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"କେରିଅର୍ ନେଟ୍ୱର୍କ ବଦଳାଯାଉଛି।"</string>
<!-- no translation found for accessibility_battery_details (7645516654955025422) -->
<skip />
<string name="accessibility_battery_level" msgid="7451474187113371965">"ବ୍ୟାଟେରୀ <xliff:g id="NUMBER">%d</xliff:g> ଶତକଡ଼ା ଅଛି।"</string>
@@ -242,107 +225,65 @@
<skip />
<!-- no translation found for accessibility_work_mode (702887484664647430) -->
<skip />
- <!-- no translation found for accessibility_recents_item_will_be_dismissed (395770242498031481) -->
- <skip />
+ <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ଖାରଜ।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ଖାରଜ କରିଦିଆଗଲା।"</string>
- <!-- no translation found for accessibility_recents_all_items_dismissed (4464697366179168836) -->
- <skip />
+ <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ସମସ୍ତ ସମ୍ପ୍ରତି ଆପ୍ଲିକେଶନଗୁଡ଼ିକ ଖାରଜ କରାଯାଇଛି।"</string>
<!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
<skip />
- <!-- no translation found for accessibility_recents_item_launched (7616039892382525203) -->
- <skip />
+ <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ଆରମ୍ଭ ହେଉଛି।"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା।"</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ଦ୍ରୁତ ସେଟିଙ୍ଗ।"</string>
- <!-- no translation found for accessibility_desc_lock_screen (5625143713611759164) -->
- <skip />
- <!-- no translation found for accessibility_desc_settings (3417884241751434521) -->
- <skip />
- <!-- no translation found for accessibility_desc_recent_apps (4876900986661819788) -->
- <skip />
+ <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string>
+ <string name="accessibility_desc_settings" msgid="3417884241751434521">"ସେଟିଙ୍ଗ"</string>
+ <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀ"</string>
<!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
<skip />
- <!-- no translation found for accessibility_desc_close (7479755364962766729) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_wifi (5518210213118181692) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_wifi_changed_off (8716484460897819400) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_wifi_changed_on (6440117170789528622) -->
- <skip />
+ <string name="accessibility_desc_close" msgid="7479755364962766729">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
+ <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ୱାଇ-ଫାଇ ବନ୍ଦ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"ୱାଇ-ଫାଇ ଅନ୍ ଅଛି।"</string>
<string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"ମୋବାଇଲ୍ <xliff:g id="SIGNAL">%1$s</xliff:g>। <xliff:g id="TYPE">%2$s</xliff:g>। <xliff:g id="NETWORK">%3$s</xliff:g>।"</string>
<string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"<xliff:g id="STATE">%s</xliff:g> ବ୍ୟାଟେରୀ ଅଛି।"</string>
- <!-- no translation found for accessibility_quick_settings_airplane_off (7786329360056634412) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_on (6406141469157599296) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_changed_off (66846307818850664) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_changed_on (8983005603505087728) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_priority_on (1448402297221249355) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_none_on (6882582132662613537) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_alarms_on (9152834845587554157) -->
- <skip />
+ <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍ ଅଫ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍ ଅନ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍କୁ ବନ୍ଦ କରାଯାଇଛି।"</string>
+ <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ଏୟାର୍ପ୍ଲେନ୍ ମୋଡ୍କୁ ଚାଲୁ କରାଯାଇଛି।"</string>
+ <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ ଅଛି, କେବଳ ଗୁରୁତ୍ୱର୍ଣ୍ଣ।"</string>
+ <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ ଅଛି, ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ।"</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ ଅଛି, କେବଳ ଆଲାର୍ମ।"</string>
<!-- no translation found for accessibility_quick_settings_dnd (6607873236717185815) -->
<skip />
- <!-- no translation found for accessibility_quick_settings_dnd_off (2371832603753738581) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_changed_off (898107593453022935) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_changed_on (4483780856613561039) -->
- <skip />
+ <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅଫ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅଫ୍ କରାଯାଇଛି।"</string>
+ <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରଯାଇଛି।"</string>
<!-- no translation found for accessibility_quick_settings_bluetooth (6341675755803320038) -->
<skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_off (2133631372372064339) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_on (7681999166216621838) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_connecting (6953242966685343855) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_connected (4306637793614573659) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_changed_off (2730003763480934529) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_changed_on (8722351798763206577) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_off (5119080556976115520) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_on (5809937096590102036) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_changed_off (8526845571503387376) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_changed_on (339403053079338468) -->
- <skip />
+ <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ବ୍ଲୁ-ଟୂଥ୍ ଅଫ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ବ୍ଲୁ-ଟୁଥ୍ ଅନ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ବ୍ଲୁ-ଟୁଥ୍ ସଂଯୋଗ ହେଉଛି।"</string>
+ <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"ବ୍ଲୁ-ଟୁଥ୍କୁ ସଂଯୋଗ କରାଯାଇଛି।"</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"ବ୍ଲୁ-ଟୁଥ୍କୁ ବନ୍ଦ କରିଦିଆଯାଇଛି।"</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"ବ୍ଲୁ-ଟୁଥ୍କୁ ଚାଲୁ କରାଯାଇଛି।"</string>
+ <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"ଲୋକେଶନ୍ର ତଥ୍ୟ ବନ୍ଦ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"ଲୋକେଶନ୍ର ତଥ୍ୟ ଅନ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"ଲୋକେଶନ୍ର ରିପୋର୍ଟ ବନ୍ଦ କରାଗଲା।"</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"ଲୋକେଶନ୍ର ରିପୋର୍ଟ ଅନ୍ କରାଗଲା।"</string>
<string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"<xliff:g id="TIME">%s</xliff:g>ରେ ଆଲାର୍ମ ସେଟ୍ କରାଯାଇଛି।"</string>
- <!-- no translation found for accessibility_quick_settings_close (3115847794692516306) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_more_time (3659274935356197708) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_less_time (2404728746293515623) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_off (4936432000069786988) -->
- <skip />
+ <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"ପ୍ୟାନେଲ୍ ବନ୍ଦ କରନ୍ତୁ।"</string>
+ <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ଅଧିକ ସମୟ।"</string>
+ <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"କମ୍ ସମୟ।"</string>
+ <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ଫ୍ଲାଶ୍ଲାଇଟ୍ ଅଫ୍ ଅଛି।"</string>
<!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
<skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_on (2003479320007841077) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_changed_off (3303701786768224304) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_changed_on (6531793301533894686) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_color_inversion_changed_off (4406577213290173911) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_color_inversion_changed_on (6897462320184911126) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_hotspot_changed_off (5004708003447561394) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_hotspot_changed_on (2890951609226476206) -->
- <skip />
- <!-- no translation found for accessibility_casting_turned_off (1430668982271976172) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ଫ୍ଲାଶ୍ଲାଇଟ୍ ଅନ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ଟର୍ଚ୍ଚ ଲାଇଟ୍ ବନ୍ଦ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ଟର୍ଚ୍ଚ ଲାଇଟ୍ ଅନ୍ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"ରଙ୍ଗ ବିପରୀତିକରଣକୁ ବନ୍ଦ କରିଦିଆଗଲା।"</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"ରଙ୍ଗ ବିପରୀତିକରଣକୁ ଚାଲୁ କରିଦିଆଗଲା।"</string>
+ <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"ମୋବାଇଲ୍ ହଟସ୍ପଟ୍ ବନ୍ଦ ଅଛି।"</string>
+ <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ମୋବାଇଲ୍ ହଟସ୍ପଟ୍ ଅନ୍ ଅଛି।"</string>
+ <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ସ୍କ୍ରୀନ୍ କାଷ୍ଟ କରିବା ରହିଯାଇଛି।"</string>
<!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
<skip />
<!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
@@ -355,22 +296,17 @@
<skip />
<!-- no translation found for accessibility_quick_settings_data_saver_changed_on (4218725402373934151) -->
<skip />
- <!-- no translation found for accessibility_brightness (8003681285547803095) -->
- <skip />
+ <string name="accessibility_brightness" msgid="8003681285547803095">"ଡିସ୍ପ୍ଲେ ଉଜ୍ଜ୍ୱଳତା"</string>
<!-- no translation found for accessibility_ambient_display_charging (9084521679384069087) -->
<skip />
- <!-- no translation found for data_usage_disabled_dialog_3g_title (5281770593459841889) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_4g_title (1601769736881078016) -->
- <skip />
+ <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
+ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
<!-- no translation found for data_usage_disabled_dialog_mobile_title (6801382439018099779) -->
<skip />
- <!-- no translation found for data_usage_disabled_dialog_title (3932437232199671967) -->
- <skip />
+ <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ଡାଟା ପଜ୍ କରାଯାଇଛି"</string>
<!-- no translation found for data_usage_disabled_dialog (4919541636934603816) -->
<skip />
- <!-- no translation found for data_usage_disabled_dialog_enable (1412395410306390593) -->
- <skip />
+ <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ଖୋଜାଯାଉଛି"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS ଦ୍ୱାରା ଲୋକେଶନ୍ ସେଟ୍ କରାଯାଇଛି"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ଲୋକେଶନ୍ ଅନୁରୋଧ ସକ୍ରିୟ ଅଛି"</string>
@@ -378,33 +314,24 @@
<!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
<skip />
<!-- no translation found for notification_group_overflow_description (4579313201268495404) -->
- <!-- no translation found for status_bar_notification_inspect_item_title (5668348142410115323) -->
- <skip />
- <!-- no translation found for status_bar_notification_app_settings_title (5525260160341558869) -->
- <skip />
+ <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ବିଜ୍ଞପ୍ତି ସେଟିଙ୍ଗ"</string>
+ <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ସେଟିଙ୍ଗ"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ସ୍କ୍ରୀନ୍ ସ୍ୱଚାଳିତ ଭାବେ ବୁଲିବ।"</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ଲ୍ୟାଣ୍ଡସ୍କେପ୍ ଅବସ୍ଥାରେ ସ୍କ୍ରୀନ୍କୁ ଲକ୍ କରାଯାଇଛି।"</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ପୋର୍ଟ୍ରେଟ୍ ଅବସ୍ଥାରେ ସ୍କ୍ରୀନ୍କୁ ଲକ୍ କରାଯାଇଛି।"</string>
- <!-- no translation found for accessibility_rotation_lock_off_changed (8134601071026305153) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape_changed (3135965553707519743) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait_changed (8922481981834012126) -->
- <skip />
+ <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"ସ୍କ୍ରୀନ୍ ବର୍ତ୍ତମାନ ସ୍ୱଚାଳିତ ଭାବେ ବୁଲିବ।"</string>
+ <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"ବର୍ତ୍ତମାନ ସ୍କ୍ରୀନ୍ଟି ଲ୍ୟାଣ୍ଡସ୍କେପ୍ ଦିଗରେ ଲକ୍ ଅଛି।"</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"ବର୍ତ୍ତମାନ ସ୍କ୍ରୀନ୍ଟି ପୋର୍ଟେଟ୍ ଦିଗରେ ଲକ୍ ଅଛି।"</string>
<string name="dessert_case" msgid="1295161776223959221">"ଡେଜର୍ଟ କେସ୍"</string>
<!-- no translation found for start_dreams (5640361424498338327) -->
<skip />
<string name="ethernet_label" msgid="7967563676324087464">"ଇଥରନେଟ୍"</string>
<!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
<skip />
- <!-- no translation found for quick_settings_dnd_label (8735855737575028208) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_priority_label (483232950670692036) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_alarms_label (2559229444312445858) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_none_label (5025477807123029478) -->
- <skip />
+ <string name="quick_settings_dnd_label" msgid="8735855737575028208">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\""</string>
+ <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"କେବଳ ପ୍ରାଥମିକତା"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"କେବଳ ଆଲାର୍ମ"</string>
+ <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ବ୍ଲୁ-ଟୁଥ୍"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ବ୍ଲୁ-ଟୁଥ୍ (<xliff:g id="NUMBER">%d</xliff:g>ଟି ଡିଭାଇସ୍)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ବ୍ଲୁ-ଟୁଥ୍ ଅଫ୍"</string>
@@ -443,16 +370,13 @@
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ୱାଇ-ଫାଇ ଅଫ୍"</string>
<!-- no translation found for quick_settings_wifi_on_label (7607810331387031235) -->
<skip />
- <!-- no translation found for quick_settings_wifi_detail_empty_text (269990350383909226) -->
- <skip />
+ <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"କୌଣସି ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
<!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
<skip />
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"କାଷ୍ଟ"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"କାଷ୍ଟିଙ୍ଗ"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ନାମହୀନ ଡିଭାଇସ୍"</string>
- <!-- no translation found for quick_settings_cast_device_default_description (2484573682378634413) -->
- <skip />
+ <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"କାଷ୍ଟ୍ ପାଇଁ ପ୍ରସ୍ତୁତ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ଉଜ୍ଜ୍ୱଳତା"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ସ୍ୱଚାଳିତ"</string>
@@ -504,23 +428,18 @@
<!-- no translation found for recents_empty_message_dismissed_all (2791312568666558651) -->
<skip />
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ଆପ୍ଲିକେଶନ୍ ସୂଚନା"</string>
- <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
- <skip />
+ <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ସ୍କ୍ରୀନ୍ ଲକ୍"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
- <!-- no translation found for recents_launch_error_message (2969287838120550506) -->
- <skip />
+ <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> କୁ ଆରମ୍ଭ କରାଯାଇପାରିଲା ନାହିଁ।"</string>
<!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
<skip />
<!-- no translation found for recents_stack_action_button_label (6593727103310426253) -->
<skip />
<!-- no translation found for recents_drag_hint_message (2649739267073203985) -->
<skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_horizontal (8848514474543427332) -->
- <skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_vertical (9075292233696180813) -->
- <skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_custom (4177837597513701943) -->
- <skip />
+ <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ଭୂସମାନ୍ତର ଭାବରେ ଭାଗ କରନ୍ତୁ"</string>
+ <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ଭୂଲମ୍ବ ଭାବରେ ଭାଗ କରନ୍ତୁ"</string>
+ <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"କଷ୍ଟମ୍ କରି ଭାଗ କରନ୍ତୁ"</string>
<!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
<skip />
<!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
@@ -539,8 +458,7 @@
<skip />
<!-- no translation found for zen_alarms_introduction (4934328096749380201) -->
<skip />
- <!-- no translation found for zen_priority_customize_button (7948043278226955063) -->
- <skip />
+ <string name="zen_priority_customize_button" msgid="7948043278226955063">"କଷ୍ଟମାଇଜ୍ କରନ୍ତୁ"</string>
<!-- no translation found for zen_silence_introduction_voice (3948778066295728085) -->
<skip />
<!-- no translation found for zen_silence_introduction (3137882381093271568) -->
@@ -553,76 +471,51 @@
<skip />
<!-- no translation found for do_disclosure_with_name (5640615509915445501) -->
<skip />
- <!-- no translation found for phone_hint (4872890986869209950) -->
- <skip />
- <!-- no translation found for voice_hint (8939888732119726665) -->
- <skip />
- <!-- no translation found for camera_hint (7939688436797157483) -->
- <skip />
+ <string name="phone_hint" msgid="4872890986869209950">"ଫୋନ୍ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"ଭଏସ୍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="camera_hint" msgid="7939688436797157483">"କ୍ୟାମେରା ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<!-- no translation found for interruption_level_none_with_warning (5114872171614161084) -->
<skip />
- <!-- no translation found for interruption_level_none (6000083681244492992) -->
- <skip />
- <!-- no translation found for interruption_level_priority (6426766465363855505) -->
- <skip />
- <!-- no translation found for interruption_level_alarms (5226306993448328896) -->
- <skip />
- <!-- no translation found for interruption_level_none_twoline (3957581548190765889) -->
- <skip />
- <!-- no translation found for interruption_level_priority_twoline (1564715335217164124) -->
- <skip />
- <!-- no translation found for interruption_level_alarms_twoline (3266909566410106146) -->
- <skip />
+ <string name="interruption_level_none" msgid="6000083681244492992">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ"</string>
+ <string name="interruption_level_priority" msgid="6426766465363855505">"କେବଳ ପ୍ରାଥମିକତା"</string>
+ <string name="interruption_level_alarms" msgid="5226306993448328896">"କେବଳ ଆଲାର୍ମ"</string>
+ <string name="interruption_level_none_twoline" msgid="3957581548190765889">"ସମ୍ପୂର୍ଣ୍ଣ\nନୀରବ"</string>
+ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"କେବଳ\nପ୍ରାଥମିକତା"</string>
+ <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"କେବଳ\nଆଲାର୍ମ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ଚାର୍ଜ କରାଯାଉଛି (ପୂର୍ଣ୍ଣ ହେବାକୁ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ରହିଛି)"</string>
<!-- no translation found for keyguard_indication_charging_time_fast (9018981952053914986) -->
<skip />
<!-- no translation found for keyguard_indication_charging_time_slowly (955252797961724952) -->
<skip />
- <!-- no translation found for accessibility_multi_user_switch_switcher (7305948938141024937) -->
- <skip />
- <!-- no translation found for accessibility_multi_user_switch_switcher_with_current (8434880595284601601) -->
- <skip />
+ <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ୟୁଜର୍ ବଦଳାନ୍ତୁ"</string>
+ <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ୟୁଜର୍ ବଦଳାନ୍ତୁ, ବର୍ତ୍ତମାନର ୟୁଜର୍ ହେଉଛନ୍ତି <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<!-- no translation found for accessibility_multi_user_switch_inactive (1424081831468083402) -->
<skip />
- <!-- no translation found for accessibility_multi_user_switch_quick_contact (3020367729287990475) -->
- <skip />
- <!-- no translation found for user_add_user (5110251524486079492) -->
- <skip />
- <!-- no translation found for user_new_user_name (426540612051178753) -->
- <skip />
+ <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"ପ୍ରୋଫାଇଲ୍ ଦେଖାନ୍ତୁ"</string>
+ <string name="user_add_user" msgid="5110251524486079492">"ୟୁଜର୍ଙ୍କୁ ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="user_new_user_name" msgid="426540612051178753">"ନୂତନ ୟୁଜର୍"</string>
<string name="guest_nickname" msgid="8059989128963789678">"ଅତିଥି"</string>
- <!-- no translation found for guest_new_guest (600537543078847803) -->
- <skip />
- <!-- no translation found for guest_exit_guest (7187359342030096885) -->
- <skip />
- <!-- no translation found for guest_exit_guest_dialog_title (8480693520521766688) -->
- <skip />
- <!-- no translation found for guest_exit_guest_dialog_message (4155503224769676625) -->
- <skip />
- <!-- no translation found for guest_exit_guest_dialog_remove (7402231963862520531) -->
- <skip />
- <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
- <skip />
- <!-- no translation found for guest_wipe_session_message (8476238178270112811) -->
- <skip />
- <!-- no translation found for guest_wipe_session_wipe (5065558566939858884) -->
- <skip />
- <!-- no translation found for guest_wipe_session_dontwipe (1401113462524894716) -->
- <skip />
- <!-- no translation found for guest_notification_title (1585278533840603063) -->
- <skip />
+ <string name="guest_new_guest" msgid="600537543078847803">"ଅତିଥି ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="guest_exit_guest" msgid="7187359342030096885">"ଅତିଥିଙ୍କୁ କାଢ଼ନ୍ତୁ"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"ଅତିଥିଙ୍କୁ କାଢ଼ିଦେବେ?"</string>
+ <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"ଏହି ଅବଧିର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
+ <string name="guest_wipe_session_title" msgid="6419439912885956132">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string>
+ <string name="guest_wipe_session_message" msgid="8476238178270112811">"ଆପଣ ନିଜର ଅବଧି ଜାରି ରଖିବାକୁ ଚାହାନ୍ତି କି?"</string>
+ <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
+ <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"ହଁ, ଜାରି ରଖନ୍ତୁ"</string>
+ <string name="guest_notification_title" msgid="1585278533840603063">"ଅତିଥି ୟୁଜର୍"</string>
<!-- no translation found for guest_notification_text (335747957734796689) -->
<skip />
- <!-- no translation found for guest_notification_remove_action (8820670703892101990) -->
- <skip />
+ <string name="guest_notification_remove_action" msgid="8820670703892101990">"ଅତିଥିଙ୍କୁ ବାହାର କରନ୍ତୁ"</string>
<!-- no translation found for user_logout_notification_title (1453960926437240727) -->
<skip />
<!-- no translation found for user_logout_notification_text (3350262809611876284) -->
<skip />
<!-- no translation found for user_logout_notification_action (1195428991423425062) -->
<skip />
- <string name="user_add_user_title" msgid="4553596395824132638">"ନୂତନ ଉପଯୋଗକର୍ତ୍ତା ଯୋଡିବେ?"</string>
- <string name="user_add_user_message_short" msgid="2161624834066214559">"ଜଣେ ନୂଆ ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଡ଼ିବାବେଳେ, ସେହି ବ୍ୟକ୍ତିଙ୍କୁ ସ୍ଥାନ ସେଟ୍ କରିବାକୁ ପଡ଼ିବ।\n\nଅନ୍ୟ ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଯେକୌଣସି ଉପଯୋଗକର୍ତ୍ତା ଆପ୍ଗୁଡ଼ିକୁ ଅପ୍ଡେଟ୍ କରିପାରିବେ।"</string>
+ <string name="user_add_user_title" msgid="4553596395824132638">"ନୂତନ ୟୁଜର୍ ଯୋଡ଼ିବେ?"</string>
+ <string name="user_add_user_message_short" msgid="2161624834066214559">"ଜଣେ ନୂଆ ୟୁଜର୍ଙ୍କୁ ଯୋଡ଼ିବାବେଳେ, ସେହି ବ୍ୟକ୍ତିଙ୍କୁ ସ୍ଥାନ ସେଟ୍ କରିବାକୁ ପଡ଼ିବ। \n \n ଅନ୍ୟ ସମସ୍ତ ୟୁଜର୍ଙ୍କ ପାଇଁ ଯେକୌଣସି ୟୁଜର୍ ଆପ୍ଗୁଡ଼ିକୁ ଅପଡେଟ୍ କରିପାରିବେ।"</string>
<!-- no translation found for user_remove_user_title (4681256956076895559) -->
<skip />
<!-- no translation found for user_remove_user_message (1453218013959498039) -->
@@ -631,24 +524,16 @@
<skip />
<!-- no translation found for battery_saver_notification_title (8614079794522291840) -->
<skip />
- <!-- no translation found for battery_saver_notification_text (820318788126672692) -->
- <skip />
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"କାର୍ଯ୍ୟ ସମ୍ପାଦନ ଓ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଡାଟା କମ୍ କରନ୍ତୁ"</string>
<!-- no translation found for battery_saver_notification_action_text (132118784269455533) -->
<skip />
- <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
- <skip />
- <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
- <skip />
- <!-- no translation found for clear_all_notifications_text (814192889771462828) -->
- <skip />
- <!-- no translation found for media_projection_action_text (8470872969457985954) -->
- <skip />
- <!-- no translation found for empty_shade_text (708135716272867002) -->
- <skip />
- <!-- no translation found for profile_owned_footer (8021888108553696069) -->
- <skip />
- <!-- no translation found for vpn_footer (2388611096129106812) -->
- <skip />
+ <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ରେ ପ୍ରଦର୍ଶିତ ହେଉଥିବା ସମସ୍ତ ବସ୍ତୁକୁ କ୍ୟାପଚର୍ କରିବା ଆରମ୍ଭ ହୋଇଯିବ।"</string>
+ <string name="media_projection_remember_text" msgid="3103510882172746752">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
+ <string name="clear_all_notifications_text" msgid="814192889771462828">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string>
+ <string name="media_projection_action_text" msgid="8470872969457985954">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
+ <string name="empty_shade_text" msgid="708135716272867002">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
+ <string name="profile_owned_footer" msgid="8021888108553696069">"ପ୍ରୋଫାଇଲ୍ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ।"</string>
+ <string name="vpn_footer" msgid="2388611096129106812">"ନେଟ୍ୱର୍କ ନୀରିକ୍ଷଣ କରାଯାଇପାରେ"</string>
<!-- no translation found for branded_vpn_footer (2168111859226496230) -->
<skip />
<!-- no translation found for quick_settings_disclosure_management_monitoring (6645176135063957394) -->
@@ -683,20 +568,16 @@
<skip />
<!-- no translation found for monitoring_title_device_owned (1652495295941959815) -->
<skip />
- <!-- no translation found for monitoring_title_profile_owned (6790109874733501487) -->
- <skip />
- <!-- no translation found for monitoring_title (169206259253048106) -->
- <skip />
+ <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ପ୍ରୋଫାଇଲ୍ ନୀରିକ୍ଷଣ"</string>
+ <string name="monitoring_title" msgid="169206259253048106">"ନେଟ୍ୱର୍କ ନୀରିକ୍ଷଣ"</string>
<!-- no translation found for monitoring_subtitle_vpn (876537538087857300) -->
<skip />
<!-- no translation found for monitoring_subtitle_network_logging (3341264304793193386) -->
<skip />
<!-- no translation found for monitoring_subtitle_ca_certificate (3874151893894355988) -->
<skip />
- <!-- no translation found for disable_vpn (4435534311510272506) -->
- <skip />
- <!-- no translation found for disconnect_vpn (1324915059568548655) -->
- <skip />
+ <string name="disable_vpn" msgid="4435534311510272506">"VPN ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ବିଛିନ୍ନ କରନ୍ତୁ"</string>
<!-- no translation found for monitoring_button_view_policies (100913612638514424) -->
<skip />
<!-- no translation found for monitoring_description_named_management (5281789135578986303) -->
@@ -741,12 +622,10 @@
<skip />
<!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
<skip />
- <!-- no translation found for monitoring_description_vpn (4445150119515393526) -->
- <skip />
+ <string name="monitoring_description_vpn" msgid="4445150119515393526">"ଏକ VPN ସଂଯୋଗ ସେଟ୍ ଅପ୍ କରିବା ପାଇଁ ଆପଣ ଗୋଟିଏ ଆପକୁ ଅନୁମତି ଦେଲେ।\n\nଏହି ଆପ୍ ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଓ ନେଟ୍ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
<skip />
- <!-- no translation found for legacy_vpn_name (6604123105765737830) -->
- <skip />
+ <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<!-- no translation found for monitoring_description_app (1828472472674709532) -->
<skip />
<!-- no translation found for monitoring_description_app_personal (484599052118316268) -->
@@ -761,28 +640,19 @@
<skip />
<!-- no translation found for keyguard_indication_trust_managed (8319646760022357585) -->
<skip />
- <!-- no translation found for keyguard_indication_trust_disabled (7412534203633528135) -->
- <skip />
- <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
- <skip />
- <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
- <skip />
- <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
- <skip />
- <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
- <skip />
- <!-- no translation found for zen_mode_and_condition (4462471036429759903) -->
- <skip />
+ <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ଯେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଆପଣ ମାନୁଆଲୀ ଅନଲକ୍ କରିନାହାନ୍ତି, ସେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଡିଭାଇସ୍ ଲକ୍ ରହିବ"</string>
+ <string name="hidden_notifications_title" msgid="7139628534207443290">"ବିଜ୍ଞପ୍ତିକୁ ଶୀଘ୍ର ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+ <string name="hidden_notifications_text" msgid="2326409389088668981">"ଅନଲକ୍ କରିବା ପୁର୍ବରୁ ସେମାନଙ୍କୁ ଦେଖନ୍ତୁ"</string>
+ <string name="hidden_notifications_cancel" msgid="3690709735122344913">"ନାହିଁ, ଥାଉ"</string>
+ <string name="hidden_notifications_setup" msgid="41079514801976810">"ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
+ <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<!-- no translation found for volume_zen_end_now (6930243045593601084) -->
<skip />
- <!-- no translation found for accessibility_volume_expand (5946812790999244205) -->
- <skip />
- <!-- no translation found for accessibility_volume_collapse (3609549593031810875) -->
- <skip />
+ <string name="accessibility_volume_expand" msgid="5946812790999244205">"ବଢ଼ାନ୍ତୁ"</string>
+ <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ଛୋଟ କରନ୍ତୁ"</string>
<!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
<skip />
- <!-- no translation found for screen_pinning_title (3273740381976175811) -->
- <skip />
+ <string name="screen_pinning_title" msgid="3273740381976175811">"ସ୍କ୍ରିନକୁ ପିନ୍ କରାଯାଇଛି"</string>
<!-- no translation found for screen_pinning_description (8909878447196419623) -->
<skip />
<!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
@@ -795,20 +665,15 @@
<skip />
<!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
<skip />
- <!-- no translation found for screen_pinning_positive (3783985798366751226) -->
- <skip />
- <!-- no translation found for screen_pinning_negative (3741602308343880268) -->
- <skip />
+ <string name="screen_pinning_positive" msgid="3783985798366751226">"ବୁଝିଲି"</string>
+ <string name="screen_pinning_negative" msgid="3741602308343880268">"ନାହିଁ, ଥାଉ"</string>
<!-- no translation found for screen_pinning_start (1022122128489278317) -->
<skip />
<!-- no translation found for screen_pinning_exit (5187339744262325372) -->
<skip />
- <!-- no translation found for quick_settings_reset_confirmation_title (748792586749897883) -->
- <skip />
- <!-- no translation found for quick_settings_reset_confirmation_message (2235970126803317374) -->
- <skip />
- <!-- no translation found for quick_settings_reset_confirmation_button (2660339101868367515) -->
- <skip />
+ <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ଲୁଚାନ୍ତୁ?"</string>
+ <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ଆଗକୁ ଆପଣ ଯେତେବେଳେ ଏହି ସେଟିଙ୍ଗକୁ ଚାଲୁ କରିବେ, ଏହା ପୁଣି ଦେଖାଦେବ।"</string>
+ <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ଲୁଚାନ୍ତୁ"</string>
<!-- no translation found for managed_profile_foreground_toast (5421487114739245972) -->
<skip />
<!-- no translation found for stream_voice_call (4410002696470423714) -->
@@ -849,6 +714,12 @@
<skip />
<!-- no translation found for volume_dialog_title (7272969888820035876) -->
<skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<!-- no translation found for output_title (5355078100792942802) -->
<skip />
<!-- no translation found for output_calls_title (8717692905017206161) -->
@@ -865,46 +736,28 @@
<skip />
<!-- no translation found for system_ui_tuner (708224127392452018) -->
<skip />
- <!-- no translation found for show_battery_percentage (5444136600512968798) -->
- <skip />
- <!-- no translation found for show_battery_percentage_summary (3215025775576786037) -->
- <skip />
- <!-- no translation found for quick_settings (10042998191725428) -->
- <skip />
- <!-- no translation found for status_bar (4877645476959324760) -->
- <skip />
+ <string name="show_battery_percentage" msgid="5444136600512968798">"ଏମ୍ବେଡ୍ ହୋଇଥିବା ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
+ <string name="show_battery_percentage_summary" msgid="3215025775576786037">"ଚାର୍ଜ ହେଉନଥିବାବେଳେ ଷ୍ଟାଟସ୍ ବାର୍ ଆଇକନ୍ ଭିତରେ ବ୍ୟାଟେରୀ ସ୍ତର ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
+ <string name="quick_settings" msgid="10042998191725428">"ଦ୍ରୁତ ସେଟିଙ୍ଗ"</string>
+ <string name="status_bar" msgid="4877645476959324760">"ଷ୍ଟାଟସ୍ ବାର୍"</string>
<!-- no translation found for overview (4018602013895926956) -->
<skip />
<!-- no translation found for demo_mode (2532177350215638026) -->
<skip />
- <!-- no translation found for enable_demo_mode (4844205668718636518) -->
- <skip />
- <!-- no translation found for show_demo_mode (2018336697782464029) -->
- <skip />
- <!-- no translation found for status_bar_ethernet (5044290963549500128) -->
- <skip />
- <!-- no translation found for status_bar_alarm (8536256753575881818) -->
- <skip />
- <!-- no translation found for status_bar_work (6022553324802866373) -->
- <skip />
- <!-- no translation found for status_bar_airplane (7057575501472249002) -->
- <skip />
- <!-- no translation found for add_tile (2995389510240786221) -->
- <skip />
- <!-- no translation found for broadcast_tile (3894036511763289383) -->
- <skip />
- <!-- no translation found for zen_alarm_warning_indef (3482966345578319605) -->
- <skip />
- <!-- no translation found for zen_alarm_warning (444533119582244293) -->
- <skip />
- <!-- no translation found for alarm_template (3980063409350522735) -->
- <skip />
- <!-- no translation found for alarm_template_far (4242179982586714810) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_detail (2579369091672902101) -->
- <skip />
- <!-- no translation found for accessibility_status_bar_hotspot (4099381329956402865) -->
- <skip />
+ <string name="enable_demo_mode" msgid="4844205668718636518">"ଡେମୋ ମୋଡ୍ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="show_demo_mode" msgid="2018336697782464029">"ଡେମୋ ମୋଡ୍ ଦେଖାନ୍ତୁ"</string>
+ <string name="status_bar_ethernet" msgid="5044290963549500128">"ଇଥରନେଟ୍"</string>
+ <string name="status_bar_alarm" msgid="8536256753575881818">"ଆଲାର୍ମ"</string>
+ <string name="status_bar_work" msgid="6022553324802866373">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
+ <string name="status_bar_airplane" msgid="7057575501472249002">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍"</string>
+ <string name="add_tile" msgid="2995389510240786221">"ଟାଇଲ୍ ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="broadcast_tile" msgid="3894036511763289383">"ଟାଇଲ୍ ବ୍ରଡ୍କାଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"ଆପଣ <xliff:g id="WHEN">%1$s</xliff:g> ପୂର୍ବରୁ ଏହା ଅଫ୍ ନକଲେ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
+ <string name="zen_alarm_warning" msgid="444533119582244293">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
+ <string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g>ରେ"</string>
+ <string name="alarm_template_far" msgid="4242179982586714810">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string>
+ <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"ଦ୍ରୁତ ସେଟିଙ୍ଗ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
+ <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"ହଟସ୍ପଟ୍"</string>
<!-- no translation found for accessibility_managed_profile (6613641363112584120) -->
<skip />
<!-- no translation found for tuner_warning_title (7094689930793031682) -->
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 8972982..3a0a331 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -105,8 +105,7 @@
<string name="camera_label" msgid="7261107956054836961">"spustiť fotoaparát"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Vyberte nové rozloženie úlohy"</string>
<string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
- <!-- no translation found for fingerprint_dialog_touch_sensor (8511557690663181761) -->
- <skip />
+ <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Klepnite na senzor odtlačkov prstov"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona odtlačku prsta"</string>
<string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikácie"</string>
<string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Oblasť chybového hlásenia"</string>
@@ -280,8 +279,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Pult s dezertami"</string>
<string name="start_dreams" msgid="5640361424498338327">"Šetrič obrazovky"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <!-- no translation found for quick_settings_header_onboarding_text (7872508260264044734) -->
- <skip />
+ <string name="quick_settings_header_onboarding_text" msgid="7872508260264044734">"Pridržaním ikon zobrazíte ďalšie možnosti"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nerušiť"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Iba prioritné"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Iba budíky"</string>
@@ -545,6 +543,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Klepnutím nastavíte vibrovanie."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Klepnutím vypnete zvuk."</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"Ovládacie prvky hlasitosti %s"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"Výstup médií"</string>
<string name="output_calls_title" msgid="8717692905017206161">"Výstup telefonického hovoru"</string>
<string name="output_none_found" msgid="5544982839808921091">"Nenašli sa žiadne zariadenia"</string>
diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml
index 635185d..3a7442a 100644
--- a/packages/SystemUI/res/values-sw372dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw372dp/dimens.xml
@@ -18,4 +18,5 @@
<resources>
<dimen name="nav_content_padding">8dp</dimen>
<dimen name="rounded_corner_content_padding">8dp</dimen>
+ <dimen name="qs_header_tile_margin_horizontal">5dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b3ab2b4..ffc5b6d 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -505,9 +505,9 @@
<string name="accessibility_output_chooser" msgid="8185317493017988680">"切換輸出裝置"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
- <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和主螢幕按鈕即可取消固定。"</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主螢幕按鈕即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="426190689254018656">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
- <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住主螢幕按鈕即可取消固定。"</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住主螢幕按鈕即可取消固定。"</string>
<string name="screen_pinning_toast" msgid="2266705122951934150">"如要取消固定這個螢幕畫面,請按住「返回」按鈕和「總覽」按鈕"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"如要取消固定這個螢幕畫面,請按住「返回」按鈕和主螢幕按鈕"</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string>
@@ -537,6 +537,12 @@
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s。輕觸即可設為震動。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s。輕觸即可設為靜音。"</string>
<string name="volume_dialog_title" msgid="7272969888820035876">"「%s」音量控制項"</string>
+ <!-- no translation found for volume_dialog_ringer_guidance_vibrate (8902050240801159042) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_silent (2128975224280276122) -->
+ <skip />
+ <!-- no translation found for volume_dialog_ringer_guidance_ring (6144469689490528338) -->
+ <skip />
<string name="output_title" msgid="5355078100792942802">"媒體輸出"</string>
<string name="output_calls_title" msgid="8717692905017206161">"通話輸出"</string>
<string name="output_none_found" msgid="5544982839808921091">"找不到裝置"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index cf0659a..a444ff9 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -124,7 +124,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night,alarm
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index aefcb55..7b1a9e1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -301,11 +301,13 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_tile_height">106dp</dimen>
- <dimen name="qs_tile_margin">19dp</dimen>
+ <dimen name="qs_tile_margin_horizontal">18dp</dimen>
+ <dimen name="qs_tile_margin_vertical">24dp</dimen>
<dimen name="qs_tile_margin_top">18dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
+ <dimen name="qs_header_tile_margin_horizontal">0dp</dimen>
<dimen name="qs_page_indicator_width">16dp</dimen>
<dimen name="qs_page_indicator_height">8dp</dimen>
<dimen name="qs_tile_icon_size">24dp</dimen>
@@ -321,7 +323,7 @@
<dimen name="qs_tile_padding_bottom">16dp</dimen>
<dimen name="qs_tile_spacing">4dp</dimen>
<dimen name="qs_panel_padding_bottom">0dp</dimen>
- <dimen name="qs_panel_padding_top">32dp</dimen>
+ <dimen name="qs_panel_padding_top">30dp</dimen>
<dimen name="qs_detail_header_height">56dp</dimen>
<dimen name="qs_detail_header_padding">0dp</dimen>
<dimen name="qs_detail_image_width">56dp</dimen>
@@ -345,12 +347,12 @@
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
- <dimen name="qs_header_tooltip_height">30dp</dimen>
+ <dimen name="qs_header_tooltip_height">18dp</dimen>
+ <dimen name="qs_header_alarm_icon_size">18dp</dimen>
+ <dimen name="qs_header_alarm_text_margin_start">6dp</dimen>
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
- <!-- Difference between drag handle margin in QQS and expanded QS -->
- <dimen name="qs_footer_drag_handle_offset">10dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 920dd98..9245ac1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -743,8 +743,6 @@
<string name="quick_settings_wifi_on_label">Wi-Fi On</string>
<!-- QuickSettings: Wifi detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_detail_empty_text">No Wi-Fi networks available</string>
- <!-- QuickSettings: Alarm title [CHAR LIMIT=NONE] -->
- <string name="quick_settings_alarm_title">Alarm</string>
<!-- QuickSettings: Cast title [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_title">Cast</string>
<!-- QuickSettings: Cast detail panel, status text when casting [CHAR LIMIT=NONE] -->
@@ -949,13 +947,13 @@
<string name="interruption_level_alarms_twoline">Alarms\nonly</string>
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
- <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
<!-- Indication on the keyguard that is shown when the device is charging rapidly. Should match keyguard_plugged_in_charging_fast [CHAR LIMIT=40]-->
- <string name="keyguard_indication_charging_time_fast">Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time_fast"><xliff:g id="percentage">%2$s</xliff:g> • Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
<!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=40]-->
- <string name="keyguard_indication_charging_time_slowly">Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
<!-- Related to user switcher --><skip/>
@@ -2140,4 +2138,8 @@
<!-- Option to grant the slice permission request on the screen [CHAR LIMIT=15] -->
<string name="slice_permission_deny">Deny</string>
+ <!-- List of packages for which we don't want to show recents onboarding, add into overlay as needed. -->
+ <string-array name="recents_onboarding_blacklisted_packages" translatable="false">
+ </string-array>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a01f71a..d006af1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -270,7 +270,7 @@
<style name="TextAppearance.QS.TileLabel">
<item name="android:textSize">@dimen/qs_tile_text_size</item>
- <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:fontFamily">sans-serif</item>
</style>
<style name="BaseBrightnessDialogContainer">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index b8319a8e..846aadd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -28,25 +28,30 @@
* Proxies SurfaceControl.screenshotToBuffer().
*/
GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
- int maxLayer, boolean useIdentityTransform, int rotation);
+ int maxLayer, boolean useIdentityTransform, int rotation) = 0;
/**
* Begins screen pinning on the provided {@param taskId}.
*/
- void startScreenPinning(int taskId);
+ void startScreenPinning(int taskId) = 1;
/**
* Called when the overview service has started the recents animation.
*/
- void onRecentsAnimationStarted();
+ void onRecentsAnimationStarted() = 2;
/**
* Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
*/
- void setRecentsOnboardingText(CharSequence text);
+ void setRecentsOnboardingText(CharSequence text) = 3;
/**
* Enables/disables launcher/overview interaction features {@link InteractionType}.
*/
- void setInteractionState(int flags);
+ void setInteractionState(int flags) = 4;
+
+ /**
+ * Notifies SystemUI that split screen has been invoked.
+ */
+ void onSplitScreenInvoked() = 5;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 0103cad..2f28c81 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -17,6 +17,7 @@
package com.android.systemui.shared.system;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -403,6 +404,25 @@
}
/**
+ * @return whether screen pinning is active.
+ */
+ public boolean isScreenPinningActive() {
+ try {
+ return ActivityManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @return whether screen pinning is enabled.
+ */
+ public boolean isScreenPinningEnabled() {
+ final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
+ return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
+ }
+
+ /**
* @return whether there is currently a locked task (ie. in screen pinning).
*/
public boolean isLockToAppActive() {
@@ -415,9 +435,9 @@
/**
* @return whether screen pinning is enabled.
+ * @deprecated See {@link #isScreenPinningEnabled}
*/
public boolean isLockToAppEnabled() {
- final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
- return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
+ return isScreenPinningEnabled();
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 68400fc..5b49e67 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -101,4 +101,12 @@
Log.w(TAG, "Failed to override pending app transition (remote): ", e);
}
}
+
+ public void endProlongedAnimations() {
+ try {
+ WindowManagerGlobal.getWindowManagerService().endProlongedAnimations();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to end prolonged animations: ", e);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c3413d9..cb5a050 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -25,6 +25,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
+import android.util.StatsLog;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -430,9 +431,13 @@
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
if (success) {
+ StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
+ StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
monitor.clearFailedUnlockAttempts();
mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
} else {
+ StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
+ StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index b54d09a..2adb286 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -167,7 +167,8 @@
}
mClickActions.put(button, pendingIntent);
- button.setText(rc.getTitleItem().getText());
+ final SliceItem titleItem = rc.getTitleItem();
+ button.setText(titleItem == null ? null : titleItem.getText());
Drawable iconDrawable = null;
SliceItem icon = SliceQuery.find(item.getSlice(),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f3f8d91f..6098e4e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -736,7 +736,8 @@
private DisplayClientState mDisplayClientState = new DisplayClientState();
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @VisibleForTesting
+ final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -773,6 +774,13 @@
maxChargingMicroWatt));
mHandler.sendMessage(msg);
} else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
+ // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to
+ // keep compatibility with apps that aren't direct boot aware.
+ // SysUI should just ignore this broadcast because it was already received
+ // and processed previously.
+ if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+ return;
+ }
SimData args = SimData.fromIntent(intent);
if (DEBUG_SIM_STATES) {
Log.v(TAG, "action " + action
@@ -1508,7 +1516,8 @@
/**
* Handle {@link #MSG_SIM_STATE_CHANGE}
*/
- private void handleSimStateChange(int subId, int slotId, State state) {
+ @VisibleForTesting
+ protected void handleSimStateChange(int subId, int slotId, State state) {
if (DEBUG_SIM_STATES) {
Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId="
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 7403ddc..cad155c 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -44,6 +44,7 @@
import com.android.systemui.power.EnhancedEstimatesImpl;
import com.android.systemui.power.PowerNotificationWarnings;
import com.android.systemui.power.PowerUI;
+import com.android.systemui.statusbar.AppOpsListener;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -314,6 +315,8 @@
mProviders.put(EnhancedEstimates.class, () -> new EnhancedEstimatesImpl());
+ mProviders.put(AppOpsListener.class, () -> new AppOpsListener(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index a2c9ab4..5a2263c 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -14,7 +14,9 @@
package com.android.systemui;
+import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
public interface ForegroundServiceController {
/**
@@ -46,4 +48,32 @@
* @return true if sbn is the system-provided "dungeon" (list of running foreground services).
*/
boolean isDungeonNotification(StatusBarNotification sbn);
+
+ /**
+ * @return true if sbn is one of the window manager "drawing over other apps" notifications
+ */
+ boolean isSystemAlertNotification(StatusBarNotification sbn);
+
+ /**
+ * Returns the key of the foreground service from this package using the standard template,
+ * if one exists.
+ */
+ @Nullable String getStandardLayoutKey(int userId, String pkg);
+
+ /**
+ * @return true if this user/pkg has a missing or custom layout notification and therefore needs
+ * a disclosure notification for system alert windows.
+ */
+ boolean isSystemAlertWarningNeeded(int userId, String pkg);
+
+ /**
+ * Records active app ops. App Ops are stored in FSC in addition to NotificationData in
+ * case they change before we have a notification to tag.
+ */
+ void onAppOpChanged(int code, int uid, String packageName, boolean active);
+
+ /**
+ * Gets active app ops for this user and package.
+ */
+ @Nullable ArraySet<Integer> getAppOps(int userId, String packageName);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
index 3714c4e..fc2b5b4 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
@@ -18,13 +18,13 @@
import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto;
import java.util.Arrays;
@@ -34,17 +34,19 @@
*/
public class ForegroundServiceControllerImpl
implements ForegroundServiceController {
-
+
// shelf life of foreground services before they go bad
public static final long FG_SERVICE_GRACE_MILLIS = 5000;
private static final String TAG = "FgServiceController";
private static final boolean DBG = false;
+ private final Context mContext;
private final SparseArray<UserServices> mUserServices = new SparseArray<>();
private final Object mMutex = new Object();
public ForegroundServiceControllerImpl(Context context) {
+ mContext = context;
}
@Override
@@ -57,6 +59,52 @@
}
@Override
+ public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) return false;
+ return services.getStandardLayoutKey(pkg) == null;
+ }
+ }
+
+ @Override
+ public String getStandardLayoutKey(int userId, String pkg) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) return null;
+ return services.getStandardLayoutKey(pkg);
+ }
+ }
+
+ @Override
+ public ArraySet<Integer> getAppOps(int userId, String pkg) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) {
+ return null;
+ }
+ return services.getFeatures(pkg);
+ }
+ }
+
+ @Override
+ public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
+ int userId = UserHandle.getUserId(uid);
+ synchronized (mMutex) {
+ UserServices userServices = mUserServices.get(userId);
+ if (userServices == null) {
+ userServices = new UserServices();
+ mUserServices.put(userId, userServices);
+ }
+ if (active) {
+ userServices.addOp(packageName, code);
+ } else {
+ userServices.removeOp(packageName, code);
+ }
+ }
+ }
+
+ @Override
public void addNotification(StatusBarNotification sbn, int importance) {
updateNotification(sbn, importance);
}
@@ -102,9 +150,16 @@
}
} else {
userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
- if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)
- && newImportance > NotificationManager.IMPORTANCE_MIN) {
- userServices.addNotification(sbn.getPackageName(), sbn.getKey());
+ if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)) {
+ if (newImportance > NotificationManager.IMPORTANCE_MIN) {
+ userServices.addImportantNotification(sbn.getPackageName(), sbn.getKey());
+ }
+ final Notification.Builder builder = Notification.Builder.recoverBuilder(
+ mContext, sbn.getNotification());
+ if (builder.usesStandardHeader()) {
+ userServices.addStandardLayoutNotification(
+ sbn.getPackageName(), sbn.getKey());
+ }
}
}
}
@@ -117,42 +172,105 @@
&& sbn.getPackageName().equals("android");
}
+ @Override
+ public boolean isSystemAlertNotification(StatusBarNotification sbn) {
+ // TODO: tag system alert notifications so they can be suppressed if app's notification
+ // is tagged
+ return false;
+ }
+
/**
* Struct to track relevant packages and notifications for a userid's foreground services.
*/
private static class UserServices {
private String[] mRunning = null;
private long mServiceStartTime = 0;
- private ArrayMap<String, ArraySet<String>> mNotifications = new ArrayMap<>(1);
+ // package -> sufficiently important posted notification keys
+ private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
+ // package -> standard layout posted notification keys
+ private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
+
+ // package -> app ops
+ private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
+
public void setRunningServices(String[] pkgs, long serviceStartTime) {
mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
mServiceStartTime = serviceStartTime;
}
- public void addNotification(String pkg, String key) {
- if (mNotifications.get(pkg) == null) {
- mNotifications.put(pkg, new ArraySet<String>());
+
+ public void addOp(String pkg, int op) {
+ if (mAppOps.get(pkg) == null) {
+ mAppOps.put(pkg, new ArraySet<>(3));
}
- mNotifications.get(pkg).add(key);
+ mAppOps.get(pkg).add(op);
}
- public boolean removeNotification(String pkg, String key) {
+
+ public boolean removeOp(String pkg, int op) {
final boolean found;
- final ArraySet<String> keys = mNotifications.get(pkg);
+ final ArraySet<Integer> keys = mAppOps.get(pkg);
+ if (keys == null) {
+ found = false;
+ } else {
+ found = keys.remove(op);
+ if (keys.size() == 0) {
+ mAppOps.remove(pkg);
+ }
+ }
+ return found;
+ }
+
+ public void addImportantNotification(String pkg, String key) {
+ addNotification(mImportantNotifications, pkg, key);
+ }
+
+ public boolean removeImportantNotification(String pkg, String key) {
+ return removeNotification(mImportantNotifications, pkg, key);
+ }
+
+ public void addStandardLayoutNotification(String pkg, String key) {
+ addNotification(mStandardLayoutNotifications, pkg, key);
+ }
+
+ public boolean removeStandardLayoutNotification(String pkg, String key) {
+ return removeNotification(mStandardLayoutNotifications, pkg, key);
+ }
+
+ public boolean removeNotification(String pkg, String key) {
+ boolean removed = false;
+ removed |= removeImportantNotification(pkg, key);
+ removed |= removeStandardLayoutNotification(pkg, key);
+ return removed;
+ }
+
+ public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
+ String key) {
+ if (map.get(pkg) == null) {
+ map.put(pkg, new ArraySet<>());
+ }
+ map.get(pkg).add(key);
+ }
+
+ public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
+ String pkg, String key) {
+ final boolean found;
+ final ArraySet<String> keys = map.get(pkg);
if (keys == null) {
found = false;
} else {
found = keys.remove(key);
if (keys.size() == 0) {
- mNotifications.remove(pkg);
+ map.remove(pkg);
}
}
return found;
}
+
public boolean isDungeonNeeded() {
if (mRunning != null
&& System.currentTimeMillis() - mServiceStartTime >= FG_SERVICE_GRACE_MILLIS) {
for (String pkg : mRunning) {
- final ArraySet<String> set = mNotifications.get(pkg);
+ final ArraySet<String> set = mImportantNotifications.get(pkg);
if (set == null || set.size() == 0) {
return true;
}
@@ -160,5 +278,27 @@
}
return false;
}
+
+ public ArraySet<Integer> getFeatures(String pkg) {
+ return mAppOps.get(pkg);
+ }
+
+ public String getStandardLayoutKey(String pkg) {
+ final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
+ if (set == null || set.size() == 0) {
+ return null;
+ }
+ return set.valueAt(0);
+ }
+
+ @Override
+ public String toString() {
+ return "UserServices{" +
+ "mRunning=" + Arrays.toString(mRunning) +
+ ", mServiceStartTime=" + mServiceStartTime +
+ ", mImportantNotifications=" + mImportantNotifications +
+ ", mStandardLayoutNotifications=" + mStandardLayoutNotifications +
+ '}';
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 1185f45..3c666e4 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -34,6 +34,8 @@
import android.view.SurfaceControl;
import com.android.systemui.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.GraphicBufferCompat;
@@ -108,6 +110,15 @@
}
}
+ public void onSplitScreenInvoked() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ EventBus.getDefault().post(new DockedFirstAnimationFrameEvent());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
public void setRecentsOnboardingText(CharSequence text) {
mOnboardingText = text;
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index ee573fb..396d317 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -24,6 +24,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
+import java.util.Set;
public final class Prefs {
private Prefs() {} // no instantation
@@ -87,6 +88,7 @@
String NUM_APPS_LAUNCHED = "NumAppsLaunched";
String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding";
String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount";
+ String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
@@ -121,6 +123,15 @@
get(context).edit().putString(key, value).apply();
}
+ public static void putStringSet(Context context, @Key String key, Set<String> value) {
+ get(context).edit().putStringSet(key, value).apply();
+ }
+
+ public static Set<String> getStringSet(
+ Context context, @Key String key, Set<String> defaultValue) {
+ return get(context).getStringSet(key, defaultValue);
+ }
+
public static Map<String, ?> getAll(Context context) {
return get(context).getAll();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index c7d276c..26618bf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -27,6 +28,7 @@
import android.icu.text.DisplayContext;
import android.net.Uri;
import android.os.Handler;
+import android.os.SystemClock;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,6 +38,7 @@
import java.util.Date;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
import androidx.app.slice.Slice;
import androidx.app.slice.SliceProvider;
@@ -53,6 +56,12 @@
public static final String KEYGUARD_NEXT_ALARM_URI =
"content://com.android.systemui.keyguard/alarm";
+ /**
+ * Only show alarms that will ring within N hours.
+ */
+ @VisibleForTesting
+ static final int ALARM_VISIBILITY_HOURS = 12;
+
private final Date mCurrentTime = new Date();
protected final Uri mSliceUri;
protected final Uri mDateUri;
@@ -65,6 +74,10 @@
private boolean mRegisteredEveryMinute;
private String mNextAlarm;
private NextAlarmController mNextAlarmController;
+ protected AlarmManager mAlarmManager;
+ protected ContentResolver mContentResolver;
+ private AlarmManager.AlarmClockInfo mNextAlarmInfo;
+ private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm;
/**
* Receiver responsible for time ticking and updating the date format.
@@ -105,17 +118,26 @@
public Slice onBindSlice(Uri sliceUri) {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText));
- if (!TextUtils.isEmpty(mNextAlarm)) {
- Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
- builder.addRow(new RowBuilder(builder, mAlarmUri)
- .setTitle(mNextAlarm).addEndItem(icon));
+ addNextAlarm(builder);
+ return builder.build();
+ }
+
+ protected void addNextAlarm(ListBuilder builder) {
+ if (TextUtils.isEmpty(mNextAlarm)) {
+ return;
}
- return builder.build();
+ Icon alarmIcon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
+ RowBuilder alarmRowBuilder = new RowBuilder(builder, mAlarmUri)
+ .setTitle(mNextAlarm)
+ .addEndItem(alarmIcon);
+ builder.addRow(alarmRowBuilder);
}
@Override
public boolean onCreateSliceProvider() {
+ mAlarmManager = getContext().getSystemService(AlarmManager.class);
+ mContentResolver = getContext().getContentResolver();
mNextAlarmController = new NextAlarmControllerImpl(getContext());
mNextAlarmController.addCallback(this);
mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
@@ -124,15 +146,25 @@
return true;
}
- public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
- if (info == null) {
- return "";
+ private void updateNextAlarm() {
+ if (withinNHours(mNextAlarmInfo, ALARM_VISIBILITY_HOURS)) {
+ String pattern = android.text.format.DateFormat.is24HourFormat(getContext(),
+ ActivityManager.getCurrentUser()) ? "H:mm" : "h:mm";
+ mNextAlarm = android.text.format.DateFormat.format(pattern,
+ mNextAlarmInfo.getTriggerTime()).toString();
+ } else {
+ mNextAlarm = "";
}
- String skeleton = android.text.format.DateFormat
- .is24HourFormat(context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
- String pattern = android.text.format.DateFormat
- .getBestDateTimePattern(Locale.getDefault(), skeleton);
- return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
+ mContentResolver.notifyChange(mSliceUri, null /* observer */);
+ }
+
+ private boolean withinNHours(AlarmManager.AlarmClockInfo alarmClockInfo, int hours) {
+ if (alarmClockInfo == null) {
+ return false;
+ }
+
+ long limit = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(hours);
+ return mNextAlarmInfo.getTriggerTime() <= limit;
}
/**
@@ -181,7 +213,7 @@
final String text = getFormattedDate();
if (!text.equals(mLastText)) {
mLastText = text;
- getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ mContentResolver.notifyChange(mSliceUri, null /* observer */);
}
}
@@ -203,7 +235,15 @@
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
- mNextAlarm = formatNextAlarm(getContext(), nextAlarm);
- getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ mNextAlarmInfo = nextAlarm;
+ mAlarmManager.cancel(mUpdateNextAlarm);
+
+ long triggerAt = mNextAlarmInfo == null ? -1 : mNextAlarmInfo.getTriggerTime()
+ - TimeUnit.HOURS.toMillis(ALARM_VISIBILITY_HOURS);
+ if (triggerAt > 0) {
+ mAlarmManager.setExact(AlarmManager.RTC, triggerAt, "lock_screen_next_alarm",
+ mUpdateNextAlarm, mHandler);
+ }
+ updateNextAlarm();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index b22ea4c..2629f30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -24,7 +24,7 @@
// The size of a single dot in relation to the whole animation.
private static final float SINGLE_SCALE = .4f;
- private static final float MINOR_ALPHA = .3f;
+ private static final float MINOR_ALPHA = .42f;
private final ArrayList<Integer> mQueuedPositions = new ArrayList<>();
@@ -53,7 +53,7 @@
removeViewAt(getChildCount() - 1);
}
TypedArray array = getContext().obtainStyledAttributes(
- new int[]{android.R.attr.colorForeground});
+ new int[]{android.R.attr.colorControlActivated});
int color = array.getColor(0, 0);
array.recycle();
while (numPages > getChildCount()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index f3417dc..ea3a60b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -1,5 +1,10 @@
package com.android.systemui.qs;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -8,20 +13,34 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
+import android.widget.Scroller;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanel.TileRecord;
import java.util.ArrayList;
+import java.util.Set;
public class PagedTileLayout extends ViewPager implements QSTileLayout {
private static final boolean DEBUG = false;
private static final String TAG = "PagedTileLayout";
+ private static final int REVEAL_SCROLL_DURATION_MILLIS = 750;
+ private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
+ private static final long BOUNCE_ANIMATION_DURATION = 450L;
+ private static final int TILE_ANIMATION_STAGGER_DELAY = 85;
+ private static final Interpolator SCROLL_CUBIC = (t) -> {
+ t -= 1.0f;
+ return t * t * t + 1.0f;
+ };
+
private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
@@ -34,37 +53,17 @@
private int mPosition;
private boolean mOffPage;
private boolean mListening;
+ private Scroller mScroller;
+
+ private AnimatorSet mBounceAnimatorSet;
+ private int mAnimatingToPage = -1;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
+ mScroller = new Scroller(context, SCROLL_CUBIC);
setAdapter(mAdapter);
- setOnPageChangeListener(new OnPageChangeListener() {
- @Override
- public void onPageSelected(int position) {
- if (mPageIndicator == null) return;
- if (mPageListener != null) {
- mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
- : position == 0);
- }
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- if (mPageIndicator == null) return;
- setCurrentPage(position, positionOffset != 0);
- mPageIndicator.setLocation(position + positionOffset);
- if (mPageListener != null) {
- mPageListener.onPageChanged(positionOffsetPixels == 0 &&
- (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
- }
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- }
- });
- setCurrentItem(0);
+ setOnPageChangeListener(mOnPageChangeListener);
+ setCurrentItem(0, false);
}
@Override
@@ -99,6 +98,45 @@
}
}
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ // Suppress all touch event during reveal animation.
+ if (mAnimatingToPage != -1) {
+ return true;
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // Suppress all touch event during reveal animation.
+ if (mAnimatingToPage != -1) {
+ return true;
+ }
+ return super.onTouchEvent(ev);
+ }
+
+ @Override
+ public void computeScroll() {
+ if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
+ scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+ float pageFraction = (float) getScrollX() / getWidth();
+ int position = (int) pageFraction;
+ float positionOffset = pageFraction - position;
+ mOnPageChangeListener.onPageScrolled(position, positionOffset, getScrollX());
+ // Keep on drawing until the animation has finished.
+ postInvalidateOnAnimation();
+ return;
+ }
+ if (mAnimatingToPage != -1) {
+ setCurrentItem(mAnimatingToPage, true);
+ mBounceAnimatorSet.start();
+ setOffscreenPageLimit(1);
+ mAnimatingToPage = -1;
+ }
+ super.computeScroll();
+ }
+
/**
* Sets individual pages to listening or not. If offPage it will set
* the next page after position to listening as well since we are in between
@@ -257,9 +295,84 @@
return mPages.get(0).mColumns;
}
+ public void startTileReveal(Set<String> tileSpecs, final Runnable postAnimation) {
+ if (tileSpecs.isEmpty() || mPages.size() < 2 || getScrollX() != 0) {
+ // Do not start the reveal animation unless there are tiles to animate, multiple
+ // TilePages available and the user has not already started dragging.
+ return;
+ }
+
+ final int lastPageNumber = mPages.size() - 1;
+ final TilePage lastPage = mPages.get(lastPageNumber);
+ final ArrayList<Animator> bounceAnims = new ArrayList<>();
+ for (TileRecord tr : lastPage.mRecords) {
+ if (tileSpecs.contains(tr.tile.getTileSpec())) {
+ bounceAnims.add(setupBounceAnimator(tr.tileView, bounceAnims.size()));
+ }
+ }
+
+ if (bounceAnims.isEmpty()) {
+ // All tileSpecs are on the first page. Nothing to do.
+ // TODO: potentially show a bounce animation for first page QS tiles
+ return;
+ }
+
+ mBounceAnimatorSet = new AnimatorSet();
+ mBounceAnimatorSet.playTogether(bounceAnims);
+ mBounceAnimatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBounceAnimatorSet = null;
+ postAnimation.run();
+ }
+ });
+ mAnimatingToPage = lastPageNumber;
+ setOffscreenPageLimit(mAnimatingToPage); // Ensure the page to reveal has been inflated.
+ mScroller.startScroll(getScrollX(), getScrollY(), getWidth() * mAnimatingToPage, 0,
+ REVEAL_SCROLL_DURATION_MILLIS);
+ postInvalidateOnAnimation();
+ }
+
+ private static Animator setupBounceAnimator(View view, int ordinal) {
+ view.setAlpha(0f);
+ view.setScaleX(0f);
+ view.setScaleY(0f);
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view,
+ PropertyValuesHolder.ofFloat(View.ALPHA, 1),
+ PropertyValuesHolder.ofFloat(View.SCALE_X, 1),
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, 1));
+ animator.setDuration(BOUNCE_ANIMATION_DURATION);
+ animator.setStartDelay(ordinal * TILE_ANIMATION_STAGGER_DELAY);
+ animator.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
+ return animator;
+ }
+
+ private final ViewPager.OnPageChangeListener mOnPageChangeListener =
+ new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ if (mPageIndicator == null) return;
+ if (mPageListener != null) {
+ mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
+ : position == 0);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
+ if (mPageIndicator == null) return;
+ setCurrentPage(position, positionOffset != 0);
+ mPageIndicator.setLocation(position + positionOffset);
+ if (mPageListener != null) {
+ mPageListener.onPageChanged(positionOffsetPixels == 0 &&
+ (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
+ }
+ }
+ };
+
public static class TilePage extends TileLayout {
private int mMaxRows = 3;
-
public TilePage(Context context, AttributeSet attrs) {
super(context, attrs);
updateResources();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 175cddc..2a4bb60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -66,10 +66,6 @@
private TouchAnimator mNonfirstPageDelayedAnimator;
private TouchAnimator mBrightnessAnimator;
- /**
- * Whether we're in the middle of animating between the collapsed and expanded states.
- */
- private boolean mIsAnimating;
private boolean mOnKeyguard;
private boolean mAllowFancy;
@@ -94,9 +90,6 @@
Log.w(TAG, "QS Not using page layout");
}
panel.setPageListener(this);
-
- // At time of creation, the QS panel is never animating.
- mIsAnimating = false;
}
public void onRtlChanged() {
@@ -251,11 +244,6 @@
} else {
mBrightnessAnimator = null;
}
- View headerView = mQsPanel.getHeaderView();
- if (headerView!= null) {
- firstPageBuilder.addFloat(headerView, "translationY", heightDiff, 0);
- mAllViews.add(headerView);
- }
mFirstPageAnimator = firstPageBuilder
.setListener(this)
.build();
@@ -342,21 +330,11 @@
@Override
public void onAnimationAtStart() {
- if (mIsAnimating) {
- mQsPanel.onCollapse();
- }
- mIsAnimating = false;
-
mQuickQsPanel.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationAtEnd() {
- if (mIsAnimating) {
- mQsPanel.onExpanded();
- }
- mIsAnimating = false;
-
mQuickQsPanel.setVisibility(View.INVISIBLE);
final int N = mQuickQsViews.size();
for (int i = 0; i < N; i++) {
@@ -366,11 +344,6 @@
@Override
public void onAnimationStarted() {
- if (!mIsAnimating) {
- mQsPanel.onAnimating();
- }
- mIsAnimating = true;
-
mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
if (mOnFirstPage) {
final int N = mQuickQsViews.size();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 993df75..e9888df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -86,14 +86,9 @@
private View mActionsContainer;
private View mDragHandle;
- private final int mDragHandleExpandOffset;
public QSFooterImpl(Context context, AttributeSet attrs) {
super(context, attrs);
-
- mDragHandleExpandOffset = getResources().
- getDimensionPixelSize(R.dimen.qs_footer_drag_handle_offset);
-
}
@Override
@@ -169,10 +164,9 @@
private TouchAnimator createFooterAnimator() {
return new TouchAnimator.Builder()
.addFloat(mDivider, "alpha", 0, 1)
- .addFloat(mCarrierText, "alpha", 0, 1)
+ .addFloat(mCarrierText, "alpha", 0, 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
- .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0)
- .addFloat(mDragHandle, "alpha", 1, 0)
+ .addFloat(mDragHandle, "alpha", 1, 0, 0)
.setStartDelay(0.15f)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d437f49..29f3c43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -272,21 +272,28 @@
mContainer.setExpansion(expansion);
final float translationScaleY = expansion - 1;
if (!mHeaderAnimating) {
- int height = mHeader.getHeight();
- getView().setTranslationY(mKeyguardShowing ? (translationScaleY * height)
- : headerTranslation);
+ getView().setTranslationY(
+ mKeyguardShowing
+ ? translationScaleY * mHeader.getHeight()
+ : headerTranslation);
}
if (expansion == mLastQSExpansion) {
return;
}
mLastQSExpansion = expansion;
- mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
- mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
+
+ boolean fullyExpanded = expansion == 1;
int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
+ mFooter.getHeight();
+ float panelTranslationY = translationScaleY * heightDiff;
+
+ // Let the views animate their contents correctly by giving them the necessary context.
+ mHeader.setExpansion(mKeyguardShowing, expansion, panelTranslationY);
+ mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
+ mQSPanel.getQsTileRevealController().setExpansion(expansion);
mQSPanel.setTranslationY(translationScaleY * heightDiff);
- boolean fullyExpanded = expansion == 1;
mQSDetail.setFullyExpanded(fullyExpanded);
+
if (fullyExpanded) {
// Always draw within the bounds of the view when fully expanded.
mQSPanel.setClipBounds(null);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index a92e346..61e3065 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -29,7 +29,6 @@
import android.service.quicksettings.Tile;
import android.util.AttributeSet;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
@@ -54,18 +53,19 @@
import java.util.ArrayList;
import java.util.Collection;
-/** View that represents the quick settings tile panel. **/
+/** View that represents the quick settings tile panel (when expanded/pulled down). **/
public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
- public static final String QS_SHOW_LONG_PRESS_TOOLTIP = "qs_show_long_press";
+ public static final String QS_SHOW_HEADER = "qs_show_header";
protected final Context mContext;
- protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
+ protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
protected final View mBrightnessView;
private final H mHandler = new H();
private final View mPageIndicator;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final QSTileRevealController mQsTileRevealController;
protected boolean mExpanded;
protected boolean mListening;
@@ -74,7 +74,6 @@
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
- protected QSTooltipView mTooltipView;
protected QSSecurityFooter mFooter;
private boolean mGridContentVisible = true;
@@ -96,11 +95,6 @@
setOrientation(VERTICAL);
- mTooltipView = (QSTooltipView) LayoutInflater.from(mContext)
- .inflate(R.layout.quick_settings_header, this, false);
-
- addView(mTooltipView);
-
mBrightnessView = LayoutInflater.from(mContext).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
addView(mBrightnessView);
@@ -115,6 +109,8 @@
addView(mPageIndicator);
((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
+ mQsTileRevealController = new QSTileRevealController(mContext, this,
+ ((PagedTileLayout) mTileLayout));
addDivider();
@@ -143,6 +139,10 @@
return mPageIndicator;
}
+ public QSTileRevealController getQsTileRevealController() {
+ return mQsTileRevealController;
+ }
+
public boolean isShowingCustomize() {
return mCustomizePanel != null && mCustomizePanel.isCustomizing();
}
@@ -152,7 +152,6 @@
super.onAttachedToWindow();
final TunerService tunerService = Dependency.get(TunerService.class);
tunerService.addTunable(this, QS_SHOW_BRIGHTNESS);
- tunerService.addTunable(this, QS_SHOW_LONG_PRESS_TOOLTIP);
if (mHost != null) {
setTiles(mHost.getTiles());
@@ -186,8 +185,6 @@
public void onTuningChanged(String key, String newValue) {
if (QS_SHOW_BRIGHTNESS.equals(key)) {
updateViewVisibilityForTuningValue(mBrightnessView, newValue);
- } else if (QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
- updateViewVisibilityForTuningValue(mTooltipView, newValue);
}
}
@@ -229,10 +226,6 @@
return mBrightnessView;
}
- View getHeaderView() {
- return mTooltipView;
- }
-
public void setCallback(QSDetail.Callback callback) {
mCallback = callback;
}
@@ -254,10 +247,7 @@
public void updateResources() {
final Resources res = mContext.getResources();
- setPadding(0, 0, 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
- mTooltipView.getLayoutParams().height =
- res.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
- mTooltipView.setLayoutParams(mTooltipView.getLayoutParams());
+ setPadding(0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_top), 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
for (TileRecord r : mRecords) {
r.tile.clearState();
}
@@ -291,21 +281,6 @@
if (mCustomizePanel != null && mCustomizePanel.isShown()) {
mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
}
-
- // Instantly hide the header here since we don't want it to still be animating.
- mTooltipView.setVisibility(View.INVISIBLE);
- }
-
- /**
- * Called when the panel is fully animated out/expanded. This is different from the state
- * tracked by {@link #mExpanded}, which only checks if the panel is even partially pulled out.
- */
- public void onExpanded() {
- mTooltipView.fadeIn();
- }
-
- public void onAnimating() {
- mTooltipView.fadeOut();
}
public void setExpanded(boolean expanded) {
@@ -384,6 +359,9 @@
}
public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
+ if (!collapsedView) {
+ mQsTileRevealController.updateRevealedTiles(tiles);
+ }
for (TileRecord record : mRecords) {
mTileLayout.removeTile(record);
record.tile.removeCallback(record.callback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
new file mode 100644
index 0000000..2f012e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
@@ -0,0 +1,76 @@
+package com.android.systemui.qs;
+
+import static com.android.systemui.Prefs.Key.QS_TILE_SPECS_REVEALED;
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.ArraySet;
+
+import com.android.systemui.Prefs;
+import com.android.systemui.plugins.qs.QSTile;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+public class QSTileRevealController {
+ private static final long QS_REVEAL_TILES_DELAY = 500L;
+
+ private final Context mContext;
+ private final QSPanel mQSPanel;
+ private final PagedTileLayout mPagedTileLayout;
+ private final ArraySet<String> mTilesToReveal = new ArraySet<>();
+ private final Handler mHandler = new Handler();
+
+ private final Runnable mRevealQsTiles = new Runnable() {
+ @Override
+ public void run() {
+ mPagedTileLayout.startTileReveal(mTilesToReveal, () -> {
+ if (mQSPanel.isExpanded()) {
+ addTileSpecsToRevealed(mTilesToReveal);
+ mTilesToReveal.clear();
+ }
+ });
+ }
+ };
+
+ QSTileRevealController(Context context, QSPanel qsPanel, PagedTileLayout pagedTileLayout) {
+ mContext = context;
+ mQSPanel = qsPanel;
+ mPagedTileLayout = pagedTileLayout;
+ }
+
+ public void setExpansion(float expansion) {
+ if (expansion == 1f) {
+ mHandler.postDelayed(mRevealQsTiles, QS_REVEAL_TILES_DELAY);
+ } else {
+ mHandler.removeCallbacks(mRevealQsTiles);
+ }
+ }
+
+ public void updateRevealedTiles(Collection<QSTile> tiles) {
+ ArraySet<String> tileSpecs = new ArraySet<>();
+ for (QSTile tile : tiles) {
+ tileSpecs.add(tile.getTileSpec());
+ }
+
+ final Set<String> revealedTiles = Prefs.getStringSet(
+ mContext, QS_TILE_SPECS_REVEALED, Collections.EMPTY_SET);
+ if (revealedTiles.isEmpty() || mQSPanel.isShowingCustomize()) {
+ // Do not reveal QS tiles the user has upon first load or those that they directly
+ // added through customization.
+ addTileSpecsToRevealed(tileSpecs);
+ } else {
+ // Animate all tiles that the user has not directly added themselves.
+ tileSpecs.removeAll(revealedTiles);
+ mTilesToReveal.addAll(tileSpecs);
+ }
+ }
+
+ private void addTileSpecsToRevealed(ArraySet<String> specs) {
+ final ArraySet<String> revealedTiles = new ArraySet<>(
+ Prefs.getStringSet(mContext, QS_TILE_SPECS_REVEALED, Collections.EMPTY_SET));
+ revealedTiles.addAll(specs);
+ Prefs.putStringSet(mContext, QS_TILE_SPECS_REVEALED, revealedTiles);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
deleted file mode 100644
index d1f9741..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 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.qs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.Prefs;
-
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * Tooltip/header view for the Quick Settings panel.
- */
-public class QSTooltipView extends LinearLayout {
-
- private static final int FADE_ANIMATION_DURATION_MS = 300;
- private static final long AUTO_FADE_OUT_DELAY_MS = TimeUnit.SECONDS.toMillis(6);
- private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
- public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
-
- private final Handler mHandler = new Handler();
- private final Runnable mAutoFadeOutRunnable = () -> fadeOut();
-
- private int mShownCount;
-
- public QSTooltipView(Context context) {
- this(context, null);
- }
-
- public QSTooltipView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mShownCount = getStoredShownCount();
- }
-
- /** Returns the latest stored tooltip shown count from SharedPreferences. */
- private int getStoredShownCount() {
- return Prefs.getInt(
- mContext,
- Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- TOOLTIP_NOT_YET_SHOWN_COUNT);
- }
-
- /**
- * Fades in the header view if we can show the tooltip - short circuits any running animation.
- */
- public void fadeIn() {
- if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
- animate().cancel();
- setVisibility(View.VISIBLE);
- animate()
- .alpha(1f)
- .setDuration(FADE_ANIMATION_DURATION_MS)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHandler.postDelayed(mAutoFadeOutRunnable, AUTO_FADE_OUT_DELAY_MS);
- }
- })
- .start();
-
- // Increment and drop the shown count in prefs for the next time we're deciding to
- // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
- // in prefs (say, from a long press).
- if (getStoredShownCount() <= mShownCount) {
- Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
- }
- }
- }
-
- /**
- * Fades out the header view if it's partially visible - short circuits any running animation.
- */
- public void fadeOut() {
- animate().cancel();
- if (getVisibility() == View.VISIBLE && getAlpha() != 0f) {
- mHandler.removeCallbacks(mAutoFadeOutRunnable);
- animate()
- .alpha(0f)
- .setDuration(FADE_ANIMATION_DURATION_MS)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- perhapsMakeViewInvisible();
- }
- })
- .start();
- } else {
- perhapsMakeViewInvisible();
- }
- }
-
- /**
- * Only update visibility if the view is currently being shown. Otherwise, it's already been
- * hidden by some other manner.
- */
- private void perhapsMakeViewInvisible() {
- if (getVisibility() == View.VISIBLE) {
- setVisibility(View.INVISIBLE);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f0684e1..2270b60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -20,7 +20,6 @@
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Space;
@@ -123,7 +122,7 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (QS_SHOW_BRIGHTNESS.equals(key) || QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
+ if (QS_SHOW_BRIGHTNESS.equals(key)) {
// No Brightness or Tooltip for you!
super.onTuningChanged(key, "0");
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 4d7333b..2151436 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -15,24 +15,30 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
-import static android.app.StatusBarManager.DISABLE_NONE;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
+import android.os.Handler;
import android.provider.AlarmClock;
import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
-import android.widget.TextClock;
+import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.R.id;
import com.android.systemui.SysUiServiceProvider;
@@ -43,11 +49,25 @@
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.policy.NextAlarmController;
-public class QuickStatusBarHeader extends RelativeLayout
- implements CommandQueue.Callbacks, View.OnClickListener {
+import java.util.Locale;
- private ActivityStarter mActivityStarter;
+/**
+ * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
+ * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
+ * contents.
+ */
+public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
+ View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
+
+ /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
+ private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
+ private static final int FADE_ANIMATION_DURATION_MS = 300;
+ private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
+ public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
+
+ private final Handler mHandler = new Handler();
private QSPanel mQsPanel;
@@ -58,20 +78,39 @@
protected QuickQSPanel mHeaderQsPanel;
protected QSTileHost mHost;
private TintedIconManager mIconManager;
- private TouchAnimator mAlphaAnimator;
+ private TouchAnimator mStatusIconsAlphaAnimator;
+ private TouchAnimator mHeaderTextContainerAlphaAnimator;
private View mQuickQsStatusIcons;
-
private View mDate;
+ private View mHeaderTextContainerView;
+ /** View corresponding to the next alarm info (including the icon). */
+ private View mNextAlarmView;
+ /** Tooltip for educating users that they can long press on icons to see more details. */
+ private View mLongPressTooltipView;
+ /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
+ private TextView mNextAlarmTextView;
+
+ private NextAlarmController mAlarmController;
+ private String mNextAlarmText;
+ /** Counts how many times the long press tooltip has been shown to the user. */
+ private int mShownCount;
+
+ /**
+ * Runnable for automatically fading out the long press tooltip (as if it were animating away).
+ */
+ private final Runnable mAutoFadeOutTooltipRunnable = () -> hideLongPressTooltip(false);
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ mAlarmController = Dependency.get(NextAlarmController.class);
+ mShownCount = getStoredShownCount();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- Resources res = getResources();
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
mDate = findViewById(R.id.date);
@@ -79,8 +118,11 @@
mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
- // RenderThread is doing more harm than good when touching the header (to expand quick
- // settings), so disable it for this view
+ // Views corresponding to the header info section (e.g. tooltip and next alarm).
+ mHeaderTextContainerView = findViewById(R.id.header_text_container);
+ mLongPressTooltipView = findViewById(R.id.long_press_tooltip);
+ mNextAlarmView = findViewById(R.id.next_alarm);
+ mNextAlarmTextView = findViewById(R.id.next_alarm_text);
updateResources();
@@ -98,8 +140,6 @@
BatteryMeterView battery = findViewById(R.id.battery);
battery.setForceShowPercent(true);
-
- mActivityStarter = Dependency.get(ActivityStarter.class);
}
private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
@@ -129,21 +169,26 @@
}
private void updateResources() {
- updateAlphaAnimator();
+ // Update height, especially due to landscape mode restricting space.
+ mHeaderTextContainerView.getLayoutParams().height =
+ mContext.getResources().getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
+ mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
+
+ updateStatusIconAlphaAnimator();
+ updateHeaderTextContainerAlphaAnimator();
}
- private void updateAlphaAnimator() {
- mAlphaAnimator = new TouchAnimator.Builder()
+ private void updateStatusIconAlphaAnimator() {
+ mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
.build();
}
- public int getCollapsedHeight() {
- return getHeight();
- }
-
- public int getExpandedHeight() {
- return getHeight();
+ private void updateHeaderTextContainerAlphaAnimator() {
+ mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
+ .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
+ .setStartDelay(.5f)
+ .build();
}
public void setExpanded(boolean expanded) {
@@ -153,10 +198,47 @@
updateEverything();
}
- public void setExpansion(float headerExpansionFraction) {
- if (mAlphaAnimator != null ) {
- mAlphaAnimator.setPosition(headerExpansionFraction);
+ /**
+ * Animates the inner contents based on the given expansion details.
+ *
+ * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
+ * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
+ * @param panelTranslationY how much the panel has physically moved down vertically (required
+ * for keyguard animations only)
+ */
+ public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
+ float panelTranslationY) {
+ final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
+ if (mStatusIconsAlphaAnimator != null) {
+ mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
}
+
+ if (isKeyguardShowing) {
+ // If the keyguard is showing, we want to offset the text so that it comes in at the
+ // same time as the panel as it slides down.
+ mHeaderTextContainerView.setTranslationY(panelTranslationY);
+ } else {
+ mHeaderTextContainerView.setTranslationY(0f);
+ }
+
+ if (mHeaderTextContainerAlphaAnimator != null) {
+ mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
+ }
+
+ // Check the original expansion fraction - we don't want to show the tooltip until the
+ // panel is pulled all the way out.
+ if (expansionFraction == 1f) {
+ // QS is fully expanded, bring in the tooltip.
+ showLongPressTooltip();
+ }
+ }
+
+ /** Returns the latest stored tooltip shown count from SharedPreferences. */
+ private int getStoredShownCount() {
+ return Prefs.getInt(
+ mContext,
+ Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
+ TOOLTIP_NOT_YET_SHOWN_COUNT);
}
@Override
@@ -191,6 +273,12 @@
}
mHeaderQsPanel.setListening(listening);
mListening = listening;
+
+ if (listening) {
+ mAlarmController.addCallback(this);
+ } else {
+ mAlarmController.removeCallback(this);
+ }
}
@Override
@@ -201,6 +289,125 @@
}
}
+ @Override
+ public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
+ mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null;
+ if (mNextAlarmText != null) {
+ hideLongPressTooltip(true /* shouldFadeInAlarmText */);
+ } else {
+ hideAlarmText();
+ }
+ updateHeaderTextContainerAlphaAnimator();
+ }
+
+ /**
+ * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying
+ * the space).
+ */
+ public void showLongPressTooltip() {
+ // If we have alarm text to show, don't bother fading in the tooltip.
+ if (!TextUtils.isEmpty(mNextAlarmText)) {
+ return;
+ }
+
+ if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
+ mLongPressTooltipView.animate().cancel();
+ mLongPressTooltipView.setVisibility(View.VISIBLE);
+ mLongPressTooltipView.animate()
+ .alpha(1f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHandler.postDelayed(
+ mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS);
+ }
+ })
+ .start();
+
+ // Increment and drop the shown count in prefs for the next time we're deciding to
+ // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
+ // in prefs (say, from a long press).
+ if (getStoredShownCount() <= mShownCount) {
+ Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
+ }
+ }
+ }
+
+ /**
+ * Fades out the long press tooltip if it's partially visible - short circuits any running
+ * animation. Additionally has the ability to fade in the alarm info text.
+ *
+ * @param shouldShowAlarmText whether we should fade in the next alarm text
+ */
+ private void hideLongPressTooltip(boolean shouldShowAlarmText) {
+ mLongPressTooltipView.animate().cancel();
+ if (mLongPressTooltipView.getVisibility() == View.VISIBLE
+ && mLongPressTooltipView.getAlpha() != 0f) {
+ mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable);
+ mLongPressTooltipView.animate()
+ .alpha(0f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLongPressTooltipView.setVisibility(View.INVISIBLE);
+
+ if (shouldShowAlarmText) {
+ showAlarmText();
+ }
+ }
+ })
+ .start();
+ } else {
+ mLongPressTooltipView.setVisibility(View.INVISIBLE);
+
+ if (shouldShowAlarmText) {
+ showAlarmText();
+ }
+ }
+ }
+
+ /**
+ * Fades in the updated alarm text. Note that if there's already an alarm showing, this will
+ * immediately hide it and fade in the updated time.
+ */
+ private void showAlarmText() {
+ mNextAlarmView.setAlpha(0f);
+ mNextAlarmView.setVisibility(View.VISIBLE);
+ mNextAlarmTextView.setText(mNextAlarmText);
+
+ mNextAlarmView.animate()
+ .alpha(1f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .start();
+ }
+
+ /**
+ * Fades out and hides the next alarm text. This also resets the text contents to null in
+ * preparation for the next alarm update.
+ */
+ private void hideAlarmText() {
+ if (mNextAlarmView.getVisibility() == View.VISIBLE) {
+ mNextAlarmView.animate()
+ .alpha(0f)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Reset the alpha regardless of how the animation ends for the next
+ // time we show this view/want to animate it.
+ mNextAlarmView.setVisibility(View.INVISIBLE);
+ mNextAlarmView.setAlpha(1f);
+ mNextAlarmTextView.setText(null);
+ }
+ })
+ .start();
+ } else {
+ // Next alarm view is already hidden, only need to clear the text.
+ mNextAlarmTextView.setText(null);
+ }
+ }
+
public void updateEverything() {
post(() -> setClickable(false));
}
@@ -225,4 +432,15 @@
public void setCallback(Callback qsPanelCallback) {
mHeaderQsPanel.setCallback(qsPanelCallback);
}
+
+ private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
+ if (info == null) {
+ return "";
+ }
+ String skeleton = android.text.format.DateFormat
+ .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
+ String pattern = android.text.format.DateFormat
+ .getBestDateTimePattern(Locale.getDefault(), skeleton);
+ return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 23faa55..66823ca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -21,7 +21,8 @@
protected int mColumns;
protected int mCellWidth;
protected int mCellHeight;
- protected int mCellMargin;
+ protected int mCellMarginHorizontal;
+ protected int mCellMarginVertical;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private int mCellMarginTop;
@@ -76,7 +77,8 @@
final Resources res = mContext.getResources();
final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
mCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
- mCellMargin = res.getDimensionPixelSize(R.dimen.qs_tile_margin);
+ mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
+ mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
if (mColumns != columns) {
mColumns = columns;
@@ -91,7 +93,7 @@
final int numTiles = mRecords.size();
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int rows = (numTiles + mColumns - 1) / mColumns;
- mCellWidth = (width - (mCellMargin * (mColumns + 1))) / mColumns;
+ mCellWidth = (width - (mCellMarginHorizontal * (mColumns + 1))) / mColumns;
View previousView = this;
for (TileRecord record : mRecords) {
@@ -102,8 +104,8 @@
// Only include the top margin in our measurement if we have more than 1 row to show.
// Otherwise, don't add the extra margin buffer at top.
- int height = (mCellHeight + mCellMargin) * rows +
- (rows != 0 ? (mCellMarginTop - mCellMargin) : 0);
+ int height = (mCellHeight + mCellMarginVertical) * rows +
+ (rows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
if (height < 0) height = 0;
setMeasuredDimension(width, height);
}
@@ -143,10 +145,10 @@
}
private int getRowTop(int row) {
- return row * (mCellHeight + mCellMargin) + mCellMarginTop;
+ return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop;
}
private int getColumnStart(int column) {
- return column * (mCellWidth + mCellMargin) + mCellMargin;
+ return column * (mCellWidth + mCellMarginHorizontal) + mCellMarginHorizontal;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index 6263efa..f673364 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -200,7 +200,6 @@
}
private static abstract class KeyframeSet {
-
private final float mFrameWidth;
private final int mSize;
@@ -210,9 +209,8 @@
}
void setValue(float fraction, Object target) {
- int i;
- for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
- float amount = fraction / mFrameWidth;
+ int i = MathUtils.constrain((int) Math.ceil(fraction / mFrameWidth), 1, mSize - 1);
+ float amount = (fraction - mFrameWidth * (i - 1)) / mFrameWidth;
interpolate(i, amount, target);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index bf9746e..77c3bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -23,7 +23,6 @@
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tiles.AirplaneModeTile;
-import com.android.systemui.qs.tiles.AlarmTile;
import com.android.systemui.qs.tiles.BatterySaverTile;
import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CastTile;
@@ -70,7 +69,6 @@
else if (tileSpec.equals("saver")) return new DataSaverTile(mHost);
else if (tileSpec.equals("night")) return new NightDisplayTile(mHost);
else if (tileSpec.equals("nfc")) return new NfcTile(mHost);
- else if (tileSpec.equals("alarm")) return new AlarmTile(mHost);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 016cbd6..04dbb88 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -50,7 +50,7 @@
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTooltipView;
+import com.android.systemui.qs.QuickStatusBarHeader;
import java.util.ArrayList;
@@ -197,7 +197,7 @@
Prefs.putInt(
mContext,
Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- QSTooltipView.MAX_TOOLTIP_SHOWN_COUNT);
+ QuickStatusBarHeader.MAX_TOOLTIP_SHOWN_COUNT);
}
public LogMaker populate(LogMaker logMaker) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java
deleted file mode 100644
index ff3fe73..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 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.qs.tiles;
-
-import static android.service.quicksettings.Tile.STATE_ACTIVE;
-import static android.service.quicksettings.Tile.STATE_UNAVAILABLE;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.QS_ALARM;
-import static com.android.systemui.keyguard.KeyguardSliceProvider.formatNextAlarm;
-
-import android.app.AlarmManager.AlarmClockInfo;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.provider.AlarmClock;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
-
-public class AlarmTile extends QSTileImpl implements NextAlarmChangeCallback {
- private final NextAlarmController mController;
- private String mNextAlarm;
- private PendingIntent mIntent;
-
- public AlarmTile(QSTileHost host) {
- super(host);
- mController = Dependency.get(NextAlarmController.class);
- }
-
- @Override
- public State newTileState() {
- return new BooleanState();
- }
-
- @Override
- protected void handleClick() {
- if (mIntent != null) {
- Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(mIntent);
- }
- }
-
- @Override
- protected void handleUpdateState(State state, Object arg) {
- state.state = mNextAlarm != null ? STATE_ACTIVE : STATE_UNAVAILABLE;
- state.label = getTileLabel();
- state.secondaryLabel = mNextAlarm;
- state.icon = ResourceIcon.get(R.drawable.stat_sys_alarm);
- ((BooleanState) state).value = mNextAlarm != null;
- }
-
- @Override
- public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
- if (nextAlarm != null) {
- mNextAlarm = formatNextAlarm(mContext, nextAlarm);
- mIntent = nextAlarm.getShowIntent();
- } else {
- mNextAlarm = null;
- mIntent = null;
- }
- refreshState();
- }
-
- @Override
- public int getMetricsCategory() {
- return QS_ALARM;
- }
-
- @Override
- public Intent getLongClickIntent() {
- return new Intent(AlarmClock.ACTION_SET_ALARM);
- }
-
- @Override
- protected void handleSetListening(boolean listening) {
- if (listening) {
- mController.addCallback(this);
- } else {
- mController.removeCallback(this);
- }
- }
-
- @Override
- public CharSequence getTileLabel() {
- return mContext.getString(R.string.status_bar_alarm);
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 409c753..df4a975 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -45,8 +45,10 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
@@ -100,6 +102,8 @@
private static RecentsTaskLoader sTaskLoader;
private static RecentsConfiguration sConfiguration;
+ private OverviewProxyService mOverviewProxyService;
+
private Handler mHandler;
private RecentsImpl mImpl;
private int mDraggingInRecentsCurrentUser;
@@ -208,6 +212,7 @@
sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor);
mHandler = new Handler();
mImpl = new RecentsImpl(mContext);
+ mOverviewProxyService = Dependency.get(OverviewProxyService.class);
// Register with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -247,6 +252,13 @@
return;
}
+ if (mOverviewProxyService.getProxy() != null) {
+ // TODO: Proxy to Launcher
+ if (!triggeredFromAltTab) {
+ return;
+ }
+ }
+
ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents();
int currentUser = sSystemServicesProxy.getCurrentUser();
@@ -282,6 +294,13 @@
return;
}
+ if (mOverviewProxyService.getProxy() != null) {
+ // TODO: Proxy to Launcher
+ if (!triggeredFromAltTab) {
+ return;
+ }
+ }
+
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
@@ -313,6 +332,11 @@
return;
}
+ if (mOverviewProxyService.getProxy() != null) {
+ // TODO: Proxy to Launcher
+ return;
+ }
+
int growTarget = getComponent(Divider.class).getView().growsRecents();
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
@@ -345,6 +369,11 @@
return;
}
+ if (mOverviewProxyService.getProxy() != null) {
+ // TODO: Proxy to Launcher
+ return;
+ }
+
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.preloadRecents();
@@ -373,6 +402,11 @@
return;
}
+ if (mOverviewProxyService.getProxy() != null) {
+ // TODO: Proxy to Launcher
+ return;
+ }
+
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.cancelPreloadingRecents();
@@ -415,7 +449,7 @@
final int activityType = runningTask != null
? runningTask.configuration.windowConfiguration.getActivityType()
: ACTIVITY_TYPE_UNDEFINED;
- boolean screenPinningActive = ActivityManagerWrapper.getInstance().isLockToAppActive();
+ boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
boolean isRunningTaskInHomeOrRecentsStack =
activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b0a2fad..95b311f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -96,6 +96,7 @@
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.WindowManagerWrapper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -836,12 +837,7 @@
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
// We post to make sure that this information is delivered after this traversals is
// finished.
- mRecentsView.post(new Runnable() {
- @Override
- public void run() {
- Recents.getSystemServices().endProlongedAnimations();
- }
- });
+ mRecentsView.post(() -> WindowManagerWrapper.getInstance().endProlongedAnimations());
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3f6f30b..055e72e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -24,7 +24,6 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.KeyguardManager;
import android.app.trust.TrustManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -34,7 +33,6 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
-import android.os.AsyncTask.Status;
import android.os.Handler;
import android.os.SystemClock;
import android.util.ArraySet;
@@ -385,8 +383,7 @@
}
public void toggleRecents(int growTarget) {
- // Skip preloading if the task is locked
- if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
+ if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
return;
}
@@ -464,8 +461,7 @@
}
public void preloadRecents() {
- // Skip preloading if the task is locked
- if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
+ if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 26fac6c..127361a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -49,6 +49,10 @@
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Shows onboarding for the new recents interaction in P (codenamed quickstep).
*/
@@ -65,6 +69,7 @@
private final Context mContext;
private final WindowManager mWindowManager;
private final OverviewProxyService mOverviewProxyService;
+ private Set<String> mBlacklistedPackages;
private final View mLayout;
private final TextView mTextView;
private final ImageView mDismissView;
@@ -85,6 +90,10 @@
public void onTaskStackChanged() {
ActivityManager.RunningTaskInfo info = ActivityManagerWrapper.getInstance()
.getRunningTask(ACTIVITY_TYPE_UNDEFINED /* ignoreActivityType */);
+ if (mBlacklistedPackages.contains(info.baseActivity.getPackageName())) {
+ hide(true);
+ return;
+ }
int activityType = info.configuration.windowConfiguration.getActivityType();
int numAppsLaunched = Prefs.getInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, 0);
if (activityType == ACTIVITY_TYPE_STANDARD) {
@@ -122,6 +131,9 @@
mOverviewProxyService = overviewProxyService;
final Resources res = context.getResources();
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ mBlacklistedPackages = new HashSet<>();
+ Collections.addAll(mBlacklistedPackages, res.getStringArray(
+ R.array.recents_onboarding_blacklisted_packages));
mLayout = LayoutInflater.from(mContext).inflate(R.layout.recents_onboarding, null);
mTextView = mLayout.findViewById(R.id.onboarding_text);
mDismissView = mLayout.findViewById(R.id.dismiss);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 93fd34a..544d95c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -444,17 +444,6 @@
}
}
- public void endProlongedAnimations() {
- if (mWm == null) {
- return;
- }
- try {
- mIwm.endProlongedAnimations();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
public void registerDockedStackListener(IDockedStackListener listener) {
if (mWm == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 3cc3273..89288d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -2188,7 +2188,8 @@
private void readSystemFlags() {
SystemServicesProxy ssp = Recents.getSystemServices();
mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
- mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isLockToAppEnabled();
+ mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isScreenPinningEnabled()
+ && !ActivityManagerWrapper.getInstance().isLockToAppActive();
}
private void updateStackActionButtonVisibility() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java
new file mode 100644
index 0000000..2ec78cf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 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.statusbar;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.ForegroundServiceController;
+
+/**
+ * This class handles listening to notification updates and passing them along to
+ * NotificationPresenter to be displayed to the user.
+ */
+public class AppOpsListener implements AppOpsManager.OnOpActiveChangedListener {
+ private static final String TAG = "NotificationListener";
+
+ // Dependencies:
+ private final ForegroundServiceController mFsc =
+ Dependency.get(ForegroundServiceController.class);
+
+ private final Context mContext;
+ protected NotificationPresenter mPresenter;
+ protected NotificationEntryManager mEntryManager;
+ protected final AppOpsManager mAppOps;
+
+ protected static final int[] OPS = new int[] {AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ AppOpsManager.OP_RECORD_AUDIO};
+
+ public AppOpsListener(Context context) {
+ mContext = context;
+ mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ }
+
+ public void setUpWithPresenter(NotificationPresenter presenter,
+ NotificationEntryManager entryManager) {
+ mPresenter = presenter;
+ mEntryManager = entryManager;
+ mAppOps.startWatchingActive(OPS, this);
+ }
+
+ public void destroy() {
+ mAppOps.stopWatchingActive(this);
+ }
+
+ @Override
+ public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
+ mFsc.onAppOpChanged(code, uid, packageName, active);
+ mPresenter.getHandler().post(() -> {
+ mEntryManager.updateNotificationsForAppOps(code, uid, packageName, active);
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index bc2dff9..785fc1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -36,6 +36,7 @@
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.MathUtils;
@@ -1354,6 +1355,14 @@
mHelperButton.setVisibility(show ? View.VISIBLE : View.GONE);
}
+ public void showAppOpsIcons(ArraySet<Integer> activeOps) {
+ if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
+ mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
+ }
+ mPrivateLayout.showAppOpsIcons(activeOps);
+ mPublicLayout.showAppOpsIcons(activeOps);
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -2629,6 +2638,16 @@
mChildrenContainer = childrenContainer;
}
+ @VisibleForTesting
+ protected void setPrivateLayout(NotificationContentView privateLayout) {
+ mPrivateLayout = privateLayout;
+ }
+
+ @VisibleForTesting
+ protected void setPublicLayout(NotificationContentView publicLayout) {
+ mPublicLayout = publicLayout;
+ }
+
/**
* Equivalent to View.OnLongClickListener with coordinates
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 22e8909..bc14203 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -411,12 +411,14 @@
break;
}
+ String percentage = NumberFormat.getPercentInstance()
+ .format(mBatteryLevel / 100f);
if (hasChargingTime) {
String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, chargingTimeRemaining);
- return mContext.getResources().getString(chargingId, chargingTimeFormatted);
+ return mContext.getResources().getString(chargingId, chargingTimeFormatted, percentage);
} else {
- return mContext.getResources().getString(chargingId);
+ return mContext.getResources().getString(chargingId, percentage);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 91960df..73c8795 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -23,6 +23,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.view.NotificationHeaderView;
@@ -1423,6 +1424,17 @@
return header;
}
+ public void showAppOpsIcons(ArraySet<Integer> activeOps) {
+ if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) {
+ mContractedWrapper.getNotificationHeader().showAppOpsIcons(activeOps);
+ }
+ if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) {
+ mExpandedWrapper.getNotificationHeader().showAppOpsIcons(activeOps);
+ }
+ if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) {
+ mHeadsUpWrapper.getNotificationHeader().showAppOpsIcons(activeOps);
+ }
+ }
public NotificationHeaderView getContractedNotificationHeader() {
if (mContractedChild != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 127f3f9..d53cb03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -34,6 +35,7 @@
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -65,6 +67,8 @@
private final Environment mEnvironment;
private HeadsUpManager mHeadsUpManager;
+ final ForegroundServiceController mFsc = Dependency.get(ForegroundServiceController.class);
+
public static final class Entry {
private static final long LAUNCH_COOLDOWN = 2000;
private static final long REMOTE_INPUT_COOLDOWN = 500;
@@ -95,6 +99,7 @@
private Throwable mDebugThrowable;
public CharSequence remoteInputTextWhenReset;
public long lastRemoteInputSent = NOT_LAUNCHED_YET;
+ public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
public Entry(StatusBarNotification n) {
this.key = n.getKey();
@@ -194,7 +199,7 @@
/**
* Update the notification icons.
* @param context the context to create the icons with.
- * @param n the notification to read the icon from.
+ * @param sbn the notification to read the icon from.
* @throws InflationException
*/
public void updateIcons(Context context, StatusBarNotification sbn)
@@ -375,6 +380,8 @@
}
mGroupManager.onEntryAdded(entry);
+ updateAppOps(entry);
+
updateRankingAndSort(mRankingMap);
}
@@ -393,6 +400,35 @@
updateRankingAndSort(ranking);
}
+ private void updateAppOps(Entry entry) {
+ final int uid = entry.notification.getUid();
+ final String pkg = entry.notification.getPackageName();
+ ArraySet<Integer> activeOps = mFsc.getAppOps(entry.notification.getUserId(), pkg);
+ if (activeOps != null) {
+ int N = activeOps.size();
+ for (int i = 0; i < N; i++) {
+ updateAppOp(activeOps.valueAt(i), uid, pkg, true);
+ }
+ }
+ }
+
+ public void updateAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+ synchronized (mEntries) {
+ final int N = mEntries.size();
+ for (int i = 0; i < N; i++) {
+ Entry entry = mEntries.valueAt(i);
+ if (uid == entry.notification.getUid()
+ && pkg.equals(entry.notification.getPackageName())) {
+ if (showIcon) {
+ entry.mActiveAppOps.add(appOp);
+ } else {
+ entry.mActiveAppOps.remove(appOp);
+ }
+ }
+ }
+ }
+ }
+
public boolean isAmbient(String key) {
if (mRankingMap != null) {
getRanking(key, mTmpRanking);
@@ -545,11 +581,14 @@
return true;
}
- final ForegroundServiceController fsc = Dependency.get(ForegroundServiceController.class);
- if (fsc.isDungeonNotification(sbn) && !fsc.isDungeonNeededForUser(sbn.getUserId())) {
+ if (mFsc.isDungeonNotification(sbn) && !mFsc.isDungeonNeededForUser(sbn.getUserId())) {
// this is a foreground-service disclosure for a user that does not need to show one
return true;
}
+ if (mFsc.isSystemAlertNotification(sbn) && !mFsc.isSystemAlertWarningNeeded(
+ sbn.getUserId(), sbn.getPackageName())) {
+ return true;
+ }
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 7360486..71f7911 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
@@ -77,7 +78,7 @@
public class NotificationEntryManager implements Dumpable, NotificationInflater.InflationCallback,
ExpandableNotificationRow.ExpansionLogger, NotificationUpdateHandler,
VisualStabilityManager.Callback {
- private static final String TAG = "NotificationEntryManager";
+ private static final String TAG = "NotificationEntryMgr";
protected static final boolean DEBUG = false;
protected static final boolean ENABLE_HEADS_UP = true;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
@@ -734,6 +735,14 @@
}
}
+ public void updateNotificationsForAppOps(int appOp, int uid, String pkg, boolean showIcon) {
+ if (mForegroundServiceController.getStandardLayoutKey(
+ UserHandle.getUserId(uid), pkg) != null) {
+ mNotificationData.updateAppOp(appOp, uid, pkg, showIcon);
+ updateNotifications();
+ }
+ }
+
private boolean alertAgain(NotificationData.Entry oldEntry, Notification newNotification) {
return oldEntry == null || !oldEntry.hasInterrupted()
|| (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index cad956c..4f09133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -698,7 +698,7 @@
if (!hasOverflow) {
// we have to ensure that adding the low priority notification won't lead to an
// overflow
- collapsedPadding -= (1.0f + OVERFLOW_EARLY_AMOUNT) * mCollapsedIcons.getIconSize();
+ collapsedPadding -= mCollapsedIcons.getNoOverflowExtraPadding();
} else {
// Partial overflow padding will fill enough space to add extra dots
collapsedPadding -= mCollapsedIcons.getPartialOverflowExtraPadding();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index cd4c7ae..75b8b37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -342,6 +342,8 @@
row.showBlockingHelper(entry.userSentiment ==
NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+
+ row.showAppOpsIcons(entry.mActiveAppOps);
}
mPresenter.onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index b220686..446a1d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -14,7 +14,6 @@
package com.android.systemui.statusbar.phone;
-import android.app.AlarmManager.AlarmClockInfo;
import android.content.Context;
import android.os.Handler;
import android.provider.Settings.Secure;
@@ -28,8 +27,6 @@
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
/**
* Manages which tiles should be automatically added to QS.
@@ -40,7 +37,6 @@
public static final String INVERSION = "inversion";
public static final String WORK = "work";
public static final String NIGHT = "night";
- public static final String ALARM = "alarm";
private final Context mContext;
private final QSTileHost mHost;
@@ -87,9 +83,6 @@
&& ColorDisplayController.isAvailable(mContext)) {
Dependency.get(ColorDisplayController.class).setListener(mColorDisplayCallback);
}
- if (!mAutoTracker.isAdded(ALARM)) {
- Dependency.get(NextAlarmController.class).addCallback(mNextAlarmChangeCallback);
- }
}
public void destroy() {
@@ -101,7 +94,6 @@
Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
Dependency.get(ColorDisplayController.class).setListener(null);
- Dependency.get(NextAlarmController.class).removeCallback(mNextAlarmChangeCallback);
}
private final ManagedProfileController.Callback mProfileCallback =
@@ -150,19 +142,6 @@
}
};
- private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() {
- @Override
- public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
- if (mAutoTracker.isAdded(ALARM)) return;
- if (nextAlarm != null) {
- mHost.addTile(ALARM);
- mAutoTracker.setTileAdded(ALARM);
- mHandler.post(() -> Dependency.get(NextAlarmController.class)
- .removeCallback(mNextAlarmChangeCallback));
- }
- }
- };
-
@VisibleForTesting
final ColorDisplayController.Callback mColorDisplayCallback =
new ColorDisplayController.Callback() {
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 f7f791e..f42473d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -51,6 +51,7 @@
public static final String TAG = "CollapsedStatusBarFragment";
private static final String EXTRA_PANEL_STATE = "panel_state";
+ public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager";
public static final int FADE_IN_DURATION = 320;
public static final int FADE_IN_DELAY = 50;
private PhoneStatusBarView mStatusBar;
@@ -94,6 +95,7 @@
mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));
}
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
+ mDarkIconManager.setShouldLog(true);
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index c499619..edfd02b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.UserHandle;
@@ -25,21 +26,27 @@
import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.settingslib.Utils;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.util.leak.LeakDetector;
-public class DemoStatusIcons extends LinearLayout implements DemoMode {
+public class DemoStatusIcons extends StatusIconContainer implements DemoMode, DarkReceiver {
private final LinearLayout mStatusIcons;
private final int mIconSize;
private boolean mDemoMode;
+ private int mColor;
public DemoStatusIcons(LinearLayout statusIcons, int iconSize) {
super(statusIcons.getContext());
mStatusIcons = statusIcons;
mIconSize = iconSize;
+ mColor = DarkIconDispatcher.DEFAULT_ICON_TINT;
setLayoutParams(mStatusIcons.getLayoutParams());
setOrientation(mStatusIcons.getOrientation());
@@ -48,6 +55,22 @@
p.addView(this, p.indexOfChild(mStatusIcons));
}
+ public void remove() {
+ ((ViewGroup) getParent()).removeView(this);
+ }
+
+ public void setColor(int color) {
+ mColor = color;
+ updateColors();
+ }
+
+ private void updateColors() {
+ for (int i = 0; i < getChildCount(); i++) {
+ StatusBarIconView child = (StatusBarIconView) getChildAt(i);
+ child.setStaticDrawableColor(mColor);
+ }
+ }
+
@Override
public void dispatchDemoCommand(String command, Bundle args) {
if (!mDemoMode && command.equals(COMMAND_ENTER)) {
@@ -136,6 +159,7 @@
break;
} else {
StatusBarIcon icon = v.getStatusBarIcon();
+ icon.visible = true;
icon.icon = Icon.createWithResource(icon.icon.getResPackage(), iconId);
v.set(icon);
v.updateDrawable();
@@ -150,9 +174,16 @@
return;
}
StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo");
+ icon.visible = true;
StatusBarIconView v = new StatusBarIconView(getContext(), null, null);
v.setTag(slot);
v.set(icon);
+ v.setStaticDrawableColor(mColor);
addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
}
+
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ setColor(DarkIconDispatcher.getTint(area, mStatusIcons, tint));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index aba5cdf..d2cdc27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.support.v4.util.ArraySet;
import android.util.Log;
@@ -32,6 +33,7 @@
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -45,12 +47,12 @@
*/
public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
- OnHeadsUpChangedListener {
+ OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener {
private static final String TAG = "HeadsUpManagerPhone";
private static final boolean DEBUG = false;
private final View mStatusBarWindowView;
- private final int mStatusBarHeight;
+ private int mStatusBarHeight;
private final NotificationGroupManager mGroupManager;
private final StatusBar mBar;
private final VisualStabilityManager mVisualStabilityManager;
@@ -291,6 +293,13 @@
}
}
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ Resources resources = mContext.getResources();
+ mStatusBarHeight = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
// VisualStabilityManager.Callback overrides:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 380c08e..edfbd3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -21,6 +21,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
+import android.util.StatsLog;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -152,6 +153,8 @@
mKeyguardView.requestLayout();
}
mShowingSoon = false;
+ StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
+ StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN);
}
};
@@ -183,6 +186,8 @@
public void hide(boolean destroyView) {
if (isShowing()) {
+ StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
+ StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
mDismissCallbackRegistry.notifyDismissCancelled();
}
mFalsingManager.onBouncerHidden();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 09acf3e..2375b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -87,10 +87,10 @@
super.onFinishInflate();
mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container);
mSystemIconsContainer = findViewById(R.id.system_icons_container);
- mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
- mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
- mCarrierLabel = (TextView) findViewById(R.id.keyguard_carrier_text);
- mBatteryView = (BatteryMeterView) mSystemIconsContainer.findViewById(R.id.battery);
+ mMultiUserSwitch = findViewById(R.id.multi_user_switch);
+ mMultiUserAvatar = findViewById(R.id.multi_user_avatar);
+ mCarrierLabel = findViewById(R.id.keyguard_carrier_text);
+ mBatteryView = mSystemIconsContainer.findViewById(R.id.battery);
loadDimens();
updateUserSwitcher();
@@ -220,7 +220,7 @@
Dependency.get(ConfigurationController.class).addCallback(this);
mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
- onOverlayChanged();
+ onThemeChanged();
}
@Override
@@ -291,12 +291,9 @@
.setDuration(300)
.setStartDelay(0)
.setInterpolator(Interpolators.ALPHA_OUT)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mMultiUserSwitch.setAlpha(1f);
- getOverlay().remove(mMultiUserSwitch);
- }
+ .withEndAction(() -> {
+ mMultiUserSwitch.setAlpha(1f);
+ getOverlay().remove(mMultiUserSwitch);
})
.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 840f55c..0ed69e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -115,6 +115,8 @@
private final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
private final static int ROTATE_BUTTON_LOOP_DURATION_MS = 2000;
+ private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
+
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
@@ -156,6 +158,7 @@
private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false);
private Animator mRotateHideAnimator;
+ private ViewRippler mViewRippler = new ViewRippler();
private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
@Override
@@ -464,12 +467,16 @@
animIcon.start();
}
+ if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
+
// Set visibility, may fail if a11y service is active.
// If invisible, call will stop animation.
mNavigationBarView.setRotateButtonVisibility(true);
} else { // Hide
+ mViewRippler.stop(); // Prevent any pending ripples, force hide or not
+
if (force) {
// If a hide animator is running stop it and make invisible
if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
@@ -519,6 +526,25 @@
return 6000;
}
+ private boolean isRotateSuggestionIntroduced() {
+ ContentResolver cr = getContext().getContentResolver();
+ return Settings.Secure.getInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0)
+ >= NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION;
+ }
+
+ private void incrementNumAcceptedRotationSuggestionsIfNeeded() {
+ // Get the number of accepted suggestions
+ ContentResolver cr = getContext().getContentResolver();
+ final int numSuggestions = Settings.Secure.getInt(cr,
+ Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0);
+
+ // Increment the number of accepted suggestions only if it would change intro mode
+ if (numSuggestions < NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION) {
+ Settings.Secure.putInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
+ numSuggestions + 1);
+ }
+ }
+
// Injected from StatusBar at creation.
public void setCurrentSysuiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
@@ -682,7 +708,8 @@
@VisibleForTesting
boolean onHomeLongClick(View v) {
- if (!mNavigationBarView.isRecentsButtonVisible() && mNavigationBarView.inScreenPinning()) {
+ if (!mNavigationBarView.isRecentsButtonVisible()
+ && ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
return onLongPressBackHome(v);
}
if (shouldDisableNavbarGestures()) {
@@ -861,6 +888,7 @@
private void onRotateSuggestionClick(View v) {
mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
+ incrementNumAcceptedRotationSuggestionsIfNeeded();
mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
}
@@ -989,6 +1017,35 @@
}
}
+ private class ViewRippler {
+ private static final int RIPPLE_OFFSET_MS = 50;
+ private static final int RIPPLE_INTERVAL_MS = 2000;
+ private View mRoot;
+
+ public void start(View root) {
+ stop(); // Stop any pending ripple animations
+
+ mRoot = root;
+
+ // Schedule pending ripples, offset the 1st to avoid problems with visibility change
+ mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
+ mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
+ mRoot.postOnAnimationDelayed(mRipple, 2*RIPPLE_INTERVAL_MS);
+ }
+
+ public void stop() {
+ if (mRoot != null) mRoot.removeCallbacks(mRipple);
+ }
+
+ private final Runnable mRipple = new Runnable() {
+ @Override
+ public void run() { // Cause the ripple to fire via false presses
+ mRoot.setPressed(true);
+ mRoot.setPressed(false);
+ }
+ };
+ }
+
public static View create(Context context, FragmentListener listener) {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 57d78dd..a4daed9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -43,6 +43,7 @@
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.tuner.TunerService;
@@ -149,7 +150,8 @@
}
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mNavigationBarView.inScreenPinning()) {
+ if (ActivityManagerWrapper.getInstance().isScreenPinningActive()
+ || mStatusBar.isKeyguardShowing()) {
return false;
}
@@ -182,7 +184,8 @@
}
public boolean onTouchEvent(MotionEvent event) {
- if (mNavigationBarView.inScreenPinning()) {
+ if (ActivityManagerWrapper.getInstance().isScreenPinningActive()
+ || mStatusBar.isKeyguardShowing()) {
return false;
}
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 a5621e5..74fbed1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,8 +21,6 @@
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
import android.animation.ObjectAnimator;
@@ -30,7 +28,6 @@
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
import android.annotation.StyleRes;
-import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -41,7 +38,6 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
@@ -60,7 +56,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
-import com.android.systemui.Interpolators;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
@@ -379,15 +374,20 @@
return getRecentsButton().getVisibility() == View.VISIBLE;
}
+ public boolean isOverviewEnabled() {
+ return (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) == 0;
+ }
+
public boolean isQuickStepSwipeUpEnabled() {
return mOverviewProxyService.getProxy() != null
+ && isOverviewEnabled()
&& ((mOverviewProxyService.getInteractionFlags()
& FLAG_DISABLE_SWIPE_UP) == 0);
}
public boolean isQuickScrubEnabled() {
return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
- && mOverviewProxyService.getProxy() != null && !isRecentsButtonVisible()
+ && mOverviewProxyService.getProxy() != null && isOverviewEnabled()
&& ((mOverviewProxyService.getInteractionFlags()
& FLAG_DISABLE_QUICK_SCRUB) == 0);
}
@@ -575,8 +575,7 @@
boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
// Always disable recents when alternate car mode UI is active.
- boolean disableRecent = mUseCarModeUi
- || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
+ boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
&& ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
@@ -584,17 +583,18 @@
// When screen pinning, don't hide back and home when connected service or back and
// recents buttons when disconnected from launcher service in screen pinning mode,
// as they are used for exiting.
+ final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
if (mOverviewProxyService.getProxy() != null) {
// Use interaction flags to show/hide navigation buttons but will be shown if required
// to exit screen pinning.
final int flags = mOverviewProxyService.getInteractionFlags();
disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0;
- if (inScreenPinning()) {
+ if (pinningActive) {
disableBack = disableHome = false;
} else {
disableBack |= (flags & FLAG_HIDE_BACK_BUTTON) != 0;
}
- } else if (inScreenPinning()) {
+ } else if (pinningActive) {
disableBack = disableRecent = false;
}
@@ -614,7 +614,7 @@
}
public boolean inScreenPinning() {
- return ActivityManagerWrapper.getInstance().isLockToAppActive();
+ return ActivityManagerWrapper.getInstance().isScreenPinningActive();
}
public void setLayoutTransitionsEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 5cf4c4c..5479dd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -56,6 +56,7 @@
private static final int NO_VALUE = Integer.MIN_VALUE;
private static final String TAG = "NotificationIconContainer";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_OVERFLOW = false;
private static final int CANNED_ANIMATION_DURATION = 100;
private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
@@ -107,6 +108,7 @@
private final HashMap<View, IconState> mIconStates = new HashMap<>();
private int mDotPadding;
private int mStaticDotRadius;
+ private int mStaticDotDiameter;
private int mActualLayoutWidth = NO_VALUE;
private float mActualPaddingEnd = NO_VALUE;
private float mActualPaddingStart = NO_VALUE;
@@ -122,17 +124,21 @@
private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons;
// Keep track of the last visible icon so collapsed container can report on its location
private IconState mLastVisibleIconState;
+ private float mVisualOverflowStart;
+ // Keep track of overflow in range [0, 3]
+ private int mNumDots;
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
initDimens();
- setWillNotDraw(!DEBUG);
+ setWillNotDraw(!(DEBUG || DEBUG_OVERFLOW));
}
private void initDimens() {
mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+ mStaticDotDiameter = 2 * mStaticDotRadius;
}
@Override
@@ -142,6 +148,30 @@
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(getActualPaddingStart(), 0, getLayoutEnd(), getHeight(), paint);
+
+ if (DEBUG_OVERFLOW) {
+ if (mLastVisibleIconState == null) {
+ return;
+ }
+
+ int height = getHeight();
+ int end = getFinalTranslationX();
+
+ // Visualize the "end" of the layout
+ paint.setColor(Color.BLUE);
+ canvas.drawLine(end, 0, end, height, paint);
+
+ paint.setColor(Color.BLACK);
+ int lastIcon = (int) mLastVisibleIconState.xTranslation;
+ canvas.drawLine(lastIcon, 0, lastIcon, height, paint);
+
+ paint.setColor(Color.RED);
+ canvas.drawLine(mVisualOverflowStart, 0, mVisualOverflowStart, height, paint);
+
+ paint.setColor(Color.YELLOW);
+ float overflow = getMaxOverflowStart();
+ canvas.drawLine(overflow, 0, overflow, height, paint);
+ }
}
@Override
@@ -282,7 +312,7 @@
}
/**
- * Calulate the horizontal translations for each notification based on how much the icons
+ * Calculate the horizontal translations for each notification based on how much the icons
* are inserted into the notification container.
* If this is not a whole number, the fraction means by how much the icon is appearing.
*/
@@ -293,9 +323,9 @@
int maxVisibleIcons = mDark ? MAX_VISIBLE_ICONS_WHEN_DARK :
mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
float layoutEnd = getLayoutEnd();
- float overflowStart = layoutEnd - mIconSize * (2 + OVERFLOW_EARLY_AMOUNT);
+ float overflowStart = getMaxOverflowStart();
+ mVisualOverflowStart = 0;
boolean hasAmbient = mSpeedBumpIndex != -1 && mSpeedBumpIndex < getChildCount();
- float visualOverflowStart = 0;
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
@@ -310,45 +340,40 @@
noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow;
}
iconState.visibleState = StatusBarIconView.STATE_ICON;
- if (firstOverflowIndex == -1 && (forceOverflow
- || (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart)))) {
+
+ boolean isOverflowing =
+ (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart));
+ if (firstOverflowIndex == -1 && (forceOverflow || isOverflowing)) {
firstOverflowIndex = noOverflowAfter && !forceOverflow ? i - 1 : i;
- int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding;
- visualOverflowStart = overflowStart + mIconSize * (1 + OVERFLOW_EARLY_AMOUNT)
- - totalDotLength / 2
- - mIconSize * 0.5f + mStaticDotRadius;
+ mVisualOverflowStart = layoutEnd - mIconSize
+ - 2 * (mStaticDotDiameter + mDotPadding);
if (forceOverflow) {
- visualOverflowStart = Math.min(translationX, visualOverflowStart
- + mStaticDotRadius * 2 + mDotPadding);
- } else {
- visualOverflowStart += (translationX - overflowStart) / mIconSize
- * (mStaticDotRadius * 2 + mDotPadding);
+ mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
}
}
translationX += iconState.iconAppearAmount * view.getWidth() * drawingScale;
}
+ mNumDots = 0;
if (firstOverflowIndex != -1) {
- int numDots = 1;
- translationX = visualOverflowStart;
+ translationX = mVisualOverflowStart;
for (int i = firstOverflowIndex; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
int dotWidth = mStaticDotRadius * 2 + mDotPadding;
iconState.xTranslation = translationX;
- if (numDots <= MAX_DOTS) {
- if (numDots == 1 && iconState.iconAppearAmount < 0.8f) {
+ if (mNumDots < MAX_DOTS) {
+ if (mNumDots == 0 && iconState.iconAppearAmount < 0.8f) {
iconState.visibleState = StatusBarIconView.STATE_ICON;
- numDots--;
} else {
iconState.visibleState = StatusBarIconView.STATE_DOT;
+ mNumDots++;
}
- translationX += (numDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth)
+ translationX += (mNumDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth)
* iconState.iconAppearAmount;
mLastVisibleIconState = iconState;
} else {
iconState.visibleState = StatusBarIconView.STATE_HIDDEN;
}
- numDots++;
}
} else if (childCount > 0) {
View lastChild = getChildAt(childCount - 1);
@@ -360,7 +385,7 @@
if (firstOverflowIndex != -1) {
// If we have an overflow, only count those half for centering because the dots
// don't have a lot of visual weight.
- float deltaIgnoringOverflow = (getLayoutEnd() - visualOverflowStart) / 2;
+ float deltaIgnoringOverflow = (getLayoutEnd() - mVisualOverflowStart) / 2;
delta = (deltaIgnoringOverflow + delta) / 2;
}
for (int i = 0; i < childCount; i++) {
@@ -440,7 +465,13 @@
return 0;
}
- return (int) (mLastVisibleIconState.xTranslation + mIconSize * (1 + OVERFLOW_EARLY_AMOUNT));
+ int translation = (int) (mLastVisibleIconState.xTranslation + mIconSize);
+ // There's a chance that last translation goes beyond the edge maybe
+ return Math.min(getWidth(), translation);
+ }
+
+ private float getMaxOverflowStart() {
+ return getLayoutEnd() - mIconSize * (2 + OVERFLOW_EARLY_AMOUNT);
}
public void setChangingViewPositions(boolean changingViewPositions) {
@@ -471,12 +502,7 @@
}
public boolean hasOverflow() {
- if (mIsStaticLayout) {
- return getChildCount() > MAX_STATIC_ICONS;
- }
-
- float width = (getChildCount() + OVERFLOW_EARLY_AMOUNT) * mIconSize;
- return width - (getWidth() - getActualPaddingStart() - getActualPaddingEnd()) > 0;
+ return mNumDots > 0;
}
/**
@@ -486,12 +512,7 @@
* This method has no meaning for non-static containers
*/
public boolean hasPartialOverflow() {
- if (mIsStaticLayout) {
- int count = getChildCount();
- return count > MAX_STATIC_ICONS && count <= MAX_STATIC_ICONS + MAX_DOTS;
- }
-
- return false;
+ return mNumDots > 0 && mNumDots < MAX_DOTS;
}
/**
@@ -504,7 +525,30 @@
return 0;
}
- return (MAX_STATIC_ICONS + MAX_DOTS - getChildCount()) * (mStaticDotRadius + mDotPadding);
+ int partialOverflowAmount = (MAX_DOTS - mNumDots) * (mStaticDotRadius * 2 + mDotPadding);
+
+ int adjustedWidth = getFinalTranslationX() + partialOverflowAmount;
+ // In case we actually give too much padding...
+ if (adjustedWidth > getWidth()) {
+ partialOverflowAmount = getWidth() - getFinalTranslationX();
+ }
+
+ return partialOverflowAmount;
+ }
+
+ // Give some extra room for btw notifications if we can
+ public int getNoOverflowExtraPadding() {
+ if (mNumDots != 0) {
+ return 0;
+ }
+
+ int collapsedPadding = (int) ((1.0f + OVERFLOW_EARLY_AMOUNT) * getIconSize());
+
+ if (collapsedPadding + getFinalTranslationX() > getWidth()) {
+ collapsedPadding = getWidth() - getFinalTranslationX();
+ }
+
+ return collapsedPadding;
}
public int getIconSize() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 51d094e..9d2480b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -205,7 +205,6 @@
private int mQsFalsingThreshold;
private float mKeyguardStatusBarAnimateAlpha = 1f;
- private float mQsClockAlphaOverride = 1f;
private int mOldLayoutDirection;
private HeadsUpTouchHelper mHeadsUpTouchHelper;
private boolean mIsExpansionFromHeadsUp;
@@ -583,7 +582,7 @@
private void updateClock() {
if (!mKeyguardStatusViewAnimating) {
- mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha * mQsClockAlphaOverride);
+ mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
}
}
@@ -1310,15 +1309,6 @@
mQsNavbarScrim.setAlpha(getQsExpansionFraction());
}
- // Fade clock when QS is on top of it
- float newClockAlpha = (height - mKeyguardStatusView.getY()) /
- mKeyguardStatusView.getHeight();
- newClockAlpha = 1 - MathUtils.constrain(newClockAlpha, 0, 1);
- if (newClockAlpha != mQsClockAlphaOverride) {
- mQsClockAlphaOverride = Interpolators.ALPHA_OUT.getInterpolation(newClockAlpha);
- updateClock();
- }
-
if (mAccessibilityManager.isEnabled()) {
setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 747a551..c326fee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -762,20 +762,31 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
- action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
- updateVolumeZen();
- } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
- updateSimState(intent);
- } else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
- updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
- TelecomManager.TTY_MODE_OFF));
- } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) ||
- action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) ||
- action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) {
- updateManagedProfile();
- } else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
- updateHeadsetPlug(intent);
+ switch (action) {
+ case AudioManager.RINGER_MODE_CHANGED_ACTION:
+ case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:
+ updateVolumeZen();
+ break;
+ case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
+ // Avoid rebroadcast because SysUI is direct boot aware.
+ if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK,
+ false)) {
+ break;
+ }
+ updateSimState(intent);
+ break;
+ case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:
+ updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
+ TelecomManager.TTY_MODE_OFF));
+ break;
+ case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
+ case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
+ case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+ updateManagedProfile();
+ break;
+ case AudioManager.ACTION_HEADSET_PLUG:
+ updateHeadsetPlug(intent);
+ break;
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index cc5a93c..900ec0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -264,7 +264,7 @@
mScrimController.setPanelExpansion(scrimFraction);
}
- public void onDensityOrFontScaleChanged() {
+ public void updateResources() {
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = getResources().getDimensionPixelSize(
R.dimen.status_bar_height);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 255e5e4..d8d388c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -167,6 +167,7 @@
private Callback mCallback;
private boolean mWallpaperSupportsAmbientMode;
private boolean mScreenOn;
+ private float mNotificationDensity;
// Scrim blanking callbacks
private Choreographer.FrameCallback mPendingFrameCallback;
@@ -251,7 +252,7 @@
mCurrentInFrontTint = state.getFrontTint();
mCurrentBehindTint = state.getBehindTint();
mCurrentInFrontAlpha = state.getFrontAlpha();
- mCurrentBehindAlpha = state.getBehindAlpha();
+ mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
applyExpansionToAlpha();
// Cancel blanking transitions that were pending before we requested a new state
@@ -396,12 +397,13 @@
// Either darken of make the scrim transparent when you
// pull down the shade
float interpolatedFract = getInterpolatedFraction();
+ float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
if (mDarkenWhileDragging) {
- mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking,
- mScrimBehindAlphaKeyguard, interpolatedFract);
+ mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking, alphaBehind,
+ interpolatedFract);
mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
} else {
- mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, mScrimBehindAlphaKeyguard,
+ mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
interpolatedFract);
mCurrentInFrontAlpha = 0;
}
@@ -415,15 +417,14 @@
public void setNotificationCount(int notificationCount) {
final float maxNotificationDensity = 3;
float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
- float newAlpha = MathUtils.map(0, 1,
- GRADIENT_SCRIM_ALPHA, GRADIENT_SCRIM_ALPHA_BUSY,
- notificationDensity);
- if (mScrimBehindAlphaKeyguard != newAlpha) {
- mScrimBehindAlphaKeyguard = newAlpha;
+ if (mNotificationDensity == notificationDensity) {
+ return;
+ }
+ mNotificationDensity = notificationDensity;
- if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
- scheduleUpdate();
- }
+ if (mState == ScrimState.KEYGUARD) {
+ applyExpansionToAlpha();
+ scheduleUpdate();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 381e4af..053c5a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -18,6 +18,7 @@
import android.graphics.Color;
import android.os.Trace;
+import android.util.MathUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.statusbar.ScrimView;
@@ -55,6 +56,13 @@
mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
mCurrentInFrontAlpha = 0;
}
+
+ @Override
+ public float getBehindAlpha(float busynessFactor) {
+ return MathUtils.map(0 /* start */, 1 /* stop */,
+ ScrimController.GRADIENT_SCRIM_ALPHA, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY,
+ busynessFactor);
+ }
},
/**
@@ -183,7 +191,7 @@
return mCurrentInFrontAlpha;
}
- public float getBehindAlpha() {
+ public float getBehindAlpha(float busyness) {
return mCurrentBehindAlpha;
}
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 933c952..86e618e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -180,6 +180,7 @@
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.AppOpsListener;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -210,7 +211,6 @@
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -240,7 +240,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -407,6 +406,7 @@
protected NotificationLogger mNotificationLogger;
protected NotificationEntryManager mEntryManager;
protected NotificationViewHierarchyManager mViewHierarchyManager;
+ protected AppOpsListener mAppOpsListener;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -624,6 +624,8 @@
mMediaManager = Dependency.get(NotificationMediaManager.class);
mEntryManager = Dependency.get(NotificationEntryManager.class);
mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
+ mAppOpsListener = Dependency.get(AppOpsListener.class);
+ mAppOpsListener.setUpWithPresenter(this, mEntryManager);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
@@ -815,6 +817,7 @@
mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
mVisualStabilityManager);
+ Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanel);
mHeadsUpManager.addListener(mGroupManager);
@@ -1071,7 +1074,6 @@
// end old BaseStatusBar.onDensityOrFontScaleChanged().
mScrimController.onDensityOrFontScaleChanged();
// TODO: Remove this.
- if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged();
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onDensityOrFontScaleChanged();
}
@@ -3081,6 +3083,9 @@
loadDimens();
+ if (mStatusBarView != null) {
+ mStatusBarView.updateResources();
+ }
if (mNotificationPanel != null) {
mNotificationPanel.updateResources();
}
@@ -3295,6 +3300,7 @@
Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
mDeviceProvisionedController.removeCallback(mUserSetupObserver);
Dependency.get(ConfigurationController.class).removeCallback(this);
+ mAppOpsListener.destroy();
}
private boolean mDemoModeAllowed;
@@ -4521,7 +4527,7 @@
if (isScreenTurningOnOrOn()) {
if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.hideBouncer(false /* destroyView */);
+ mStatusBarKeyguardViewManager.reset(true /* hide */);
}
mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
updateScrimController();
@@ -4727,7 +4733,7 @@
@Override
public boolean isPowerSaveActive() {
- return mBatteryController.isPowerSave();
+ return mBatteryController.isAodPowerSave();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 07610ce..956bebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -18,6 +18,7 @@
import static android.app.StatusBarManager.DISABLE_NONE;
import android.content.Context;
+import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -29,6 +30,7 @@
import android.widget.LinearLayout.LayoutParams;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -109,6 +111,20 @@
super.onSetIcon(viewIndex, icon);
mDarkIconDispatcher.applyDark((ImageView) mGroup.getChildAt(viewIndex));
}
+
+ @Override
+ protected DemoStatusIcons createDemoStatusIcons() {
+ DemoStatusIcons icons = super.createDemoStatusIcons();
+ mDarkIconDispatcher.addDarkReceiver(icons);
+
+ return icons;
+ }
+
+ @Override
+ protected void exitDemoMode() {
+ mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons);
+ super.exitDemoMode();
+ }
}
public static class TintedIconManager extends IconManager {
@@ -134,15 +150,28 @@
}
}
}
+
+ @Override
+ protected DemoStatusIcons createDemoStatusIcons() {
+ DemoStatusIcons icons = super.createDemoStatusIcons();
+ icons.setColor(mColor);
+ return icons;
+ }
}
/**
* Turns info from StatusBarIconController into ImageViews in a ViewGroup.
*/
- public static class IconManager {
+ public static class IconManager implements DemoMode {
protected final ViewGroup mGroup;
protected final Context mContext;
protected final int mIconSize;
+ // Whether or not these icons show up in dumpsys
+ protected boolean mShouldLog = false;
+
+ // Enables SystemUI demo mode to take effect in this group
+ protected boolean mDemoable = true;
+ protected DemoStatusIcons mDemoStatusIcons;
public IconManager(ViewGroup group) {
mGroup = group;
@@ -159,6 +188,22 @@
}
}
+ public boolean isDemoable() {
+ return mDemoable;
+ }
+
+ public void setIsDemoable(boolean demoable) {
+ mDemoable = demoable;
+ }
+
+ public void setShouldLog(boolean should) {
+ mShouldLog = should;
+ }
+
+ public boolean shouldLog() {
+ return mShouldLog;
+ }
+
protected void onIconAdded(int index, String slot, boolean blocked,
StatusBarIcon icon) {
addIcon(index, slot, blocked, icon);
@@ -218,5 +263,31 @@
StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
view.set(icon);
}
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (!mDemoable) {
+ return;
+ }
+
+ if (mDemoStatusIcons != null && command.equals(COMMAND_EXIT)) {
+ mDemoStatusIcons.dispatchDemoCommand(command, args);
+ exitDemoMode();
+ } else {
+ if (mDemoStatusIcons == null) {
+ mDemoStatusIcons = createDemoStatusIcons();
+ }
+ mDemoStatusIcons.dispatchDemoCommand(command, args);
+ }
+ }
+
+ protected void exitDemoMode() {
+ mDemoStatusIcons.remove();
+ mDemoStatusIcons = null;
+ }
+
+ protected DemoStatusIcons createDemoStatusIcons() {
+ return new DemoStatusIcons((LinearLayout) mGroup, mIconSize);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 1c3ee75..8f5e705 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -41,6 +41,8 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import static com.android.systemui.statusbar.phone.CollapsedStatusBarFragment.STATUS_BAR_ICON_MANAGER_TAG;
+
/**
* Receives the callbacks from CommandQueue related to icons and tracks the state of
* all the icons. Dispatches this state to any IconManagers that are currently
@@ -48,6 +50,7 @@
*/
public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable,
ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController {
+ private static final String TAG = "StatusBarIconController";
private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
private final ArraySet<String> mIconBlacklist = new ArraySet<>();
@@ -55,6 +58,7 @@
private Context mContext;
private DemoStatusIcons mDemoStatusIcons;
+ private IconManager mStatusBarIconManager;
public StatusBarIconControllerImpl(Context context) {
super(context.getResources().getStringArray(
@@ -197,26 +201,28 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- // TODO: Dump info about all icon groups?
- ViewGroup statusIcons = mIconGroups.get(0).mGroup;
- int N = statusIcons.getChildCount();
- pw.println(" icon views: " + N);
- for (int i = 0; i < N; i++) {
- StatusBarIconView ic = (StatusBarIconView) statusIcons.getChildAt(i);
- pw.println(" [" + i + "] icon=" + ic);
+ pw.println(TAG + " state:");
+ for (IconManager manager : mIconGroups) {
+ if (manager.shouldLog()) {
+ ViewGroup group = manager.mGroup;
+ int N = group.getChildCount();
+ pw.println(" icon views: " + N);
+ for (int i = 0; i < N; i++) {
+ StatusBarIconView ic = (StatusBarIconView) group.getChildAt(i);
+ pw.println(" [" + i + "] icon=" + ic);
+ }
+ }
}
+
super.dump(pw);
}
public void dispatchDemoCommand(String command, Bundle args) {
- if (mDemoStatusIcons == null) {
- // TODO: Rework how we handle demo mode.
- int iconSize = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size);
- mDemoStatusIcons = new DemoStatusIcons((LinearLayout) mIconGroups.get(0).mGroup,
- iconSize);
+ for (IconManager manager : mIconGroups) {
+ if (manager.isDemoable()) {
+ manager.dispatchDemoCommand(command, args);
+ }
}
- mDemoStatusIcons.dispatchDemoCommand(command, args);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
index f600908..1aa3a43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -77,6 +77,7 @@
}
public void dump(PrintWriter pw) {
+ pw.println("StatusBarIconList state:");
final int N = mSlots.size();
pw.println(" icon slots: " + N);
for (int i=0; i<N; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 47ea3a7..a009d80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.os.Bundle;
import android.os.SystemClock;
+import android.util.StatsLog;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -140,6 +141,8 @@
mShowing = true;
mStatusBarWindowManager.setKeyguardShowing(true);
reset(true /* hideBouncerWhenShowing */);
+ StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
+ StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
}
/**
@@ -161,7 +164,7 @@
updateStates();
}
- public void hideBouncer(boolean destroyView) {
+ private void hideBouncer(boolean destroyView) {
mBouncer.hide(destroyView);
cancelPendingWakeupAction();
}
@@ -289,6 +292,8 @@
public void setOccluded(boolean occluded, boolean animate) {
mStatusBar.setOccluded(occluded);
if (occluded && !mOccluded && mShowing) {
+ StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
+ StatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED);
if (mStatusBar.isInLaunchTransition()) {
mOccluded = true;
mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
@@ -301,6 +306,9 @@
});
return;
}
+ } else if (!occluded && mOccluded && mShowing) {
+ StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
+ StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
}
boolean isOccluding = !mOccluded && occluded;
mOccluded = occluded;
@@ -398,6 +406,8 @@
mStatusBarWindowManager.setKeyguardShowing(false);
mViewMediatorCallback.keyguardGone();
}
+ StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
+ StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
}
public void onDensityOrFontScaleChanged() {
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 503a1b4..dba89479 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-/**
- * A container for Status bar system icons. Limits the number of system icons and handles overflow
- * similar to NotificationIconController. Can be used to layout nested StatusIconContainers
- *
- * Children are expected to be of type StatusBarIconView.
- */
package com.android.systemui.statusbar.phone;
import android.annotation.Nullable;
@@ -33,6 +27,12 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.stack.ViewState;
+/**
+ * A container for Status bar system icons. Limits the number of system icons and handles overflow
+ * similar to NotificationIconController. Can be used to layout nested StatusIconContainers
+ *
+ * Children are expected to be of type StatusBarIconView.
+ */
public class StatusIconContainer extends AlphaOptimizedLinearLayout {
private static final String TAG = "StatusIconContainer";
@@ -40,6 +40,10 @@
private static final int MAX_ICONS = 5;
private static final int MAX_DOTS = 3;
+ public StatusIconContainer(Context context) {
+ this(context, null);
+ }
+
public StatusIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 641fe69..6f4026d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -41,6 +41,13 @@
boolean isPowerSave();
/**
+ * Returns {@code true} if AOD was disabled by power saving policies.
+ */
+ default boolean isAodPowerSave() {
+ return isPowerSave();
+ }
+
+ /**
* A listener that will be notified whenever a change in battery level or power save mode
* has occurred.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index e8d5af6..49f880c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -24,8 +24,10 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
+import android.os.PowerSaveState;
import android.util.Log;
-import com.android.systemui.DemoMode;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -52,13 +54,19 @@
protected boolean mCharging;
protected boolean mCharged;
protected boolean mPowerSave;
+ protected boolean mAodPowerSave;
private boolean mTestmode = false;
private boolean mHasReceivedBattery = false;
public BatteryControllerImpl(Context context) {
+ this(context, context.getSystemService(PowerManager.class));
+ }
+
+ @VisibleForTesting
+ BatteryControllerImpl(Context context, PowerManager powerManager) {
mContext = context;
mHandler = new Handler();
- mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mPowerManager = powerManager;
registerReceiver();
updatePowerSave();
@@ -166,6 +174,11 @@
return mPowerSave;
}
+ @Override
+ public boolean isAodPowerSave() {
+ return mAodPowerSave;
+ }
+
private void updatePowerSave() {
setPowerSave(mPowerManager.isPowerSaveMode());
}
@@ -173,6 +186,11 @@
private void setPowerSave(boolean powerSave) {
if (powerSave == mPowerSave) return;
mPowerSave = powerSave;
+
+ // AOD power saving setting might be different from PowerManager power saving mode.
+ PowerSaveState state = mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD);
+ mAodPowerSave = state.batterySaverEnabled;
+
if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off"));
firePowerSaveChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index a2bec98..cc7943b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -26,11 +26,9 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
import android.view.DisplayListCanvas;
import android.view.RenderNodeAnimator;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
import com.android.systemui.Interpolators;
@@ -58,17 +56,14 @@
private float mGlowAlpha = 0f;
private float mGlowScale = 1f;
private boolean mPressed;
- private boolean mVisible;
private boolean mDrawingHardwareGlow;
private int mMaxWidth;
private boolean mLastDark;
private boolean mDark;
- private boolean mDelayTouchFeedback;
private final Interpolator mInterpolator = new LogInterpolator();
private boolean mSupportHardware;
private final View mTargetView;
- private final Handler mHandler = new Handler();
private final HashSet<Animator> mRunningAnimations = new HashSet<>();
private final ArrayList<Animator> mTmpArray = new ArrayList<>();
@@ -82,10 +77,6 @@
mDark = darkIntensity >= 0.5f;
}
- public void setDelayTouchFeedback(boolean delay) {
- mDelayTouchFeedback = delay;
- }
-
private Paint getRipplePaint() {
if (mRipplePaint == null) {
mRipplePaint = new Paint();
@@ -220,16 +211,7 @@
}
}
- /**
- * Abort the ripple while it is delayed and before shown used only when setShouldDelayStartTouch
- * is enabled.
- */
- public void abortDelayedRipple() {
- mHandler.removeCallbacksAndMessages(null);
- }
-
private void cancelAnimations() {
- mVisible = false;
mTmpArray.addAll(mRunningAnimations);
int size = mTmpArray.size();
for (int i = 0; i < size; i++) {
@@ -238,21 +220,11 @@
}
mTmpArray.clear();
mRunningAnimations.clear();
- mHandler.removeCallbacksAndMessages(null);
}
private void setPressedSoftware(boolean pressed) {
if (pressed) {
- if (mDelayTouchFeedback) {
- if (mRunningAnimations.isEmpty()) {
- mHandler.removeCallbacksAndMessages(null);
- mHandler.postDelayed(this::enterSoftware, ViewConfiguration.getTapTimeout());
- } else if (mVisible) {
- enterSoftware();
- }
- } else {
- enterSoftware();
- }
+ enterSoftware();
} else {
exitSoftware();
}
@@ -260,7 +232,6 @@
private void enterSoftware() {
cancelAnimations();
- mVisible = true;
mGlowAlpha = getMaxGlowAlpha();
ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale",
0f, GLOW_MAX_SCALE_FACTOR);
@@ -269,12 +240,6 @@
scaleAnimator.addListener(mAnimatorListener);
scaleAnimator.start();
mRunningAnimations.add(scaleAnimator);
-
- // With the delay, it could eventually animate the enter animation with no pressed state,
- // then immediately show the exit animation. If this is skipped there will be no ripple.
- if (mDelayTouchFeedback && !mPressed) {
- exitSoftware();
- }
}
private void exitSoftware() {
@@ -288,16 +253,7 @@
private void setPressedHardware(boolean pressed) {
if (pressed) {
- if (mDelayTouchFeedback) {
- if (mRunningAnimations.isEmpty()) {
- mHandler.removeCallbacksAndMessages(null);
- mHandler.postDelayed(this::enterHardware, ViewConfiguration.getTapTimeout());
- } else if (mVisible) {
- enterHardware();
- }
- } else {
- enterHardware();
- }
+ enterHardware();
} else {
exitHardware();
}
@@ -346,7 +302,6 @@
private void enterHardware() {
cancelAnimations();
- mVisible = true;
mDrawingHardwareGlow = true;
setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(),
@@ -388,12 +343,6 @@
mRunningAnimations.add(endAnim);
invalidateSelf();
-
- // With the delay, it could eventually animate the enter animation with no pressed state,
- // then immediately show the exit animation. If this is skipped there will be no ripple.
- if (mDelayTouchFeedback && !mPressed) {
- exitHardware();
- }
}
private void exitHardware() {
@@ -417,7 +366,6 @@
public void onAnimationEnd(Animator animation) {
mRunningAnimations.remove(animation);
if (mRunningAnimations.isEmpty() && !mPressed) {
- mVisible = false;
mDrawingHardwareGlow = false;
invalidateSelf();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 98bebec..e7b802d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -67,6 +67,7 @@
private int mTouchSlop;
private int mTouchDownX;
private int mTouchDownY;
+ private boolean mIsPressed;
private boolean mSupportsLongpress = true;
private AudioManager mAudioManager;
private boolean mGestureAborted;
@@ -79,7 +80,7 @@
private final Runnable mCheckLongPress = new Runnable() {
public void run() {
- if (isPressed()) {
+ if (mIsPressed) {
// Log.d("KeyButtonView", "longpressed: " + this);
if (isLongClickable()) {
// Just an old-fashioned ImageView
@@ -90,6 +91,12 @@
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
mLongClicked = true;
}
+
+ // Only when quick step is enabled, ripple will not be shown on touch down, then
+ // show the ripple on touch up or on long press
+ if (mLongClicked && mOverviewProxyService.getProxy() != null) {
+ setPressed(true);
+ }
}
}
};
@@ -216,7 +223,6 @@
case MotionEvent.ACTION_DOWN:
mDownTime = SystemClock.uptimeMillis();
mLongClicked = false;
- setPressed(true);
mTouchDownX = (int) ev.getX();
mTouchDownY = (int) ev.getY();
if (mCode != 0) {
@@ -225,6 +231,7 @@
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
+ mIsPressed = true;
if (isProxyConnected) {
// Provide small vibration for quick step or immediate down feedback
AsyncTask.execute(() ->
@@ -232,6 +239,7 @@
.get(VibrationEffect.EFFECT_TICK, false)));
} else {
playSoundEffect(SoundEffectConstants.CLICK);
+ setPressed(mIsPressed);
}
removeCallbacks(mCheckLongPress);
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
@@ -242,7 +250,12 @@
boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop;
boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop;
if (exceededTouchSlopX || exceededTouchSlopY) {
- setPressed(false);
+ // When quick step is enabled, prevent animating the ripple triggered by
+ // setPressed and decide to run it on touch up
+ mIsPressed = false;
+ if (!isProxyConnected) {
+ setPressed(mIsPressed);
+ }
removeCallbacks(mCheckLongPress);
}
break;
@@ -254,10 +267,11 @@
removeCallbacks(mCheckLongPress);
break;
case MotionEvent.ACTION_UP:
- final boolean doIt = isPressed() && !mLongClicked;
- setPressed(false);
+ final boolean doIt = mIsPressed && !mLongClicked;
if (isProxyConnected) {
if (doIt) {
+ // Animate the ripple in on touch up with setPressed and then out later
+ setPressed(true);
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
playSoundEffect(SoundEffectConstants.CLICK);
}
@@ -266,6 +280,7 @@
// and it feels weird to sometimes get a release haptic and other times not.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
}
+ setPressed(false);
if (mCode != 0) {
if (doIt) {
// If there was a pending remote recents animation, then we need to
@@ -295,6 +310,12 @@
mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser());
}
+ @Override
+ public void setPressed(boolean pressed) {
+ mIsPressed = pressed;
+ super.setPressed(pressed);
+ }
+
public void sendEvent(int action, int flags) {
sendEvent(action, flags, SystemClock.uptimeMillis());
}
@@ -317,7 +338,6 @@
@Override
public void abortCurrentGesture() {
setPressed(false);
- mRipple.abortDelayedRipple();
mGestureAborted = true;
}
@@ -336,7 +356,6 @@
@Override
public void setDelayTouchFeedback(boolean shouldDelay) {
- mRipple.setDelayTouchFeedback(shouldDelay);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index baf0ebf..5363742 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -403,54 +403,62 @@
Log.d(TAG, "onReceive: intent=" + intent);
}
final String action = intent.getAction();
- if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
- action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
- updateConnectivity();
- } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- refreshLocale();
- updateAirplaneMode(false);
- } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) {
- // We are using different subs now, we might be able to make calls.
- recalculateEmergency();
- } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
- // Notify every MobileSignalController so they can know whether they are the
- // data sim or not.
- for (int i = 0; i < mMobileSignalControllers.size(); i++) {
- MobileSignalController controller = mMobileSignalControllers.valueAt(i);
- controller.handleBroadcast(intent);
- }
- } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
- // Might have different subscriptions now.
- updateMobileControllers();
- } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
- mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
- if (mMobileSignalControllers.size() == 0) {
- // If none of the subscriptions are active, we might need to recalculate
- // emergency state.
+ switch (action) {
+ case ConnectivityManager.CONNECTIVITY_ACTION:
+ case ConnectivityManager.INET_CONDITION_ACTION:
+ updateConnectivity();
+ break;
+ case Intent.ACTION_AIRPLANE_MODE_CHANGED:
+ refreshLocale();
+ updateAirplaneMode(false);
+ break;
+ case TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
+ // We are using different subs now, we might be able to make calls.
recalculateEmergency();
- }
- } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
- mConfig = Config.readConfig(mContext);
- mReceiverHandler.post(new Runnable() {
- @Override
- public void run() {
- handleConfigurationChanged();
+ break;
+ case TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
+ // Notify every MobileSignalController so they can know whether they are the
+ // data sim or not.
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
+ controller.handleBroadcast(intent);
}
- });
- } else {
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
- if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
- mMobileSignalControllers.get(subId).handleBroadcast(intent);
+ break;
+ case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
+ // Avoid rebroadcast because SysUI is direct boot aware.
+ if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+ break;
+ }
+ // Might have different subscriptions now.
+ updateMobileControllers();
+ break;
+ case TelephonyIntents.ACTION_SERVICE_STATE_CHANGED:
+ mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
+ if (mMobileSignalControllers.size() == 0) {
+ // If none of the subscriptions are active, we might need to recalculate
+ // emergency state.
+ recalculateEmergency();
+ }
+ break;
+ case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
+ mConfig = Config.readConfig(mContext);
+ mReceiverHandler.post(this::handleConfigurationChanged);
+ break;
+ default:
+ int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
+ mMobileSignalControllers.get(subId).handleBroadcast(intent);
+ } else {
+ // Can't find this subscription... We must be out of date.
+ updateMobileControllers();
+ }
} else {
- // Can't find this subscription... We must be out of date.
- updateMobileControllers();
+ // No sub id, must be for the wifi.
+ mWifiSignalController.handleBroadcast(intent);
}
- } else {
- // No sub id, must be for the wifi.
- mWifiSignalController.handleBroadcast(intent);
- }
+ break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 1b55a5b..66fde79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1394,6 +1394,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
float densityScale = getResources().getDisplayMetrics().density;
mSwipeHelper.setDensityScale(densityScale);
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
new file mode 100644
index 0000000..21483aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.keyguard;
+
+import android.content.Intent;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class KeyguardUpdateMonitorTest extends SysuiTestCase {
+
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setup() {
+ mTestableLooper = TestableLooper.get(this);
+ }
+
+ @Test
+ public void testIgnoresSimStateCallback_rebroadcast() {
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+
+ AtomicBoolean simStateChanged = new AtomicBoolean(false);
+ KeyguardUpdateMonitor keyguardUpdateMonitor = new KeyguardUpdateMonitor(getContext()) {
+ @Override
+ protected void handleSimStateChange(int subId, int slotId,
+ IccCardConstants.State state) {
+ simStateChanged.set(true);
+ super.handleSimStateChange(subId, slotId, state);
+ }
+ };
+
+ keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent);
+ mTestableLooper.processAllMessages();
+ Assert.assertTrue("onSimStateChanged not called", simStateChanged.get());
+
+ intent.putExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, true);
+ simStateChanged.set(false);
+ keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent);
+ mTestableLooper.processAllMessages();
+ Assert.assertFalse("onSimStateChanged should have been skipped", simStateChanged.get());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 943020c..18dd3c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -16,6 +16,14 @@
package com.android.systemui;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.annotation.UserIdInt;
import android.app.Notification;
import android.app.NotificationManager;
@@ -24,17 +32,14 @@
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.widget.RemoteViews;
+
import com.android.internal.messages.nano.SystemMessageProto;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ForegroundServiceControllerTest extends SysuiTestCase {
@@ -49,7 +54,7 @@
}
@Test
- public void testNotificationCRUD() {
+ public void testNotificationCRUD_dungeon() {
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, "com.example.app1");
StatusBarNotification sbn_user2_app2_fg = makeMockFgSBN(USERID_TWO, "com.example.app2");
StatusBarNotification sbn_user1_app3_fg = makeMockFgSBN(USERID_ONE, "com.example.app3");
@@ -98,6 +103,101 @@
}
@Test
+ public void testNotificationCRUD_stdLayout() {
+ StatusBarNotification sbn_user1_app1_fg =
+ makeMockFgSBN(USERID_ONE, "com.example.app1", 0, true);
+ StatusBarNotification sbn_user2_app2_fg =
+ makeMockFgSBN(USERID_TWO, "com.example.app2", 1, true);
+ StatusBarNotification sbn_user1_app3_fg =
+ makeMockFgSBN(USERID_ONE, "com.example.app3", 2, true);
+ StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+ StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
+ 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
+
+ assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
+ assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+
+ fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
+ fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
+ fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
+
+ // these are never added to the tracker
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+
+ fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
+ fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
+ // should still not be there
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+
+ fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
+ fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
+ fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+
+ assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
+
+ assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
+ assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
+
+ assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
+ assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
+
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.removeNotification(sbn_user2_app1));
+ }
+
+ @Test
+ public void testAppOpsCRUD() {
+ // no crash on remove that doesn't exist
+ fsc.onAppOpChanged(9, 1000, "pkg1", false);
+ assertNull(fsc.getAppOps(0, "pkg1"));
+
+ // multiuser & multipackage
+ fsc.onAppOpChanged(8, 50, "pkg1", true);
+ fsc.onAppOpChanged(1, 60, "pkg3", true);
+ fsc.onAppOpChanged(7, 500000, "pkg2", true);
+
+ assertEquals(1, fsc.getAppOps(0, "pkg1").size());
+ assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
+
+ assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+ assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+
+ assertEquals(1, fsc.getAppOps(0, "pkg3").size());
+ assertTrue(fsc.getAppOps(0, "pkg3").contains(1));
+
+ // multiple ops for the same package
+ fsc.onAppOpChanged(9, 50, "pkg1", true);
+ fsc.onAppOpChanged(5, 50, "pkg1", true);
+
+ assertEquals(3, fsc.getAppOps(0, "pkg1").size());
+ assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
+ assertTrue(fsc.getAppOps(0, "pkg1").contains(9));
+ assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+
+ assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+ assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+
+ // remove one of the multiples
+ fsc.onAppOpChanged(9, 50, "pkg1", false);
+ assertEquals(2, fsc.getAppOps(0, "pkg1").size());
+ assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
+ assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+
+ // remove last op
+ fsc.onAppOpChanged(1, 60, "pkg3", false);
+ assertNull(fsc.getAppOps(0, "pkg3"));
+ }
+
+ @Test
public void testDungeonPredicate() {
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
@@ -252,6 +352,14 @@
assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ // importance upgrade
+ fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ fsc.updateNotification(sbn_user1_app1_fg,
+ NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
+
// finally, let's turn off the service
fsc.addNotification(makeMockDungeon(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
@@ -260,12 +368,71 @@
assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
}
+ @Test
+ public void testStdLayoutBasic() {
+ final String PKG1 = "com.example.app0";
+
+ StatusBarNotification sbn_user1_app1 = makeMockFgSBN(USERID_ONE, PKG1, 0, true);
+ sbn_user1_app1.getNotification().flags = 0;
+ StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
+ assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
+ // let's take out the non-fg notification and see what happens.
+ fsc.removeNotification(sbn_user1_app1);
+ // still covered by sbn_user1_app1_fg
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
+
+ // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
+ StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
+ sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
+ fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+ // ok, ok, we'll put it back
+ sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+ fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
+
+ assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
+ assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
+
+ // let's try a custom layout
+ sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, false);
+ fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+ // now let's test an upgrade (non fg to fg)
+ fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
+ sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ fsc.updateNotification(sbn_user1_app1,
+ NotificationManager.IMPORTANCE_MIN); // this is now a fg notification
+
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+
+ // remove it, make sure we're out of compliance again
+ assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
+ assertFalse(fsc.removeNotification(sbn_user1_app1));
+ assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+ assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ }
+
private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
int flags) {
final Notification n = mock(Notification.class);
+ n.extras = new Bundle();
n.flags = flags;
return makeMockSBN(userid, pkg, id, tag, n);
}
+
private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
Notification n) {
final StatusBarNotification sbn = mock(StatusBarNotification.class);
@@ -278,9 +445,25 @@
when(sbn.getKey()).thenReturn("MOCK:"+userid+"|"+pkg+"|"+id+"|"+tag);
return sbn;
}
+
+ private StatusBarNotification makeMockFgSBN(int userid, String pkg, int id,
+ boolean usesStdLayout) {
+ StatusBarNotification sbn =
+ makeMockSBN(userid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE);
+ if (usesStdLayout) {
+ sbn.getNotification().contentView = null;
+ sbn.getNotification().headsUpContentView = null;
+ sbn.getNotification().bigContentView = null;
+ } else {
+ sbn.getNotification().contentView = mock(RemoteViews.class);
+ }
+ return sbn;
+ }
+
private StatusBarNotification makeMockFgSBN(int userid, String pkg) {
return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
}
+
private StatusBarNotification makeMockDungeon(int userid, String[] pkgs) {
final Notification n = mock(Notification.class);
n.flags = Notification.FLAG_ONGOING_EVENT;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index cd409d8..b6116e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -16,10 +16,17 @@
package com.android.systemui.keyguard;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
import androidx.app.slice.Slice;
+
+import android.app.AlarmManager;
+import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
-import android.os.Debug;
import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -32,24 +39,31 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
import androidx.app.slice.SliceItem;
import androidx.app.slice.SliceProvider;
import androidx.app.slice.SliceSpecs;
import androidx.app.slice.core.SliceQuery;
-import androidx.app.slice.widget.SliceLiveData;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
public class KeyguardSliceProviderTest extends SysuiTestCase {
+ @Mock
+ private ContentResolver mContentResolver;
+ @Mock
+ private AlarmManager mAlarmManager;
private TestableKeyguardSliceProvider mProvider;
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
mProvider = new TestableKeyguardSliceProvider();
mProvider.attachInfo(getContext(), null);
SliceProvider.setSpecs(Arrays.asList(SliceSpecs.LIST));
@@ -70,7 +84,7 @@
@Test
public void returnsValidSlice() {
- Slice slice = mProvider.onBindSlice(Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI));
+ Slice slice = mProvider.onBindSlice(mProvider.getUri());
SliceItem text = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_TEXT,
android.app.slice.Slice.HINT_TITLE,
null /* nonHints */);
@@ -87,21 +101,52 @@
@Test
public void updatesClock() {
- mProvider.mUpdateClockInvokations = 0;
mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK));
TestableLooper.get(this).processAllMessages();
- Assert.assertEquals("Clock should have been updated.", 1 /* expected */,
- mProvider.mUpdateClockInvokations);
+ verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+ }
+
+ @Test
+ public void schedulesAlarm12hBefore() {
+ long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(16);
+ AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null);
+ mProvider.onNextAlarmChanged(alarmClockInfo);
+
+ long twelveHours = TimeUnit.HOURS.toMillis(KeyguardSliceProvider.ALARM_VISIBILITY_HOURS);
+ long triggerAt = in16Hours - twelveHours;
+ verify(mAlarmManager).setExact(eq(AlarmManager.RTC), eq(triggerAt), anyString(), any(),
+ any());
+ }
+
+ @Test
+ public void updatingNextAlarmInvalidatesSlice() {
+ long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(8);
+ AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null);
+ mProvider.onNextAlarmChanged(alarmClockInfo);
+
+ verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
}
private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
int mCleanDateFormatInvokations;
- int mUpdateClockInvokations;
+ private int mCounter;
TestableKeyguardSliceProvider() {
super(new Handler(TestableLooper.get(KeyguardSliceProviderTest.this).getLooper()));
}
+ Uri getUri() {
+ return mSliceUri;
+ }
+
+ @Override
+ public boolean onCreateSliceProvider() {
+ super.onCreateSliceProvider();
+ mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager;
+ mContentResolver = KeyguardSliceProviderTest.this.mContentResolver;
+ return true;
+ }
+
@Override
void cleanDateFormat() {
super.cleanDateFormat();
@@ -109,9 +154,8 @@
}
@Override
- protected void updateClock() {
- super.updateClock();
- mUpdateClockInvokations++;
+ protected String getFormattedDate() {
+ return super.getFormattedDate() + mCounter++;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 11491a75..2040e75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -54,7 +54,7 @@
// Layout needs to leave space for the tile margins. Three times the margin size is
// sufficient for any number of columns.
mLayoutSizeForOneTile =
- mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin) * 3;
+ mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) * 3;
}
private QSPanel.TileRecord createTileRecord() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
index 641cdc7..4cc0e20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
@@ -56,6 +56,28 @@
}
@Test
+ public void testSetValueFloat_threeValues() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 20, 50)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.25f);
+ assertEquals(10f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(20f, mTestView.getX());
+
+ animator.setPosition(.75f);
+ assertEquals(35f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ @Test
public void testSetValueInt() {
TouchAnimator animator = new TouchAnimator.Builder()
.addInt(mTestView, "top", 0, 50)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java
new file mode 100644
index 0000000..2a48c4b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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.statusbar;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AppOpsListenerTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test";
+ private static final int TEST_UID = 0;
+
+ @Mock private NotificationPresenter mPresenter;
+ @Mock private AppOpsManager mAppOpsManager;
+
+ // Dependency mocks:
+ @Mock private NotificationEntryManager mEntryManager;
+ @Mock private ForegroundServiceController mFsc;
+
+ private AppOpsListener mListener;
+ private Handler mHandler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
+ mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
+ getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager);
+ mHandler = new Handler(Looper.getMainLooper());
+ when(mPresenter.getHandler()).thenReturn(mHandler);
+
+ mListener = new AppOpsListener(mContext);
+ }
+
+ @Test
+ public void testOnlyListenForFewOps() {
+ mListener.setUpWithPresenter(mPresenter, mEntryManager);
+
+ verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsListener.OPS, mListener);
+ }
+
+ @Test
+ public void testStopListening() {
+ mListener.destroy();
+ verify(mAppOpsManager, times(1)).stopWatchingActive(mListener);
+ }
+
+ @Test
+ public void testInformEntryMgrOnAppOpsChange() {
+ mListener.setUpWithPresenter(mPresenter, mEntryManager);
+ mListener.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ waitForIdleSync(mHandler);
+ verify(mEntryManager, times(1)).updateNotificationsForAppOps(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ }
+
+ @Test
+ public void testInformFscOnAppOpsChange() {
+ mListener.setUpWithPresenter(mPresenter, mEntryManager);
+ mListener.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ waitForIdleSync(mHandler);
+ verify(mFsc, times(1)).onAppOpChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 544585a..ce629bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -19,10 +19,15 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import android.view.NotificationHeaderView;
import android.view.View;
import com.android.systemui.SysuiTestCase;
@@ -146,4 +151,34 @@
Assert.assertTrue("Should always play sounds when not trusted.",
mGroup.isSoundEffectsEnabled());
}
+
+ @Test
+ public void testShowAppOpsIcons_noHeader() {
+ // public notification is custom layout - no header
+ mGroup.setSensitive(true, true);
+ mGroup.showAppOpsIcons(new ArraySet<>());
+ }
+
+ @Test
+ public void testShowAppOpsIcons_header() throws Exception {
+ NotificationHeaderView mockHeader = mock(NotificationHeaderView.class);
+
+ NotificationContentView publicLayout = mock(NotificationContentView.class);
+ mGroup.setPublicLayout(publicLayout);
+ NotificationContentView privateLayout = mock(NotificationContentView.class);
+ mGroup.setPrivateLayout(privateLayout);
+ NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
+ when(mockContainer.getNotificationChildCount()).thenReturn(1);
+ when(mockContainer.getHeaderView()).thenReturn(mockHeader);
+ mGroup.setChildrenContainer(mockContainer);
+
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS);
+ mGroup.showAppOpsIcons(ops);
+
+ verify(mockHeader, times(1)).showAppOpsIcons(ops);
+ verify(privateLayout, times(1)).showAppOpsIcons(ops);
+ verify(publicLayout, times(1)).showAppOpsIcons(ops);
+
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
index 436849c..1fb4c37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
@@ -16,14 +16,23 @@
package com.android.systemui.statusbar;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import android.view.NotificationHeaderView;
import android.view.View;
import com.android.systemui.SysuiTestCase;
@@ -75,4 +84,35 @@
mView.setHeadsUpAnimatingAway(true);
Assert.assertFalse(mView.isAnimatingVisibleType());
}
+
+ @Test
+ @UiThreadTest
+ public void testShowAppOpsIcons() {
+ NotificationHeaderView mockContracted = mock(NotificationHeaderView.class);
+ when(mockContracted.findViewById(com.android.internal.R.id.notification_header))
+ .thenReturn(mockContracted);
+ NotificationHeaderView mockExpanded = mock(NotificationHeaderView.class);
+ when(mockExpanded.findViewById(com.android.internal.R.id.notification_header))
+ .thenReturn(mockExpanded);
+ NotificationHeaderView mockHeadsUp = mock(NotificationHeaderView.class);
+ when(mockHeadsUp.findViewById(com.android.internal.R.id.notification_header))
+ .thenReturn(mockHeadsUp);
+ NotificationHeaderView mockAmbient = mock(NotificationHeaderView.class);
+ when(mockAmbient.findViewById(com.android.internal.R.id.notification_header))
+ .thenReturn(mockAmbient);
+
+ mView.setContractedChild(mockContracted);
+ mView.setExpandedChild(mockExpanded);
+ mView.setHeadsUpChild(mockHeadsUp);
+ mView.setAmbientChild(mockAmbient);
+
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS);
+ mView.showAppOpsIcons(ops);
+
+ verify(mockContracted, times(1)).showAppOpsIcons(ops);
+ verify(mockExpanded, times(1)).showAppOpsIcons(ops);
+ verify(mockAmbient, never()).showAppOpsIcons(ops);
+ verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
index 972eddb..b1e1c02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
@@ -16,8 +16,16 @@
package com.android.systemui.statusbar;
+import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
+import static android.app.AppOpsManager.OP_CAMERA;
+
+import static junit.framework.Assert.assertEquals;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -33,7 +41,9 @@
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -41,6 +51,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -51,6 +63,10 @@
private final StatusBarNotification mMockStatusBarNotification =
mock(StatusBarNotification.class);
+ @Mock
+ ForegroundServiceController mFsc;
+ @Mock
+ NotificationData.Environment mEnvironment;
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
private NotificationData mNotificationData;
@@ -58,6 +74,7 @@
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
when(mMockPackageManager.checkUidPermission(
@@ -69,9 +86,11 @@
eq(UID_ALLOW_DURING_SETUP)))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- NotificationData.Environment mock = mock(NotificationData.Environment.class);
- when(mock.getGroupManager()).thenReturn(new NotificationGroupManager());
- mNotificationData = new TestableNotificationData(mock);
+ mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
+ when(mEnvironment.getGroupManager()).thenReturn(new NotificationGroupManager());
+ when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
+ when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
+ mNotificationData = new TestableNotificationData(mEnvironment);
mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
mRow = new NotificationTestHelper(getContext()).createRow();
}
@@ -117,6 +136,117 @@
Assert.assertTrue(mRow.getEntry().channel != null);
}
+ @Test
+ public void testAdd_appOpsAdded() {
+ ArraySet<Integer> expected = new ArraySet<>();
+ expected.add(3);
+ expected.add(235);
+ expected.add(1);
+ when(mFsc.getAppOps(mRow.getEntry().notification.getUserId(),
+ mRow.getEntry().notification.getPackageName())).thenReturn(expected);
+
+ mNotificationData.add(mRow.getEntry());
+ assertEquals(expected.size(),
+ mNotificationData.get(mRow.getEntry().key).mActiveAppOps.size());
+ for (int op : expected) {
+ assertTrue(" entry missing op " + op,
+ mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
+ }
+ }
+
+ @Test
+ public void testAdd_noExistingAppOps() {
+ when(mFsc.getAppOps(mRow.getEntry().notification.getUserId(),
+ mRow.getEntry().notification.getPackageName())).thenReturn(null);
+
+ mNotificationData.add(mRow.getEntry());
+ assertEquals(0, mNotificationData.get(mRow.getEntry().key).mActiveAppOps.size());
+ }
+
+ @Test
+ public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
+ mNotificationData.add(mRow.getEntry());
+ ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
+ mNotificationData.add(row2.getEntry());
+ ExpandableNotificationRow diffPkg =
+ new NotificationTestHelper(getContext()).createRow("pkg", 4000);
+ mNotificationData.add(diffPkg.getEntry());
+
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ expectedOps.add(OP_ACCEPT_HANDOVER);
+
+ for (int op : expectedOps) {
+ mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
+ NotificationTestHelper.PKG, true);
+ }
+ for (int op : expectedOps) {
+ assertTrue(mRow.getEntry().key + " doesn't have op " + op,
+ mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
+ assertTrue(row2.getEntry().key + " doesn't have op " + op,
+ mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
+ assertFalse(diffPkg.getEntry().key + " has op " + op,
+ mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
+ }
+ }
+
+ @Test
+ public void testAppOpsRemoval() throws Exception {
+ mNotificationData.add(mRow.getEntry());
+ ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
+ mNotificationData.add(row2.getEntry());
+
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ expectedOps.add(OP_ACCEPT_HANDOVER);
+
+ for (int op : expectedOps) {
+ mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
+ NotificationTestHelper.PKG, true);
+ }
+
+ expectedOps.remove(OP_ACCEPT_HANDOVER);
+ mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
+ NotificationTestHelper.PKG, false);
+
+ assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
+ mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
+ assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
+ mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
+ assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
+ mNotificationData.get(mRow.getEntry().key)
+ .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
+ assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
+ mNotificationData.get(row2.getEntry().key)
+ .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
+ }
+
+ @Test
+ public void testSuppressSystemAlertNotification() {
+ when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
+ when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
+
+ assertTrue(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
+ }
+
+ @Test
+ public void testDoNotSuppressSystemAlertNotification() {
+ when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
+ when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
+
+ assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
+
+ when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
+ when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
+
+ assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
+
+ when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
+ when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
+
+ assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
+ }
+
private void initStatusBarNotification(boolean allowDuringSetup) {
Bundle bundle = new Bundle();
bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index f9ec3f92..37dd939 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -23,14 +23,17 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
@@ -274,4 +277,40 @@
assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
}
+
+ @Test
+ public void testUpdateAppOps_foregroundNoti() {
+ com.android.systemui.util.Assert.isNotMainThread();
+
+ when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+ .thenReturn("something");
+ mEntry.row = mRow;
+ mEntryManager.getNotificationData().add(mEntry);
+
+
+ mHandler.post(() -> {
+ mEntryManager.updateNotificationsForAppOps(
+ AppOpsManager.OP_CAMERA, mEntry.notification.getUid(),
+ mEntry.notification.getPackageName(), true);
+ });
+ waitForIdleSync(mHandler);
+
+ verify(mPresenter, times(1)).updateNotificationViews();
+ assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains(
+ AppOpsManager.OP_CAMERA));
+ }
+
+ @Test
+ public void testUpdateAppOps_otherNoti() {
+ com.android.systemui.util.Assert.isNotMainThread();
+
+ when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+ .thenReturn(null);
+ mHandler.post(() -> {
+ mEntryManager.updateNotificationsForAppOps(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+ });
+ waitForIdleSync(mHandler);
+
+ verify(mPresenter, never()).updateNotificationViews();
+ }
}
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 f3c1171..2764254 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -48,6 +48,8 @@
private ExpandableNotificationRow mRow;
private InflationException mException;
private HeadsUpManager mHeadsUpManager;
+ protected static final String PKG = "com.android.systemui";
+ protected static final int UID = 1000;
public NotificationTestHelper(Context context) {
mContext = context;
@@ -55,7 +57,7 @@
mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null);
}
- public ExpandableNotificationRow createRow() throws Exception {
+ public ExpandableNotificationRow createRow(String pkg, int uid) throws Exception {
Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
R.drawable.ic_person)
.setCustomContentView(new RemoteViews(mContext.getPackageName(),
@@ -67,10 +69,19 @@
.setContentText("Text")
.setPublicVersion(publicVersion)
.build();
- return createRow(notification);
+ return createRow(notification, pkg, uid);
+ }
+
+ public ExpandableNotificationRow createRow() throws Exception {
+ return createRow(PKG, UID);
}
public ExpandableNotificationRow createRow(Notification notification) throws Exception {
+ return createRow(notification, PKG, UID);
+ }
+
+ public ExpandableNotificationRow createRow(Notification notification, String pkg, int uid)
+ throws Exception {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
mContext.LAYOUT_INFLATER_SERVICE);
mInstrumentation.runOnMainSync(() -> {
@@ -83,8 +94,7 @@
row.setHeadsUpManager(mHeadsUpManager);
row.setAboveShelfChangedListener(aboveShelf -> {});
UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
- StatusBarNotification sbn = new StatusBarNotification("com.android.systemui",
- "com.android.systemui", mId++, null, 1000,
+ StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, mId++, null, uid,
2000, notification, mUser, null, System.currentTimeMillis());
NotificationData.Entry entry = new NotificationData.Entry(sbn);
entry.row = row;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index fbe730a..76ed452 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -19,6 +19,9 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -170,6 +173,19 @@
assertEquals(View.VISIBLE, entry1.row.getVisibility());
}
+ @Test
+ public void testUpdateNotificationViews_appOps() throws Exception {
+ NotificationData.Entry entry0 = createEntry();
+ entry0.row = spy(entry0.row);
+ when(mNotificationData.getActiveNotifications()).thenReturn(
+ Lists.newArrayList(entry0));
+ mListContainer.addContainerView(entry0.row);
+
+ mViewHierarchyManager.updateNotificationViews();
+
+ verify(entry0.row, times(1)).showAppOpsIcons(any());
+ }
+
private class FakeListContainer implements NotificationListContainer {
final LinearLayout mLayout = new LinearLayout(mContext);
final List<View> mRows = Lists.newArrayList();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 2d2db1b..a80b045 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -18,28 +18,21 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.app.AlarmManager.AlarmClockInfo;
-import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import com.android.internal.app.ColorDisplayController;
import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.Mockito;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -47,19 +40,16 @@
public class AutoTileManagerTest extends SysuiTestCase {
@Mock private QSTileHost mQsTileHost;
- @Mock private AutoAddTracker mAutoAddTracker;
- @Captor private ArgumentCaptor<NextAlarmChangeCallback> mAlarmCallback;
private AutoTileManager mAutoTileManager;
@Before
public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mDependency.injectMockDependency(NextAlarmController.class);
- mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker,
- mQsTileHost, new Handler(TestableLooper.get(this).getLooper()));
- verify(Dependency.get(NextAlarmController.class))
- .addCallback(mAlarmCallback.capture());
+ mDependency.injectTestDependency(Dependency.BG_LOOPER,
+ TestableLooper.get(this).getLooper());
+ Prefs.putBoolean(mContext, Prefs.Key.QS_NIGHTDISPLAY_ADDED, false);
+ mQsTileHost = Mockito.mock(QSTileHost.class);
+ mAutoTileManager = new AutoTileManager(mContext, mQsTileHost);
}
@Test
@@ -109,30 +99,4 @@
ColorDisplayController.AUTO_MODE_DISABLED);
verify(mQsTileHost, never()).addTile("night");
}
-
- @Test
- public void alarmTileAdded_whenAlarmSet() {
- mAlarmCallback.getValue().onNextAlarmChanged(new AlarmClockInfo(0, null));
-
- verify(mQsTileHost).addTile("alarm");
- verify(mAutoAddTracker).setTileAdded("alarm");
- }
-
- @Test
- public void alarmTileNotAdded_whenAlarmNotSet() {
- mAlarmCallback.getValue().onNextAlarmChanged(null);
-
- verify(mQsTileHost, never()).addTile("alarm");
- verify(mAutoAddTracker, never()).setTileAdded("alarm");
- }
-
- @Test
- public void alarmTileNotAdded_whenAlreadyAdded() {
- when(mAutoAddTracker.isAdded("alarm")).thenReturn(true);
-
- mAlarmCallback.getValue().onNextAlarmChanged(new AlarmClockInfo(0, null));
-
- verify(mQsTileHost, never()).addTile("alarm");
- verify(mAutoAddTracker, never()).setTileAdded("alarm");
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 8347fb0..168d8d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -356,6 +356,52 @@
Assert.assertTrue(mScrimController.wasAnimationJustCancelled());
}
+ /**
+ * Number of visible notifications affects scrim opacity.
+ */
+ @Test
+ public void testNotificationDensity() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.finishAnimationsImmediately();
+
+ mScrimController.setNotificationCount(0);
+ mScrimController.finishAnimationsImmediately();
+ Assert.assertEquals("lower density when no notifications",
+ ScrimController.GRADIENT_SCRIM_ALPHA, mScrimBehind.getViewAlpha(), 0.01f);
+
+ mScrimController.setNotificationCount(3);
+ mScrimController.finishAnimationsImmediately();
+ Assert.assertEquals("stronger density when notifications are visible",
+ ScrimController.GRADIENT_SCRIM_ALPHA_BUSY, mScrimBehind.getViewAlpha(), 0.01f);
+ }
+
+ /**
+ * Moving from/to states conserves old notification density.
+ */
+ @Test
+ public void testConservesNotificationDensity() {
+ testConservesNotificationDensity(0 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA);
+ testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY);
+ }
+
+ /**
+ * Conserves old notification density after leaving state and coming back.
+ *
+ * @param count How many notification.
+ * @param expectedAlpha Expected alpha.
+ */
+ private void testConservesNotificationDensity(int count, float expectedAlpha) {
+ mScrimController.setNotificationCount(count);
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.finishAnimationsImmediately();
+
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.finishAnimationsImmediately();
+
+ Assert.assertEquals("Doesn't respect notification busyness after transition",
+ expectedAlpha, mScrimBehind.getViewAlpha(), 0.01f);
+ }
+
private void assertScrimTint(ScrimView scrimView, boolean tinted) {
final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT;
final String name = scrimView == mScrimInFront ? "front" : "back";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 31442af..ff545f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -69,6 +69,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.AppOpsListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
@@ -145,6 +146,7 @@
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
+ mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
new file mode 100644
index 0000000..d54c295
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 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.statusbar.policy;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.os.PowerManager;
+import android.os.PowerSaveState;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class BatteryControllerTest extends SysuiTestCase {
+
+ @Mock
+ private PowerManager mPowerManager;
+ private BatteryControllerImpl mBatteryController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mBatteryController = new BatteryControllerImpl(getContext(), mPowerManager);
+ }
+
+ @Test
+ public void testIndependentAODBatterySaver_true() {
+ PowerSaveState state = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(true)
+ .build();
+ Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ when(mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD)).thenReturn(state);
+ when(mPowerManager.isPowerSaveMode()).thenReturn(true);
+
+ mBatteryController.onReceive(getContext(), intent);
+
+ Assert.assertTrue(mBatteryController.isPowerSave());
+ Assert.assertTrue(mBatteryController.isAodPowerSave());
+ }
+
+ @Test
+ public void testIndependentAODBatterySaver_false() {
+ PowerSaveState state = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(false)
+ .build();
+ Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ when(mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD)).thenReturn(state);
+ when(mPowerManager.isPowerSaveMode()).thenReturn(true);
+
+ mBatteryController.onReceive(getContext(), intent);
+
+ Assert.assertTrue(mBatteryController.isPowerSave());
+ Assert.assertFalse(mBatteryController.isAodPowerSave());
+ }
+
+}
diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk
index 4c80a26..8507646 100644
--- a/packages/VpnDialogs/Android.mk
+++ b/packages/VpnDialogs/Android.mk
@@ -27,5 +27,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := VpnDialogs
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml
index 3b4eedd..93f56ba 100644
--- a/packages/VpnDialogs/res/values-or/strings.xml
+++ b/packages/VpnDialogs/res/values-or/strings.xml
@@ -16,10 +16,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for prompt (3183836924226407828) -->
- <skip />
- <!-- no translation found for warning (809658604548412033) -->
- <skip />
+ <string name="prompt" msgid="3183836924226407828">"ସଂଯୋଗ ଅନୁରୋଧ"</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ଏକ VPN ସଂଯୋଗ ସେଟ୍ ଅପ୍ କରିବାକୁ ଚାହେଁ, ଯାହା ଏହି ନେଟ୍ୱର୍କର ଟ୍ରାଫିକକୁ ମନିଟର୍ କରିବାକୁ ଅନୁମତି ଦିଏ। ଆପଣ ସୋର୍ସ ଉପରେ ବିଶ୍ୱାସ କରିବା ବଦଳରେ କେବଳ ସ୍ୱୀକାର କରନ୍ତୁ। <br /> <br /> <img src=vpn_icon /> VPN ସକ୍ରିୟ ଥିବାବେଳେ ଏହା ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ର ଉପରେ ଦେଖାଯାଏ।"</string>
<string name="legacy_title" msgid="192936250066580964">"VPN ସଂଯୋଗ ହେଲା"</string>
<string name="session" msgid="6470628549473641030">"ସେସନ୍:"</string>
<string name="duration" msgid="3584782459928719435">"ଅବଧି:"</string>
diff --git a/packages/WAPPushManager/Android.mk b/packages/WAPPushManager/Android.mk
index 60f093f..91526dd 100644
--- a/packages/WAPPushManager/Android.mk
+++ b/packages/WAPPushManager/Android.mk
@@ -9,6 +9,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := WAPPushManager
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += telephony-common
LOCAL_STATIC_JAVA_LIBRARIES += android-common
diff --git a/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk
index bfc85ab..c4c2240f 100644
--- a/packages/WAPPushManager/tests/Android.mk
+++ b/packages/WAPPushManager/tests/Android.mk
@@ -32,6 +32,7 @@
# automatically get all of its classes loaded into our environment.
LOCAL_PACKAGE_NAME := WAPPushManagerTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_INSTRUMENTATION_FOR := WAPPushManager
diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk
index cf04249..a6426a6 100644
--- a/packages/WallpaperBackup/Android.mk
+++ b/packages/WallpaperBackup/Android.mk
@@ -24,6 +24,7 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PACKAGE_NAME := WallpaperBackup
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := false
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 7efe8ab..848f2bd 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := WallpaperCropper
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
index 4f3a8b1..f5afad2 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
@@ -9,5 +9,6 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationNarrowOverlay
+LOCAL_SDK_VERSION := current
include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
index a584a7f..c22b2e7 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
@@ -46,7 +46,8 @@
<bool name="config_fillMainBuiltInDisplayCutout">true</bool>
<!-- Height of the status bar -->
- <dimen name="status_bar_height">48dp</dimen>
+ <dimen name="status_bar_height_portrait">48dp</dimen>
+ <dimen name="status_bar_height_landscape">28dp</dimen>
<!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
<dimen name="quick_qs_offset_height">48dp</dimen>
<!-- Total height of QQS (quick_qs_offset_height + 128) -->
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
index dac3878..f1f8c27 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
@@ -9,5 +9,6 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationTallOverlay
+LOCAL_SDK_VERSION := current
include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
index 915e164..401e092 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
@@ -46,7 +46,8 @@
<bool name="config_fillMainBuiltInDisplayCutout">true</bool>
<!-- Height of the status bar -->
- <dimen name="status_bar_height">48dp</dimen>
+ <dimen name="status_bar_height_portrait">48dp</dimen>
+ <dimen name="status_bar_height_landscape">28dp</dimen>
<!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
<dimen name="quick_qs_offset_height">48dp</dimen>
<!-- Total height of QQS (quick_qs_offset_height + 128) -->
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
index f4f250c..d149d8e 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
@@ -9,5 +9,6 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationWideOverlay
+LOCAL_SDK_VERSION := current
include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
index b8e29da..f328b83 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
@@ -46,7 +46,8 @@
<bool name="config_fillMainBuiltInDisplayCutout">true</bool>
<!-- Height of the status bar -->
- <dimen name="status_bar_height">48dp</dimen>
+ <dimen name="status_bar_height_portrait">48dp</dimen>
+ <dimen name="status_bar_height_landscape">28dp</dimen>
<!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
<dimen name="quick_qs_offset_height">48dp</dimen>
<!-- Total height of QQS (quick_qs_offset_height + 128) -->
diff --git a/packages/overlays/SysuiDarkThemeOverlay/Android.mk b/packages/overlays/SysuiDarkThemeOverlay/Android.mk
index 4b83058..7b277bc 100644
--- a/packages/overlays/SysuiDarkThemeOverlay/Android.mk
+++ b/packages/overlays/SysuiDarkThemeOverlay/Android.mk
@@ -9,5 +9,6 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := SysuiDarkThemeOverlay
+LOCAL_SDK_VERSION := current
include $(BUILD_RRO_PACKAGE)
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index 3c4e951..5be90c0 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := PacProcessor
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
diff --git a/packages/services/Proxy/Android.mk b/packages/services/Proxy/Android.mk
index d5546b2..ce1715f 100644
--- a/packages/services/Proxy/Android.mk
+++ b/packages/services/Proxy/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ProxyHandler
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c56002e..6f31b0a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5328,6 +5328,26 @@
// OS: P
PACKAGE_OPTIMIZATION_COMPILATION_REASON = 1321;
+ // FIELD: The camera API level used.
+ // CATEGORY: CAMERA
+ // OS: P
+ FIELD_CAMERA_API_LEVEL = 1322;
+
+ // OPEN: Settings > Battery > Battery tip > Battery tip Dialog
+ // CATEGORY: SETTINGS
+ // OS: P
+ FUELGAUGE_BATTERY_TIP_DIALOG = 1323;
+
+ // OPEN: Settings > Battery > Battery tip
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_BATTERY_TIP_SHOWN = 1324;
+
+ // OPEN: Settings > Security & Location > Location > See all
+ // CATEGORY: SETTINGS
+ // OS: P
+ RECENT_LOCATION_REQUESTS_ALL = 1325;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index c77dcc0..74efec9 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -379,6 +379,9 @@
// Number of connectivity single scan requests.
optional int32 num_connectivity_oneshot_scans = 93;
+
+ // WifiWake statistics
+ optional WifiWakeStats wifi_wake_stats = 94;
}
// Information that gets logged for every WiFi connection.
@@ -1159,3 +1162,39 @@
// Amount of time wifi is in tx (ms)
optional int64 tx_time_ms = 5;
}
+
+// Metrics for Wifi Wake
+message WifiWakeStats {
+ // An individual session for Wifi Wake
+ message Session {
+ // A Wifi Wake lifecycle event
+ message Event {
+ // Elapsed time in milliseconds since start of session.
+ optional int64 elapsed_time_millis = 1;
+
+ // Number of scans that have occurred since start of session.
+ optional int32 elapsed_scans = 2;
+ }
+
+ // Start time of session in milliseconds.
+ optional int64 start_time_millis = 1;
+
+ // The number of networks the lock was initialized with at start.
+ optional int32 locked_networks_at_start = 2;
+
+ // Event for unlocking the WakeupLock. Does not occur if lock was initialized with 0 networks.
+ optional Event unlock_event = 3;
+
+ // Event for triggering wakeup.
+ optional Event wakeup_event = 4;
+
+ // Event for WifiWake reset event. This event marks the end of a session.
+ optional Event reset_event = 5;
+ }
+
+ // Total number of sessions for Wifi Wake.
+ optional int32 num_sessions = 1;
+
+ // Session information for every Wifi Wake session (up to a maximum of 10).
+ repeated Session sessions = 2;
+}
diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk
index e0e490c..c4517a9 100644
--- a/sax/tests/saxtests/Android.mk
+++ b/sax/tests/saxtests/Android.mk
@@ -10,6 +10,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := FrameworksSaxTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 50968a0..b0b9586 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -128,6 +128,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.IntSupplier;
@@ -2055,7 +2056,7 @@
}
ComponentName componentName = ComponentName.unflattenFromString(componentId);
- if (componentName.equals(userState.mServiceAssignedToAccessibilityButton)) {
+ if (Objects.equals(componentName, userState.mServiceAssignedToAccessibilityButton)) {
return false;
}
userState.mServiceAssignedToAccessibilityButton = componentName;
@@ -3300,7 +3301,8 @@
if (mAccessibilityFocusedWindowId != windowId) {
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::clearAccessibilityFocus,
- AccessibilityManagerService.this, 0));
+ AccessibilityManagerService.this,
+ box(mAccessibilityFocusedWindowId)));
mSecurityPolicy.setAccessibilityFocusedWindowLocked(windowId);
mAccessibilityFocusNodeId = nodeId;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index d4ecc28..f7a4b73 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -356,7 +356,8 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (mDestroyed || !mBinding) {
- mContext.unbindService(mServiceConnection);
+ // This is abnormal. Unbinding the connection has been requested already.
+ Slog.wtf(LOG_TAG, "onServiceConnected was dispatched after unbindService.");
return;
}
mBinding = false;
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 7278e83..dbed242 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -590,7 +590,7 @@
}
}
- final class AnchoredWindow implements View.OnTouchListener {
+ final class AnchoredWindow {
private final @NonNull OverlayControl mOverlayControl;
private final WindowManager mWm;
private final View mContentView;
@@ -623,7 +623,6 @@
params.accessibilityTitle = mContentView.getContext()
.getString(R.string.autofill_picker_accessibility_title);
mWm.addView(mContentView, params);
- mContentView.setOnTouchListener(this);
mOverlayControl.hideOverlays();
mShowing = true;
} else {
@@ -647,7 +646,6 @@
void hide() {
try {
if (mShowing) {
- mContentView.setOnTouchListener(null);
mWm.removeView(mContentView);
mShowing = false;
}
@@ -661,16 +659,6 @@
mOverlayControl.showOverlays();
}
}
-
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- // When the window is touched outside, hide the window.
- if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- mCallback.onCanceled();
- return true;
- }
- return false;
- }
}
public void dump(PrintWriter pw, String prefix) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 782bf71..369df54 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3555,6 +3555,7 @@
+ (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
if (mBackupRunning) pw.println("Backup currently running");
+ pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running");
pw.println("Last backup pass started: " + mLastBackupPass
+ " (now = " + System.currentTimeMillis() + ')');
pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled());
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 3cf374f..4443130 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -23,6 +23,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
@@ -30,6 +31,7 @@
import android.os.ParcelFileDescriptor;
import android.util.Slog;
+import com.android.server.LocalServices;
import com.android.server.backup.utils.AppBackupUtils;
import java.io.BufferedInputStream;
@@ -235,7 +237,7 @@
if (home != null) {
try {
homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
- PackageManager.GET_SIGNATURES);
+ PackageManager.GET_SIGNING_CERTIFICATES);
homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
homeVersion = homeInfo.getLongVersionCode();
homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
@@ -252,10 +254,11 @@
// 2. the home app [or absence] we now use differs from the prior state,
// OR 3. it looks like we use the same home app + version as before, but
// the signatures don't match so we treat them as different apps.
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
final boolean needHomeBackup = (homeVersion != mStoredHomeVersion)
|| !Objects.equals(home, mStoredHomeComponent)
|| (home != null
- && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo));
+ && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo, pmi));
if (needHomeBackup) {
if (DEBUG) {
Slog.i(TAG, "Home preference changed; backing up new state " + home);
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 501ff29..c87d298 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.app.backup.BackupManager;
+import android.app.backup.BackupTransport;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -58,8 +59,6 @@
@VisibleForTesting
public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
- private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";
-
private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
private final Context mContext;
private final PackageManager mPackageManager;
@@ -587,7 +586,7 @@
String callerLogString = "TransportManager.registerTransport()";
Bundle extras = new Bundle();
- extras.putBoolean(EXTRA_TRANSPORT_REGISTRATION, true);
+ extras.putBoolean(BackupTransport.EXTRA_TRANSPORT_REGISTRATION, true);
TransportClient transportClient = mTransportClientManager.getTransportClient(
transportComponent, extras, callerLogString);
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 3df6e47..136fada 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -302,7 +302,7 @@
sets = transport.getAvailableRestoreSets();
// cache the result in the active session
synchronized (params.session) {
- params.session.mRestoreSets = sets;
+ params.session.setRestoreSets(sets);
}
if (sets == null) {
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index e500d6e..5125b0d 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -16,6 +16,7 @@
package com.android.server.backup.params;
+import android.annotation.Nullable;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IRestoreObserver;
import android.content.pm.PackageInfo;
@@ -28,10 +29,10 @@
public final IRestoreObserver observer;
public final IBackupManagerMonitor monitor;
public final long token;
- public final PackageInfo packageInfo;
+ @Nullable public final PackageInfo packageInfo;
public final int pmToken; // in post-install restore, the PM's token for this transaction
public final boolean isSystemRestore;
- public final String[] filterSet;
+ @Nullable public final String[] filterSet;
public final OnTaskFinishedListener listener;
/**
@@ -129,10 +130,10 @@
IRestoreObserver observer,
IBackupManagerMonitor monitor,
long token,
- PackageInfo packageInfo,
+ @Nullable PackageInfo packageInfo,
int pmToken,
boolean isSystemRestore,
- String[] filterSet,
+ @Nullable String[] filterSet,
OnTaskFinishedListener listener) {
this.transportClient = transportClient;
this.observer = observer;
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 238f7a0..140dded 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -22,6 +22,7 @@
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_GET_RESTORE_SETS;
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE;
+import android.annotation.Nullable;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
@@ -53,13 +54,15 @@
private final TransportManager mTransportManager;
private final String mTransportName;
private final BackupManagerService mBackupManagerService;
- private final String mPackageName;
+ @Nullable private final String mPackageName;
public RestoreSet[] mRestoreSets = null;
boolean mEnded = false;
boolean mTimedOut = false;
- public ActiveRestoreSession(BackupManagerService backupManagerService,
- String packageName, String transportName) {
+ public ActiveRestoreSession(
+ BackupManagerService backupManagerService,
+ @Nullable String packageName,
+ String transportName) {
mBackupManagerService = backupManagerService;
mPackageName = packageName;
mTransportManager = backupManagerService.getTransportManager();
@@ -360,6 +363,10 @@
}
}
+ public void setRestoreSets(RestoreSet[] restoreSets) {
+ mRestoreSets = restoreSets;
+ }
+
/**
* Returns 0 if operation sent or -1 otherwise.
*/
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 0ca4f25..c1a1c1d 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -36,11 +36,13 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -207,8 +209,11 @@
if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
info);
+ PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
- mBackupManagerService.getPackageManager(), allowApks, info, signatures);
+ mBackupManagerService.getPackageManager(), allowApks, info, signatures,
+ pmi);
mManifestSignatures.put(info.packageName, signatures);
mPackagePolicies.put(pkg, restorePolicy);
mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index e576b3c..dacde0b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -40,6 +40,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
@@ -47,6 +48,7 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupManagerService;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -470,9 +472,11 @@
if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
info);
+ PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
mBackupManagerService.getPackageManager(), allowApks,
- info, signatures);
+ info, signatures, pmi);
mManifestSignatures.put(info.packageName, signatures);
mPackagePolicies.put(pkg, restorePolicy);
mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 6eb9619..4b467e5 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -30,6 +30,7 @@
import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
+import android.annotation.Nullable;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupDataInput;
@@ -42,6 +43,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Message;
@@ -56,6 +58,7 @@
import com.android.internal.backup.IBackupTransport;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.BackupUtils;
import com.android.server.backup.PackageManagerBackupAgent;
@@ -158,12 +161,18 @@
private final int mEphemeralOpToken;
- // Invariant: mWakelock is already held, and this task is responsible for
- // releasing it at the end of the restore operation.
- public PerformUnifiedRestoreTask(BackupManagerService backupManagerService,
- TransportClient transportClient, IRestoreObserver observer,
- IBackupManagerMonitor monitor, long restoreSetToken, PackageInfo targetPackage,
- int pmToken, boolean isFullSystemRestore, String[] filterSet,
+ // This task can assume that the wakelock is properly held for it and doesn't have to worry
+ // about releasing it.
+ public PerformUnifiedRestoreTask(
+ BackupManagerService backupManagerService,
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long restoreSetToken,
+ @Nullable PackageInfo targetPackage,
+ int pmToken,
+ boolean isFullSystemRestore,
+ @Nullable String[] filterSet,
OnTaskFinishedListener listener) {
this.backupManagerService = backupManagerService;
mTransportManager = backupManagerService.getTransportManager();
@@ -336,7 +345,7 @@
*
* [ state change => FINAL ]
*
- * 7. t.finishRestore(), release wakelock, etc.
+ * 7. t.finishRestore(), call listeners, etc.
*
*
*/
@@ -497,7 +506,7 @@
try {
mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo(
- pkgName, PackageManager.GET_SIGNATURES);
+ pkgName, PackageManager.GET_SIGNING_CERTIFICATES);
} catch (NameNotFoundException e) {
// Whoops, we thought we could restore this package but it
// turns out not to be present. Skip it.
@@ -612,7 +621,8 @@
}
Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
- if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage, pmi)) {
Slog.w(TAG, "Signature mismatch restoring " + packageName);
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage,
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 6780563..90c1387 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -25,6 +25,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Process;
import android.util.Slog;
@@ -37,6 +38,9 @@
* Utility methods wrapping operations on ApplicationInfo and PackageInfo.
*/
public class AppBackupUtils {
+
+ private static final boolean DEBUG = false;
+
/**
* Returns whether app is eligible for backup.
*
@@ -88,7 +92,8 @@
public static boolean appIsRunningAndEligibleForBackupWithTransport(
@Nullable TransportClient transportClient, String packageName, PackageManager pm) {
try {
- PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ PackageInfo packageInfo = pm.getPackageInfo(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES);
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if (!appIsEligibleForBackup(applicationInfo, pm)
|| appIsStopped(applicationInfo)
@@ -165,12 +170,18 @@
*
* <ul>
* <li>Source and target have at least one signature each
- * <li>Target contains all signatures in source
+ * <li>Target contains all signatures in source, and nothing more
* </ul>
*
+ * or if both source and target have exactly one signature, and they don't match, we check
+ * if the app was ever signed with source signature (i.e. app has rotated key)
+ * Note: key rotation is only supported for apps ever signed with one key, and those apps will
+ * not be allowed to be signed by more certificates in the future
+ *
* Note that if {@param target} is null we return false.
*/
- public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
+ public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target,
+ PackageManagerInternal pmi) {
if (target == null) {
return false;
}
@@ -187,33 +198,52 @@
return true;
}
- Signature[] deviceSigs = target.signatures;
- if (MORE_DEBUG) {
- Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs);
- }
-
// Don't allow unsigned apps on either end
- if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) {
+ if (ArrayUtils.isEmpty(storedSigs)) {
return false;
}
- // Signatures can be added over time, so the target-device apk needs to contain all the
- // source-device apk signatures, but not necessarily the other way around.
- int nStored = storedSigs.length;
- int nDevice = deviceSigs.length;
+ Signature[][] deviceHistorySigs = target.signingCertificateHistory;
+ if (ArrayUtils.isEmpty(deviceHistorySigs)) {
+ Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" +
+ " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
+ return false;
+ }
- for (int i = 0; i < nStored; i++) {
- boolean match = false;
- for (int j = 0; j < nDevice; j++) {
- if (storedSigs[i].equals(deviceSigs[j])) {
- match = true;
- break;
+ if (DEBUG) {
+ Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceHistorySigs);
+ }
+
+ final int nStored = storedSigs.length;
+ if (nStored == 1) {
+ // if the app is only signed with one sig, it's possible it has rotated its key
+ // (the checks with signing history are delegated to PackageManager)
+ // TODO: address the case that app has declared restoreAnyVersion and is restoring
+ // from higher version to lower after having rotated the key (i.e. higher version has
+ // different sig than lower version that we want to restore to)
+ return pmi.isDataRestoreSafe(storedSigs[0], target.packageName);
+ } else {
+ // the app couldn't have rotated keys, since it was signed with multiple sigs - do
+ // a comprehensive 1-to-1 signatures check
+ // since app hasn't rotated key, we only need to check with deviceHistorySigs[0]
+ Signature[] deviceSigs = deviceHistorySigs[0];
+ int nDevice = deviceSigs.length;
+
+ // ensure that each stored sig matches an on-device sig
+ for (int i = 0; i < nStored; i++) {
+ boolean match = false;
+ for (int j = 0; j < nDevice; j++) {
+ if (storedSigs[i].equals(deviceSigs[j])) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
}
}
- if (!match) {
- return false;
- }
+ // we have found a match for all stored sigs
+ return true;
}
- return true;
}
}
diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
index 10f0695..df7e6d4 100644
--- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageInstaller.Session;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.IBinder;
@@ -37,6 +38,7 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.restore.RestoreDeleteObserver;
import com.android.server.backup.restore.RestorePolicy;
@@ -142,9 +144,8 @@
uninstall = true;
} else {
try {
- PackageInfo pkg = packageManager.getPackageInfo(
- info.packageName,
- PackageManager.GET_SIGNATURES);
+ PackageInfo pkg = packageManager.getPackageInfo(info.packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES);
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP)
== 0) {
Slog.w(TAG, "Restore stream contains apk of package "
@@ -154,7 +155,9 @@
} else {
// So far so good -- do the signatures match the manifest?
Signature[] sigs = manifestSignatures.get(info.packageName);
- if (AppBackupUtils.signaturesMatch(sigs, pkg)) {
+ PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ if (AppBackupUtils.signaturesMatch(sigs, pkg, pmi)) {
// If this is a system-uid app without a declared backup agent,
// don't restore any of the file data.
if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index cc26ff8..6dd5284 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -50,6 +50,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.Process;
@@ -385,7 +386,8 @@
* @return a restore policy constant.
*/
public RestorePolicy chooseRestorePolicy(PackageManager packageManager,
- boolean allowApks, FileMetadata info, Signature[] signatures) {
+ boolean allowApks, FileMetadata info, Signature[] signatures,
+ PackageManagerInternal pmi) {
if (signatures == null) {
return RestorePolicy.IGNORE;
}
@@ -395,7 +397,7 @@
// Okay, got the manifest info we need...
try {
PackageInfo pkgInfo = packageManager.getPackageInfo(
- info.packageName, PackageManager.GET_SIGNATURES);
+ info.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
// Fall through to IGNORE if the app explicitly disallows backup
final int flags = pkgInfo.applicationInfo.flags;
if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
@@ -411,7 +413,7 @@
// such packages are signed with the platform cert instead of
// the app developer's cert, so they're different on every
// device.
- if (AppBackupUtils.signaturesMatch(signatures, pkgInfo)) {
+ if (AppBackupUtils.signaturesMatch(signatures, pkgInfo, pmi)) {
if ((pkgInfo.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
Slog.i(TAG, "Package has restoreAnyVersion; taking data");
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index c93f405..d17ca7f 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -66,6 +66,7 @@
import android.system.Os;
import android.text.TextUtils;
import android.text.format.DateFormat;
+import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.KeyValueListParser;
@@ -268,6 +269,7 @@
// Key names stored in the settings value.
private static final String KEY_MIN_FUTURITY = "min_futurity";
private static final String KEY_MIN_INTERVAL = "min_interval";
+ private static final String KEY_MAX_INTERVAL = "max_interval";
private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";
private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
@@ -285,6 +287,7 @@
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
+ private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
@@ -303,6 +306,9 @@
// Minimum alarm recurrence interval
public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL;
+ // Maximum alarm recurrence interval
+ public long MAX_INTERVAL = DEFAULT_MAX_INTERVAL;
+
// Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle.
public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME;
@@ -361,6 +367,7 @@
MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY);
MIN_INTERVAL = mParser.getLong(KEY_MIN_INTERVAL, DEFAULT_MIN_INTERVAL);
+ MAX_INTERVAL = mParser.getLong(KEY_MAX_INTERVAL, DEFAULT_MAX_INTERVAL);
ALLOW_WHILE_IDLE_SHORT_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME,
DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME);
ALLOW_WHILE_IDLE_LONG_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME,
@@ -391,6 +398,10 @@
TimeUtils.formatDuration(MIN_INTERVAL, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_MAX_INTERVAL); pw.print("=");
+ TimeUtils.formatDuration(MAX_INTERVAL, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_LISTENER_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(LISTENER_TIMEOUT, pw);
pw.println();
@@ -419,6 +430,7 @@
proto.write(ConstantsProto.MIN_FUTURITY_DURATION_MS, MIN_FUTURITY);
proto.write(ConstantsProto.MIN_INTERVAL_DURATION_MS, MIN_INTERVAL);
+ proto.write(ConstantsProto.MAX_INTERVAL_DURATION_MS, MAX_INTERVAL);
proto.write(ConstantsProto.LISTENER_TIMEOUT_DURATION_MS, LISTENER_TIMEOUT);
proto.write(ConstantsProto.ALLOW_WHILE_IDLE_SHORT_DURATION_MS,
ALLOW_WHILE_IDLE_SHORT_TIME);
@@ -481,7 +493,7 @@
Batch(Alarm seed) {
start = seed.whenElapsed;
- end = seed.maxWhenElapsed;
+ end = clampPositive(seed.maxWhenElapsed);
flags = seed.flags;
alarms.add(seed);
if (seed.operation == mTimeTickSender) {
@@ -737,7 +749,7 @@
if (futurity < MIN_FUZZABLE_INTERVAL) {
futurity = 0;
}
- return triggerAtTime + (long)(.75 * futurity);
+ return clampPositive(triggerAtTime + (long)(.75 * futurity));
}
// returns true if the batch was added at the head
@@ -913,7 +925,7 @@
// the window based on the alarm's new futurity. Note that this
// reflects a policy of preferring timely to deferred delivery.
maxElapsed = (a.windowLength > 0)
- ? (whenElapsed + a.windowLength)
+ ? clampPositive(whenElapsed + a.windowLength)
: maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
}
a.whenElapsed = whenElapsed;
@@ -921,6 +933,10 @@
setImplLocked(a, true, doValidate);
}
+ static long clampPositive(long val) {
+ return (val >= 0) ? val : Long.MAX_VALUE;
+ }
+
/**
* Sends alarms that were blocked due to user applied background restrictions - either because
* the user lifted those or the uid came to foreground.
@@ -1421,13 +1437,18 @@
}
// Sanity check the recurrence interval. This will catch people who supply
- // seconds when the API expects milliseconds.
+ // seconds when the API expects milliseconds, or apps trying shenanigans
+ // around intentional period overflow, etc.
final long minInterval = mConstants.MIN_INTERVAL;
if (interval > 0 && interval < minInterval) {
Slog.w(TAG, "Suspiciously short interval " + interval
+ " millis; expanding to " + (minInterval/1000)
+ " seconds");
interval = minInterval;
+ } else if (interval > mConstants.MAX_INTERVAL) {
+ Slog.w(TAG, "Suspiciously long interval " + interval
+ + " millis; clamping");
+ interval = mConstants.MAX_INTERVAL;
}
if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
@@ -2170,42 +2191,42 @@
synchronized (mLock) {
final long nowRTC = System.currentTimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
- proto.write(AlarmManagerServiceProto.CURRENT_TIME, nowRTC);
- proto.write(AlarmManagerServiceProto.ELAPSED_REALTIME, nowElapsed);
- proto.write(AlarmManagerServiceProto.LAST_TIME_CHANGE_CLOCK_TIME,
+ proto.write(AlarmManagerServiceDumpProto.CURRENT_TIME, nowRTC);
+ proto.write(AlarmManagerServiceDumpProto.ELAPSED_REALTIME, nowElapsed);
+ proto.write(AlarmManagerServiceDumpProto.LAST_TIME_CHANGE_CLOCK_TIME,
mLastTimeChangeClockTime);
- proto.write(AlarmManagerServiceProto.LAST_TIME_CHANGE_REALTIME,
+ proto.write(AlarmManagerServiceDumpProto.LAST_TIME_CHANGE_REALTIME,
mLastTimeChangeRealtime);
- mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
+ mConstants.dumpProto(proto, AlarmManagerServiceDumpProto.SETTINGS);
if (mAppStateTracker != null) {
mAppStateTracker.dumpProto(proto,
- AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+ AlarmManagerServiceDumpProto.FORCE_APP_STANDBY_TRACKER);
}
- proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
+ proto.write(AlarmManagerServiceDumpProto.IS_INTERACTIVE, mInteractive);
if (!mInteractive) {
// Durations
- proto.write(AlarmManagerServiceProto.TIME_SINCE_NON_INTERACTIVE_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_SINCE_NON_INTERACTIVE_MS,
nowElapsed - mNonInteractiveStartTime);
- proto.write(AlarmManagerServiceProto.MAX_WAKEUP_DELAY_MS,
+ proto.write(AlarmManagerServiceDumpProto.MAX_WAKEUP_DELAY_MS,
currentNonWakeupFuzzLocked(nowElapsed));
- proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_DISPATCH_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_SINCE_LAST_DISPATCH_MS,
nowElapsed - mLastAlarmDeliveryTime);
- proto.write(AlarmManagerServiceProto.TIME_UNTIL_NEXT_NON_WAKEUP_DELIVERY_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_UNTIL_NEXT_NON_WAKEUP_DELIVERY_MS,
nowElapsed - mNextNonWakeupDeliveryTime);
}
- proto.write(AlarmManagerServiceProto.TIME_UNTIL_NEXT_NON_WAKEUP_ALARM_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_UNTIL_NEXT_NON_WAKEUP_ALARM_MS,
mNextNonWakeup - nowElapsed);
- proto.write(AlarmManagerServiceProto.TIME_UNTIL_NEXT_WAKEUP_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_UNTIL_NEXT_WAKEUP_MS,
mNextWakeup - nowElapsed);
- proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_WAKEUP_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_SINCE_LAST_WAKEUP_MS,
nowElapsed - mLastWakeup);
- proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_WAKEUP_SET_MS,
+ proto.write(AlarmManagerServiceDumpProto.TIME_SINCE_LAST_WAKEUP_SET_MS,
nowElapsed - mLastWakeupSet);
- proto.write(AlarmManagerServiceProto.TIME_CHANGE_EVENT_COUNT, mNumTimeChanged);
+ proto.write(AlarmManagerServiceDumpProto.TIME_CHANGE_EVENT_COUNT, mNumTimeChanged);
final TreeSet<Integer> users = new TreeSet<>();
final int nextAlarmClockForUserSize = mNextAlarmClockForUser.size();
@@ -2221,14 +2242,14 @@
final AlarmManager.AlarmClockInfo next = mNextAlarmClockForUser.get(user);
final long time = next != null ? next.getTriggerTime() : 0;
final boolean pendingSend = mPendingSendNextAlarmClockChangedForUser.get(user);
- final long aToken = proto.start(AlarmManagerServiceProto.NEXT_ALARM_CLOCK_METADATA);
+ final long aToken = proto.start(AlarmManagerServiceDumpProto.NEXT_ALARM_CLOCK_METADATA);
proto.write(AlarmClockMetadataProto.USER, user);
proto.write(AlarmClockMetadataProto.IS_PENDING_SEND, pendingSend);
proto.write(AlarmClockMetadataProto.TRIGGER_TIME_MS, time);
proto.end(aToken);
}
for (Batch b : mAlarmBatches) {
- b.writeToProto(proto, AlarmManagerServiceProto.PENDING_ALARM_BATCHES,
+ b.writeToProto(proto, AlarmManagerServiceDumpProto.PENDING_ALARM_BATCHES,
nowElapsed, nowRTC);
}
for (int i = 0; i < mPendingBackgroundAlarms.size(); i++) {
@@ -2236,66 +2257,66 @@
if (blockedAlarms != null) {
for (Alarm a : blockedAlarms) {
a.writeToProto(proto,
- AlarmManagerServiceProto.PENDING_USER_BLOCKED_BACKGROUND_ALARMS,
+ AlarmManagerServiceDumpProto.PENDING_USER_BLOCKED_BACKGROUND_ALARMS,
nowElapsed, nowRTC);
}
}
}
if (mPendingIdleUntil != null) {
mPendingIdleUntil.writeToProto(
- proto, AlarmManagerServiceProto.PENDING_IDLE_UNTIL, nowElapsed, nowRTC);
+ proto, AlarmManagerServiceDumpProto.PENDING_IDLE_UNTIL, nowElapsed, nowRTC);
}
for (Alarm a : mPendingWhileIdleAlarms) {
- a.writeToProto(proto, AlarmManagerServiceProto.PENDING_WHILE_IDLE_ALARMS,
+ a.writeToProto(proto, AlarmManagerServiceDumpProto.PENDING_WHILE_IDLE_ALARMS,
nowElapsed, nowRTC);
}
if (mNextWakeFromIdle != null) {
- mNextWakeFromIdle.writeToProto(proto, AlarmManagerServiceProto.NEXT_WAKE_FROM_IDLE,
+ mNextWakeFromIdle.writeToProto(proto, AlarmManagerServiceDumpProto.NEXT_WAKE_FROM_IDLE,
nowElapsed, nowRTC);
}
for (Alarm a : mPendingNonWakeupAlarms) {
- a.writeToProto(proto, AlarmManagerServiceProto.PAST_DUE_NON_WAKEUP_ALARMS,
+ a.writeToProto(proto, AlarmManagerServiceDumpProto.PAST_DUE_NON_WAKEUP_ALARMS,
nowElapsed, nowRTC);
}
- proto.write(AlarmManagerServiceProto.DELAYED_ALARM_COUNT, mNumDelayedAlarms);
- proto.write(AlarmManagerServiceProto.TOTAL_DELAY_TIME_MS, mTotalDelayTime);
- proto.write(AlarmManagerServiceProto.MAX_DELAY_DURATION_MS, mMaxDelayTime);
- proto.write(AlarmManagerServiceProto.MAX_NON_INTERACTIVE_DURATION_MS,
+ proto.write(AlarmManagerServiceDumpProto.DELAYED_ALARM_COUNT, mNumDelayedAlarms);
+ proto.write(AlarmManagerServiceDumpProto.TOTAL_DELAY_TIME_MS, mTotalDelayTime);
+ proto.write(AlarmManagerServiceDumpProto.MAX_DELAY_DURATION_MS, mMaxDelayTime);
+ proto.write(AlarmManagerServiceDumpProto.MAX_NON_INTERACTIVE_DURATION_MS,
mNonInteractiveTime);
- proto.write(AlarmManagerServiceProto.BROADCAST_REF_COUNT, mBroadcastRefCount);
- proto.write(AlarmManagerServiceProto.PENDING_INTENT_SEND_COUNT, mSendCount);
- proto.write(AlarmManagerServiceProto.PENDING_INTENT_FINISH_COUNT, mSendFinishCount);
- proto.write(AlarmManagerServiceProto.LISTENER_SEND_COUNT, mListenerCount);
- proto.write(AlarmManagerServiceProto.LISTENER_FINISH_COUNT, mListenerFinishCount);
+ proto.write(AlarmManagerServiceDumpProto.BROADCAST_REF_COUNT, mBroadcastRefCount);
+ proto.write(AlarmManagerServiceDumpProto.PENDING_INTENT_SEND_COUNT, mSendCount);
+ proto.write(AlarmManagerServiceDumpProto.PENDING_INTENT_FINISH_COUNT, mSendFinishCount);
+ proto.write(AlarmManagerServiceDumpProto.LISTENER_SEND_COUNT, mListenerCount);
+ proto.write(AlarmManagerServiceDumpProto.LISTENER_FINISH_COUNT, mListenerFinishCount);
for (InFlight f : mInFlight) {
- f.writeToProto(proto, AlarmManagerServiceProto.OUTSTANDING_DELIVERIES);
+ f.writeToProto(proto, AlarmManagerServiceDumpProto.OUTSTANDING_DELIVERIES);
}
for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); ++i) {
final long token = proto.start(
- AlarmManagerServiceProto.LAST_ALLOW_WHILE_IDLE_DISPATCH_TIMES);
+ AlarmManagerServiceDumpProto.LAST_ALLOW_WHILE_IDLE_DISPATCH_TIMES);
final int uid = mLastAllowWhileIdleDispatch.keyAt(i);
final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i);
- proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID, uid);
- proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime);
- proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS,
+ proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.UID, uid);
+ proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime);
+ proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS,
lastTime + getWhileIdleMinIntervalLocked(uid));
proto.end(token);
}
for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
if (mUseAllowWhileIdleShortTime.valueAt(i)) {
- proto.write(AlarmManagerServiceProto.USE_ALLOW_WHILE_IDLE_SHORT_TIME,
+ proto.write(AlarmManagerServiceDumpProto.USE_ALLOW_WHILE_IDLE_SHORT_TIME,
mUseAllowWhileIdleShortTime.keyAt(i));
}
}
- mLog.writeToProto(proto, AlarmManagerServiceProto.RECENT_PROBLEMS);
+ mLog.writeToProto(proto, AlarmManagerServiceDumpProto.RECENT_PROBLEMS);
final FilterStats[] topFilters = new FilterStats[10];
final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
@@ -2336,13 +2357,13 @@
}
}
for (int i = 0; i < len; ++i) {
- final long token = proto.start(AlarmManagerServiceProto.TOP_ALARMS);
+ final long token = proto.start(AlarmManagerServiceDumpProto.TOP_ALARMS);
FilterStats fs = topFilters[i];
- proto.write(AlarmManagerServiceProto.TopAlarm.UID, fs.mBroadcastStats.mUid);
- proto.write(AlarmManagerServiceProto.TopAlarm.PACKAGE_NAME,
+ proto.write(AlarmManagerServiceDumpProto.TopAlarm.UID, fs.mBroadcastStats.mUid);
+ proto.write(AlarmManagerServiceDumpProto.TopAlarm.PACKAGE_NAME,
fs.mBroadcastStats.mPackageName);
- fs.writeToProto(proto, AlarmManagerServiceProto.TopAlarm.FILTER);
+ fs.writeToProto(proto, AlarmManagerServiceDumpProto.TopAlarm.FILTER);
proto.end(token);
}
@@ -2351,10 +2372,10 @@
for (int iu = 0; iu < mBroadcastStats.size(); ++iu) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
for (int ip = 0; ip < uidStats.size(); ++ip) {
- final long token = proto.start(AlarmManagerServiceProto.ALARM_STATS);
+ final long token = proto.start(AlarmManagerServiceDumpProto.ALARM_STATS);
BroadcastStats bs = uidStats.valueAt(ip);
- bs.writeToProto(proto, AlarmManagerServiceProto.AlarmStat.BROADCAST);
+ bs.writeToProto(proto, AlarmManagerServiceDumpProto.AlarmStat.BROADCAST);
// uidStats is an ArrayMap, which we can't sort.
tmpFilters.clear();
@@ -2363,7 +2384,7 @@
}
Collections.sort(tmpFilters, comparator);
for (FilterStats fs : tmpFilters) {
- fs.writeToProto(proto, AlarmManagerServiceProto.AlarmStat.FILTERS);
+ fs.writeToProto(proto, AlarmManagerServiceDumpProto.AlarmStat.FILTERS);
}
proto.end(token);
@@ -2374,7 +2395,7 @@
for (int i = 0; i < mAllowWhileIdleDispatches.size(); i++) {
IdleDispatchEntry ent = mAllowWhileIdleDispatches.get(i);
final long token = proto.start(
- AlarmManagerServiceProto.ALLOW_WHILE_IDLE_DISPATCHES);
+ AlarmManagerServiceDumpProto.ALLOW_WHILE_IDLE_DISPATCHES);
proto.write(IdleDispatchEntryProto.UID, ent.uid);
proto.write(IdleDispatchEntryProto.PKG, ent.pkg);
@@ -2390,7 +2411,7 @@
if (WAKEUP_STATS) {
for (WakeupEvent event : mRecentWakeups) {
- final long token = proto.start(AlarmManagerServiceProto.RECENT_WAKEUP_HISTORY);
+ final long token = proto.start(AlarmManagerServiceDumpProto.RECENT_WAKEUP_HISTORY);
proto.write(WakeupEventProto.UID, event.uid);
proto.write(WakeupEventProto.ACTION, event.action);
proto.write(WakeupEventProto.WHEN, event.when);
@@ -3175,8 +3196,7 @@
whenElapsed = _whenElapsed;
expectedWhenElapsed = _whenElapsed;
windowLength = _windowLength;
- maxWhenElapsed = _maxWhen;
- expectedMaxWhenElapsed = _maxWhen;
+ maxWhenElapsed = expectedMaxWhenElapsed = clampPositive(_maxWhen);
repeatInterval = _interval;
operation = _op;
listener = _rec;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ca67a34..53c9ecb 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -211,9 +211,11 @@
public final class ActiveCallback implements DeathRecipient {
final IAppOpsActiveCallback mCallback;
+ final int mUid;
- public ActiveCallback(IAppOpsActiveCallback callback) {
+ public ActiveCallback(IAppOpsActiveCallback callback, int uid) {
mCallback = callback;
+ mUid = uid;
try {
mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -230,24 +232,22 @@
}
}
- final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
+ final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
public final class ClientState extends Binder implements DeathRecipient {
+ final ArrayList<Op> mStartedOps = new ArrayList<>();
final IBinder mAppToken;
final int mPid;
- final ArrayList<Op> mStartedOps;
public ClientState(IBinder appToken) {
mAppToken = appToken;
mPid = Binder.getCallingPid();
- if (appToken instanceof Binder) {
- // For local clients, there is no reason to track them.
- mStartedOps = null;
- } else {
- mStartedOps = new ArrayList<Op>();
+ // Watch only for remote processes dying
+ if (!(appToken instanceof Binder)) {
try {
mAppToken.linkToDeath(this, 0);
} catch (RemoteException e) {
+ /* do nothing */
}
}
}
@@ -256,7 +256,7 @@
public String toString() {
return "ClientState{" +
"mAppToken=" + mAppToken +
- ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
+ ", " + "pid=" + mPid +
'}';
}
@@ -264,7 +264,7 @@
public void binderDied() {
synchronized (AppOpsService.this) {
for (int i=mStartedOps.size()-1; i>=0; i--) {
- finishOperationLocked(mStartedOps.get(i));
+ finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
}
mClients.remove(mAppToken);
}
@@ -397,6 +397,27 @@
mUidStates.remove(uid);
}
+ // Finish ops other packages started on behalf of the package.
+ final int clientCount = mClients.size();
+ for (int i = 0; i < clientCount; i++) {
+ final ClientState client = mClients.valueAt(i);
+ if (client.mStartedOps == null) {
+ continue;
+ }
+ final int opCount = client.mStartedOps.size();
+ for (int j = opCount - 1; j >= 0; j--) {
+ final Op op = client.mStartedOps.get(j);
+ if (uid == op.uid && packageName.equals(op.packageName)) {
+ finishOperationLocked(op, /*finishNested*/ true);
+ client.mStartedOps.remove(j);
+ if (op.nesting <= 0) {
+ scheduleOpActiveChangedIfNeededLocked(op.op,
+ uid, packageName, false);
+ }
+ }
+ }
+ }
+
if (ops != null) {
scheduleFastWriteLocked();
@@ -1195,8 +1216,11 @@
@Override
public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS,
- "startWatchingActive");
+ int watchedUid = -1;
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+ != PackageManager.PERMISSION_GRANTED) {
+ watchedUid = Binder.getCallingUid();
+ }
if (ops != null) {
Preconditions.checkArrayElementsInRange(ops, 0,
AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
@@ -1210,7 +1234,7 @@
callbacks = new SparseArray<>();
mActiveWatchers.put(callback.asBinder(), callbacks);
}
- final ActiveCallback activeCallback = new ActiveCallback(callback);
+ final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid);
for (int op : ops) {
callbacks.put(op, activeCallback);
}
@@ -1239,7 +1263,8 @@
}
@Override
- public int startOperation(IBinder token, int code, int uid, String packageName) {
+ public int startOperation(IBinder token, int code, int uid, String packageName,
+ boolean startIfModeDefault) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -1265,7 +1290,8 @@
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
final int uidMode = uidState.opModes.get(switchCode);
- if (uidMode != AppOpsManager.MODE_ALLOWED) {
+ if (uidMode != AppOpsManager.MODE_ALLOWED
+ && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
@@ -1274,7 +1300,8 @@
}
} else {
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
+ if (switchOp.mode != AppOpsManager.MODE_ALLOWED
+ && (!startIfModeDefault || switchOp.mode != AppOpsManager.MODE_DEFAULT)) {
if (DEBUG) Slog.d(TAG, "startOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
@@ -1316,13 +1343,11 @@
if (op == null) {
return;
}
- if (client.mStartedOps != null) {
- if (!client.mStartedOps.remove(op)) {
- throw new IllegalStateException("Operation not started: uid" + op.uid
- + " pkg=" + op.packageName + " op=" + op.op);
- }
+ if (!client.mStartedOps.remove(op)) {
+ throw new IllegalStateException("Operation not started: uid" + op.uid
+ + " pkg=" + op.packageName + " op=" + op.op);
}
- finishOperationLocked(op);
+ finishOperationLocked(op, /*finishNested*/ false);
if (op.nesting <= 0) {
scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
}
@@ -1337,6 +1362,9 @@
final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
ActiveCallback callback = callbacks.get(code);
if (callback != null) {
+ if (callback.mUid >= 0 && callback.mUid != uid) {
+ continue;
+ }
if (dispatchedCallbacks == null) {
dispatchedCallbacks = new ArraySet<>();
}
@@ -1380,9 +1408,9 @@
return AppOpsManager.permissionToOpCode(permission);
}
- void finishOperationLocked(Op op) {
- if (op.nesting <= 1) {
- if (op.nesting == 1) {
+ void finishOperationLocked(Op op, boolean finishNested) {
+ if (op.nesting <= 1 || finishNested) {
+ if (op.nesting == 1 || finishNested) {
op.duration = (int)(System.currentTimeMillis() - op.time);
op.time += op.duration;
} else {
@@ -2420,7 +2448,7 @@
pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
ClientState cs = mClients.valueAt(i);
pw.print(" "); pw.println(cs);
- if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
+ if (cs.mStartedOps.size() > 0) {
pw.println(" Started ops:");
for (int j=0; j<cs.mStartedOps.size(); j++) {
Op op = cs.mStartedOps.get(j);
@@ -2651,8 +2679,12 @@
@Override
public boolean isOperationActive(int code, int uid, String packageName) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS,
- "isOperationActive");
+ if (Binder.getCallingUid() != uid) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
verifyIncomingOp(code);
final String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -2661,8 +2693,6 @@
synchronized (AppOpsService.this) {
for (int i = mClients.size() - 1; i >= 0; i--) {
final ClientState client = mClients.valueAt(i);
- if (client.mStartedOps == null) continue;
-
for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
final Op op = client.mStartedOps.get(j);
if (op.op == code && op.uid == uid) return true;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f633003..79297aa 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
@@ -1359,9 +1360,8 @@
if (nai != null) {
synchronized (nai) {
if (nai.networkCapabilities != null) {
- // TODO : don't remove the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- return networkCapabilitiesWithoutUids(nai.networkCapabilities);
+ return networkCapabilitiesWithoutUidsUnlessAllowed(nai.networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
}
}
}
@@ -1374,10 +1374,18 @@
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
- private NetworkCapabilities networkCapabilitiesWithoutUids(NetworkCapabilities nc) {
+ private NetworkCapabilities networkCapabilitiesWithoutUidsUnlessAllowed(
+ NetworkCapabilities nc, int callerPid, int callerUid) {
+ if (checkSettingsPermission(callerPid, callerUid)) return new NetworkCapabilities(nc);
return new NetworkCapabilities(nc).setUids(null);
}
+ private void restrictRequestUidsForCaller(NetworkCapabilities nc) {
+ if (!checkSettingsPermission()) {
+ nc.setSingleUid(Binder.getCallingUid());
+ }
+ }
+
@Override
public NetworkState[] getAllNetworkState() {
// Require internal since we're handing out IMSI details
@@ -1577,6 +1585,16 @@
"ConnectivityService");
}
+ private boolean checkSettingsPermission() {
+ return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_SETTINGS);
+ }
+
+ private boolean checkSettingsPermission(int pid, int uid) {
+ return PERMISSION_GRANTED == mContext.checkPermission(
+ android.Manifest.permission.NETWORK_SETTINGS, pid, uid);
+ }
+
private void enforceTetherAccessPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -4258,13 +4276,12 @@
enforceMeteredApnPolicy(networkCapabilities);
}
ensureRequestableCapabilities(networkCapabilities);
- // Set the UID range for this request to the single UID of the requester.
+ // Set the UID range for this request to the single UID of the requester, or to an empty
+ // set of UIDs if the caller has the appropriate permission and UIDs have not been set.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
// are no visible methods to set the UIDs, an app could use reflection to try and get
// networks for other apps so it's essential that the UIDs are overwritten.
- // TODO : don't forcefully set the UID when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- networkCapabilities.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(networkCapabilities);
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
@@ -4338,9 +4355,7 @@
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
ensureValidNetworkSpecifier(networkCapabilities);
- // TODO : don't forcefully set the UID when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- networkCapabilities.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4394,9 +4409,7 @@
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- // TODO : don't forcefully set the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- nc.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(nc);
if (!ConnectivityManager.checkChangePermission(mContext)) {
// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
@@ -4426,9 +4439,7 @@
ensureValidNetworkSpecifier(networkCapabilities);
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- // TODO : don't forcefully set the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- nc.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(nc);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -4992,8 +5003,8 @@
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities nc =
- networkCapabilitiesWithoutUids(networkAgent.networkCapabilities);
+ final NetworkCapabilities nc = networkCapabilitiesWithoutUidsUnlessAllowed(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(bundle, nc);
break;
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8b5176e..e202618 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -37,6 +37,7 @@
import android.telephony.DisconnectCause;
import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneStateListener;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.PreciseDisconnectCause;
@@ -179,6 +180,8 @@
private ArrayList<List<CellInfo>> mCellInfo = null;
+ private ArrayList<List<PhysicalChannelConfig>> mPhysicalChannelConfigs;
+
private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -335,6 +338,7 @@
mDataConnectionLinkProperties = new LinkProperties[numPhones];
mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
mCellInfo = new ArrayList<List<CellInfo>>();
+ mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -349,6 +353,7 @@
mCallForwarding[i] = false;
mCellLocation[i] = new Bundle();
mCellInfo.add(i, null);
+ mPhysicalChannelConfigs.add(i, null);
mConnectedApns[i] = new ArrayList<String>();
}
@@ -659,6 +664,14 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION) != 0) {
+ try {
+ r.callback.onPhysicalChannelConfigurationChanged(
+ mPhysicalChannelConfigs.get(phoneId));
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -1020,6 +1033,45 @@
}
}
+ public void notifyPhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
+ notifyPhysicalChannelConfigurationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ configs);
+ }
+
+ public void notifyPhysicalChannelConfigurationForSubscriber(int subId,
+ List<PhysicalChannelConfig> configs) {
+ if (!checkNotifyPermission("notifyPhysicalChannelConfiguration()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyPhysicalChannelConfiguration: subId=" + subId + " configs=" + configs);
+ }
+
+ synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mPhysicalChannelConfigs.set(phoneId, configs);
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION)
+ && idMatch(r.subId, subId, phoneId)) {
+ try {
+ if (DBG_LOC) {
+ log("notifyPhysicalChannelConfiguration: mPhysicalChannelConfigs="
+ + configs + " r=" + r);
+ }
+ r.callback.onPhysicalChannelConfigurationChanged(configs);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 14c99b2..752c44a 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -98,7 +98,7 @@
private final Context mContext;
private final PowerManager.WakeLock mWakeLock;
- private final IAppOpsService mAppOpsService;
+ private final AppOpsManager mAppOps;
private final IBatteryStats mBatteryStatsService;
private PowerManagerInternal mPowerManagerInternal;
private InputManager mIm;
@@ -265,8 +265,7 @@
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
mWakeLock.setReferenceCounted(true);
- mAppOpsService =
- IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
BatteryStats.SERVICE_NAME));
@@ -721,17 +720,10 @@
}
private int getAppOpMode(Vibration vib) {
- int mode;
- try {
- mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
- vib.usageHint, vib.uid, vib.opPkg);
- if (mode == AppOpsManager.MODE_ALLOWED) {
- mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to get appop mode for vibration!", e);
- mode = AppOpsManager.MODE_IGNORED;
+ int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
+ vib.usageHint, vib.uid, vib.opPkg);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
}
return mode;
}
@@ -741,11 +733,8 @@
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
try {
if (mCurrentVibration != null) {
- try {
- mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
- mCurrentVibration.opPkg);
- } catch (RemoteException e) { }
+ mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
+ mCurrentVibration.opPkg);
unlinkVibration(mCurrentVibration);
mCurrentVibration = null;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5fc4373..0c6746e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3861,8 +3861,9 @@
return new ServiceDumper(fd, pw, args, opti, dumpAll, dumpPackage);
}
- protected void writeToProto(ProtoOutputStream proto) {
+ protected void writeToProto(ProtoOutputStream proto, long fieldId) {
synchronized (mAm) {
+ final long outterToken = proto.start(fieldId);
int[] users = mAm.mUserController.getUsers();
for (int user : users) {
ServiceMap smap = mServiceMap.get(user);
@@ -3878,6 +3879,7 @@
}
proto.end(token);
}
+ proto.end(outterToken);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 56ed6c8..bac81e7 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -158,6 +158,8 @@
}
private void positionChildAt(ActivityStack stack, int position) {
+ // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
+ // the position internally, also update the logic here
mStacks.remove(stack);
final int insertPosition = getTopInsertPosition(stack, position);
mStacks.add(insertPosition, stack);
@@ -750,7 +752,15 @@
return;
}
- positionChildAt(mHomeStack, Math.max(0, mStacks.indexOf(behindStack) - 1));
+ // Note that positionChildAt will first remove the given stack before inserting into the
+ // list, so we need to adjust the insertion index to account for the removed index
+ // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
+ // position internally
+ final int homeStackIndex = mStacks.indexOf(mHomeStack);
+ final int behindStackIndex = mStacks.indexOf(behindStack);
+ final int insertIndex = homeStackIndex <= behindStackIndex
+ ? behindStackIndex - 1 : behindStackIndex;
+ positionChildAt(mHomeStack, Math.max(0, insertIndex));
}
boolean isSleeping() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d4307d7..6726b6e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -440,15 +440,17 @@
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.am.proto.ActivityManagerServiceProto;
-import com.android.server.am.proto.BroadcastProto;
+import com.android.server.am.proto.ActivityManagerServiceDumpActivitiesProto;
+import com.android.server.am.proto.ActivityManagerServiceDumpBroadcastsProto;
+import com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto;
+import com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
+import com.android.server.am.proto.ActivityManagerServiceDumpServicesProto;
import com.android.server.am.proto.GrantUriProto;
import com.android.server.am.proto.ImportanceTokenProto;
-import com.android.server.am.proto.MemInfoProto;
+import com.android.server.am.proto.MemInfoDumpProto;
import com.android.server.am.proto.NeededUriGrantsProto;
import com.android.server.am.proto.ProcessOomProto;
import com.android.server.am.proto.ProcessToGcProto;
-import com.android.server.am.proto.ProcessesProto;
-import com.android.server.am.proto.ProcessesProto.UidObserverRegistrationProto;
import com.android.server.am.proto.StickyBroadcastProto;
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
@@ -1376,9 +1378,9 @@
void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- proto.write(ProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
- proto.write(ProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
- proto.write(ProcessesProto.PendingTempWhitelist.TAG, tag);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TAG, tag);
proto.end(token);
}
}
@@ -6490,22 +6492,27 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
+ final int[] userIds = mUserController.expandUserId(userId);
+
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
- synchronized(this) {
+ for (int targetUserId : userIds) {
int appId = -1;
try {
appId = UserHandle.getAppId(
- pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
+ pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUserId));
} catch (RemoteException e) {
}
if (appId == -1) {
Slog.w(TAG, "Invalid packageName: " + packageName);
return;
}
- killPackageProcessesLocked(packageName, appId, userId,
- ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+ synchronized (this) {
+ killPackageProcessesLocked(packageName, appId, targetUserId,
+ ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+ }
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -9409,6 +9416,25 @@
allowed = false;
}
}
+ if (pi.pathPermissions != null) {
+ final int N = pi.pathPermissions.length;
+ for (int i=0; i<N; i++) {
+ if (pi.pathPermissions[i] != null
+ && pi.pathPermissions[i].match(grantUri.uri.getPath())) {
+ if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (pi.pathPermissions[i].getReadPermission() != null) {
+ allowed = false;
+ }
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (pi.pathPermissions[i].getWritePermission() != null) {
+ allowed = false;
+ }
+ }
+ break;
+ }
+ }
+ }
if (allowed) {
return -1;
}
@@ -10123,92 +10149,33 @@
}
/**
- * Updates (grants or revokes) a persitable URI permission.
- *
- * @param uri URI to be granted or revoked.
- * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
- * applies to all URIs that are prefixed by this URI.
- * @param packageName target package.
- * @param grant if {@code true} a new permission will be granted, otherwise an existing
- * permission will be revoked.
- * @param userId user handle
- *
- * @return whether or not the requested succeeded.
- *
- * @deprecated TODO(b/72055774): caller should use takePersistableUriPermission() or
- * releasePersistableUriPermission() instead, but such change will be made in a separate CL
- * so it can be easily reverted if it breaks existing functionality.
- */
- @Deprecated // STOPSHIP if not removed
- @Override
- public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
- boolean grant, int userId) {
- enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
- "updatePersistableUriPermission");
- final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
-
- final GrantUri grantUri = new GrantUri(userId, uri, prefix);
-
- boolean persistChanged = false;
- synchronized (this) {
- if (grant) { // Grant
- final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, userId, 0);
- if (pi == null) {
- Slog.w(TAG, "No content provider found for authority " + authority);
- return false;
- }
- final UriPermission permission = findOrCreateUriPermissionLocked(pi.packageName,
- packageName, uid, grantUri);
- if (permission.isNew()) {
- final int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- permission.initPersistedModes(modeFlags, System.currentTimeMillis());
- persistChanged = true;
- } else {
- // Caller should not try to grant permission that is already granted.
- Slog.w(TAG_URI_PERMISSION,
- "permission already granted for " + grantUri.toSafeString());
- return false;
- }
- persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
- } else { // Revoke
- final UriPermission permission = findUriPermissionLocked(uid, grantUri);
- if (permission == null) {
- // Caller should not try to revoke permission that is not granted.
- Slog.v(TAG_URI_PERMISSION, "no permission for " + grantUri.toSafeString());
- return false;
- } else {
- permission.modeFlags = 0;
- removeUriPermissionIfNeededLocked(permission);
- persistChanged = true;
- }
- }
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
- return true;
- }
-
- /**
* @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of package whose uri is being granted to (if {@code null}, uses
+ * calling uid)
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void takePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
- enforceNotIsolatedCaller("takePersistableUriPermission");
+ public void takePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+ final int uid;
+ if (toPackage != null) {
+ enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "takePersistableUriPermission");
+ uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("takePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
GrantUri grantUri = new GrantUri(userId, uri, false);
- UriPermission exactPerm = findUriPermissionLocked(callingUid, grantUri);
- UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ UriPermission exactPerm = findUriPermissionLocked(uid, grantUri);
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, true));
final boolean exactValid = (exactPerm != null)
@@ -10218,7 +10185,7 @@
if (!(exactValid || prefixValid)) {
throw new SecurityException("No persistable permission grants found for UID "
- + callingUid + " and Uri " + grantUri.toSafeString());
+ + uid + " and Uri " + grantUri.toSafeString());
}
if (exactValid) {
@@ -10228,7 +10195,7 @@
persistChanged |= prefixPerm.takePersistableModes(modeFlags);
}
- persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
if (persistChanged) {
schedulePersistUriGrants();
@@ -10238,25 +10205,36 @@
/**
* @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of the target package whose uri is being released (if {@code null},
+ * uses calling uid)
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void releasePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
- enforceNotIsolatedCaller("releasePersistableUriPermission");
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+
+ final int uid;
+ if (toPackage != null) {
+ enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "releasePersistableUriPermission");
+ uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("releasePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
- UriPermission exactPerm = findUriPermissionLocked(callingUid,
+ UriPermission exactPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, true));
- if (exactPerm == null && prefixPerm == null) {
- throw new SecurityException("No permission grants found for UID " + callingUid
+ if (exactPerm == null && prefixPerm == null && toPackage == null) {
+ throw new SecurityException("No permission grants found for UID " + uid
+ " and Uri " + uri.toSafeString());
}
@@ -12855,6 +12833,25 @@
}
@Override
+ public boolean isBackgroundRestricted(String packageName) {
+ final int callingUid = Binder.getCallingUid();
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ final int packageUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.getUserId(callingUid));
+ if (packageUid != callingUid) {
+ throw new IllegalArgumentException("Uid " + callingUid
+ + " cannot query restriction state for package " + packageName);
+ }
+ } catch (RemoteException exc) {
+ // Ignore.
+ }
+ final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+ callingUid, packageName);
+ return (mode != AppOpsManager.MODE_ALLOWED);
+ }
+
+ @Override
public void backgroundWhitelistUid(final int uid) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Only the OS may call backgroundWhitelistUid()");
@@ -15730,12 +15727,12 @@
opti++;
if ("activities".equals(cmd) || "a".equals(cmd)) {
- // output proto is ActivityStackSupervisorProto
+ // output proto is ActivityManagerServiceDumpActivitiesProto
synchronized (this) {
writeActivitiesToProtoLocked(proto);
}
} else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
- // output proto is BroadcastProto
+ // output proto is ActivityManagerServiceDumpBroadcastsProto
synchronized (this) {
writeBroadcastsToProtoLocked(proto);
}
@@ -15757,7 +15754,8 @@
pw.println("Use -h for help.");
}
} else if ("service".equals(cmd)) {
- mServices.writeToProto(proto);
+ // output proto is ActivityManagerServiceDumpServicesProto
+ mServices.writeToProto(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
} else if ("processes".equals(cmd) || "p".equals(cmd)) {
if (opti < args.length) {
dumpPackage = args[opti];
@@ -15779,7 +15777,7 @@
proto.end(broadcastToken);
long serviceToken = proto.start(ActivityManagerServiceProto.SERVICES);
- mServices.writeToProto(proto);
+ mServices.writeToProto(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
proto.end(serviceToken);
long processToken = proto.start(ActivityManagerServiceProto.PROCESSES);
@@ -16142,8 +16140,8 @@
}
private void writeActivitiesToProtoLocked(ProtoOutputStream proto) {
- // The output proto of "activity --proto activities" is ActivityStackSupervisorProto
- mStackSupervisor.writeToProto(proto);
+ // The output proto of "activity --proto activities" is ActivityManagerServiceDumpActivitiesProto
+ mStackSupervisor.writeToProto(proto, ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR);
}
private void dumpLastANRLocked(PrintWriter pw) {
@@ -16840,7 +16838,7 @@
if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
continue;
}
- r.writeToProto(proto, ProcessesProto.PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS);
if (r.persistent) {
numPers++;
}
@@ -16852,7 +16850,7 @@
if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
continue;
}
- r.writeToProto(proto, ProcessesProto.ISOLATED_PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS);
}
for (int i=0; i<mActiveInstrumentation.size(); i++) {
@@ -16861,7 +16859,7 @@
&& !ai.mTargetInfo.packageName.equals(dumpPackage)) {
continue;
}
- ai.writeToProto(proto, ProcessesProto.ACTIVE_INSTRUMENTATIONS);
+ ai.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
}
int whichAppId = getAppId(dumpPackage);
@@ -16870,7 +16868,7 @@
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
continue;
}
- uidRec.writeToProto(proto, ProcessesProto.ACTIVE_UIDS);
+ uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
}
for (int i=0; i<mValidateUids.size(); i++) {
@@ -16878,16 +16876,16 @@
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
continue;
}
- uidRec.writeToProto(proto, ProcessesProto.VALIDATE_UIDS);
+ uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
}
if (mLruProcesses.size() > 0) {
- long lruToken = proto.start(ProcessesProto.LRU_PROCS);
+ long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS);
int total = mLruProcesses.size();
- proto.write(ProcessesProto.LruProcesses.SIZE, total);
- proto.write(ProcessesProto.LruProcesses.NON_ACT_AT, total-mLruProcessActivityStart);
- proto.write(ProcessesProto.LruProcesses.NON_SVC_AT, total-mLruProcessServiceStart);
- writeProcessOomListToProto(proto, ProcessesProto.LruProcesses.LIST, this,
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.SIZE, total);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT, total-mLruProcessActivityStart);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_SVC_AT, total-mLruProcessServiceStart);
+ writeProcessOomListToProto(proto, ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, this,
mLruProcesses,false, dumpPackage);
proto.end(lruToken);
}
@@ -16899,7 +16897,7 @@
if (!r.pkgList.containsKey(dumpPackage)) {
continue;
}
- r.writeToProto(proto, ProcessesProto.PIDS_SELF_LOCKED);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PIDS_SELF_LOCKED);
}
}
}
@@ -16913,7 +16911,7 @@
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
}
- it.writeToProto(proto, ProcessesProto.IMPORTANT_PROCS);
+ it.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.IMPORTANT_PROCS);
}
}
}
@@ -16923,7 +16921,7 @@
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
}
- r.writeToProto(proto, ProcessesProto.PERSISTENT_STARTING_PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PERSISTENT_STARTING_PROCS);
}
for (int i=0; i<mRemovedProcesses.size(); i++) {
@@ -16931,7 +16929,7 @@
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
}
- r.writeToProto(proto, ProcessesProto.REMOVED_PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.REMOVED_PROCS);
}
for (int i=0; i<mProcessesOnHold.size(); i++) {
@@ -16939,41 +16937,41 @@
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
}
- r.writeToProto(proto, ProcessesProto.ON_HOLD_PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ON_HOLD_PROCS);
}
- writeProcessesToGcToProto(proto, ProcessesProto.GC_PROCS, dumpPackage);
- mAppErrors.writeToProto(proto, ProcessesProto.APP_ERRORS, dumpPackage);
+ writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS, dumpPackage);
+ mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS, dumpPackage);
if (dumpPackage == null) {
- mUserController.writeToProto(proto, ProcessesProto.USER_CONTROLLER);
- getGlobalConfiguration().writeToProto(proto, ProcessesProto.GLOBAL_CONFIGURATION);
- proto.write(ProcessesProto.CONFIG_WILL_CHANGE, getFocusedStack().mConfigWillChange);
+ mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
+ getGlobalConfiguration().writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GLOBAL_CONFIGURATION);
+ proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, getFocusedStack().mConfigWillChange);
}
if (mHomeProcess != null && (dumpPackage == null
|| mHomeProcess.pkgList.containsKey(dumpPackage))) {
- mHomeProcess.writeToProto(proto, ProcessesProto.HOME_PROC);
+ mHomeProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
}
if (mPreviousProcess != null && (dumpPackage == null
|| mPreviousProcess.pkgList.containsKey(dumpPackage))) {
- mPreviousProcess.writeToProto(proto, ProcessesProto.PREVIOUS_PROC);
- proto.write(ProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
+ mPreviousProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
}
if (mHeavyWeightProcess != null && (dumpPackage == null
|| mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
- mHeavyWeightProcess.writeToProto(proto, ProcessesProto.HEAVY_WEIGHT_PROC);
+ mHeavyWeightProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
}
for (Map.Entry<String, Integer> entry : mCompatModePackages.getPackages().entrySet()) {
String pkg = entry.getKey();
int mode = entry.getValue();
if (dumpPackage == null || dumpPackage.equals(pkg)) {
- long compatToken = proto.start(ProcessesProto.SCREEN_COMPAT_PACKAGES);
- proto.write(ProcessesProto.ScreenCompatPackage.PACKAGE, pkg);
- proto.write(ProcessesProto.ScreenCompatPackage.MODE, mode);
+ long compatToken = proto.start(ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE, pkg);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE, mode);
proto.end(compatToken);
}
}
@@ -16983,89 +16981,89 @@
final UidObserverRegistration reg = (UidObserverRegistration)
mUidObservers.getRegisteredCallbackCookie(i);
if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
- reg.writeToProto(proto, ProcessesProto.UID_OBSERVERS);
+ reg.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
}
}
for (int v : mDeviceIdleWhitelist) {
- proto.write(ProcessesProto.DEVICE_IDLE_WHITELIST, v);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_WHITELIST, v);
}
for (int v : mDeviceIdleTempWhitelist) {
- proto.write(ProcessesProto.DEVICE_IDLE_TEMP_WHITELIST, v);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_TEMP_WHITELIST, v);
}
if (mPendingTempWhitelist.size() > 0) {
for (int i=0; i < mPendingTempWhitelist.size(); i++) {
mPendingTempWhitelist.valueAt(i).writeToProto(proto,
- ProcessesProto.PENDING_TEMP_WHITELIST);
+ ActivityManagerServiceDumpProcessesProto.PENDING_TEMP_WHITELIST);
}
}
if (dumpPackage == null) {
- final long sleepToken = proto.start(ProcessesProto.SLEEP_STATUS);
- proto.write(ProcessesProto.SleepStatus.WAKEFULNESS,
+ final long sleepToken = proto.start(ActivityManagerServiceDumpProcessesProto.SLEEP_STATUS);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.WAKEFULNESS,
PowerManagerInternal.wakefulnessToProtoEnum(mWakefulness));
for (SleepToken st : mStackSupervisor.mSleepTokens) {
- proto.write(ProcessesProto.SleepStatus.SLEEP_TOKENS, st.toString());
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEP_TOKENS, st.toString());
}
- proto.write(ProcessesProto.SleepStatus.SLEEPING, mSleeping);
- proto.write(ProcessesProto.SleepStatus.SHUTTING_DOWN, mShuttingDown);
- proto.write(ProcessesProto.SleepStatus.TEST_PSS_MODE, mTestPssMode);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEPING, mSleeping);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SHUTTING_DOWN, mShuttingDown);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.TEST_PSS_MODE, mTestPssMode);
proto.end(sleepToken);
if (mRunningVoice != null) {
- final long vrToken = proto.start(ProcessesProto.RUNNING_VOICE);
- proto.write(ProcessesProto.VoiceProto.SESSION, mRunningVoice.toString());
- mVoiceWakeLock.writeToProto(proto, ProcessesProto.VoiceProto.WAKELOCK);
+ final long vrToken = proto.start(ActivityManagerServiceDumpProcessesProto.RUNNING_VOICE);
+ proto.write(ActivityManagerServiceDumpProcessesProto.VoiceProto.SESSION, mRunningVoice.toString());
+ mVoiceWakeLock.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VoiceProto.WAKELOCK);
proto.end(vrToken);
}
- mVrController.writeToProto(proto, ProcessesProto.VR_CONTROLLER);
+ mVrController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER);
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
if (dumpPackage == null || dumpPackage.equals(mDebugApp)
|| dumpPackage.equals(mOrigDebugApp)) {
- final long debugAppToken = proto.start(ProcessesProto.DEBUG);
- proto.write(ProcessesProto.DebugApp.DEBUG_APP, mDebugApp);
- proto.write(ProcessesProto.DebugApp.ORIG_DEBUG_APP, mOrigDebugApp);
- proto.write(ProcessesProto.DebugApp.DEBUG_TRANSIENT, mDebugTransient);
- proto.write(ProcessesProto.DebugApp.ORIG_WAIT_FOR_DEBUGGER, mOrigWaitForDebugger);
+ final long debugAppToken = proto.start(ActivityManagerServiceDumpProcessesProto.DEBUG);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.DEBUG_APP, mDebugApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.ORIG_DEBUG_APP, mOrigDebugApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.DEBUG_TRANSIENT, mDebugTransient);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.ORIG_WAIT_FOR_DEBUGGER, mOrigWaitForDebugger);
proto.end(debugAppToken);
}
}
if (mCurAppTimeTracker != null) {
- mCurAppTimeTracker.writeToProto(proto, ProcessesProto.CURRENT_TRACKER, true);
+ mCurAppTimeTracker.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER, true);
}
if (mMemWatchProcesses.getMap().size() > 0) {
- final long token = proto.start(ProcessesProto.MEM_WATCH_PROCESSES);
+ final long token = proto.start(ActivityManagerServiceDumpProcessesProto.MEM_WATCH_PROCESSES);
ArrayMap<String, SparseArray<Pair<Long, String>>> procs = mMemWatchProcesses.getMap();
for (int i=0; i<procs.size(); i++) {
final String proc = procs.keyAt(i);
final SparseArray<Pair<Long, String>> uids = procs.valueAt(i);
- final long ptoken = proto.start(ProcessesProto.MemWatchProcess.PROCS);
- proto.write(ProcessesProto.MemWatchProcess.Process.NAME, proc);
+ final long ptoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.PROCS);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.NAME, proc);
for (int j=0; j<uids.size(); j++) {
- final long utoken = proto.start(ProcessesProto.MemWatchProcess.Process.MEM_STATS);
+ final long utoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MEM_STATS);
Pair<Long, String> val = uids.valueAt(j);
- proto.write(ProcessesProto.MemWatchProcess.Process.MemStats.UID, uids.keyAt(j));
- proto.write(ProcessesProto.MemWatchProcess.Process.MemStats.SIZE,
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MemStats.UID, uids.keyAt(j));
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MemStats.SIZE,
DebugUtils.sizeValueToString(val.first, new StringBuilder()));
- proto.write(ProcessesProto.MemWatchProcess.Process.MemStats.REPORT_TO, val.second);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MemStats.REPORT_TO, val.second);
proto.end(utoken);
}
proto.end(ptoken);
}
- final long dtoken = proto.start(ProcessesProto.MemWatchProcess.DUMP);
- proto.write(ProcessesProto.MemWatchProcess.Dump.PROC_NAME, mMemWatchDumpProcName);
- proto.write(ProcessesProto.MemWatchProcess.Dump.FILE, mMemWatchDumpFile);
- proto.write(ProcessesProto.MemWatchProcess.Dump.PID, mMemWatchDumpPid);
- proto.write(ProcessesProto.MemWatchProcess.Dump.UID, mMemWatchDumpUid);
+ final long dtoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.DUMP);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PROC_NAME, mMemWatchDumpProcName);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.FILE, mMemWatchDumpFile);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PID, mMemWatchDumpPid);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.UID, mMemWatchDumpUid);
proto.end(dtoken);
proto.end(token);
@@ -17073,58 +17071,58 @@
if (mTrackAllocationApp != null) {
if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
- proto.write(ProcessesProto.TRACK_ALLOCATION_APP, mTrackAllocationApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.TRACK_ALLOCATION_APP, mTrackAllocationApp);
}
}
if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
(mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
- final long token = proto.start(ProcessesProto.PROFILE);
- proto.write(ProcessesProto.Profile.APP_NAME, mProfileApp);
- mProfileProc.writeToProto(proto,ProcessesProto.Profile.PROC);
+ final long token = proto.start(ActivityManagerServiceDumpProcessesProto.PROFILE);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME, mProfileApp);
+ mProfileProc.writeToProto(proto,ActivityManagerServiceDumpProcessesProto.Profile.PROC);
if (mProfilerInfo != null) {
- mProfilerInfo.writeToProto(proto, ProcessesProto.Profile.INFO);
- proto.write(ProcessesProto.Profile.TYPE, mProfileType);
+ mProfilerInfo.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.Profile.INFO);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE, mProfileType);
}
proto.end(token);
}
}
if (dumpPackage == null || dumpPackage.equals(mNativeDebuggingApp)) {
- proto.write(ProcessesProto.NATIVE_DEBUGGING_APP, mNativeDebuggingApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NATIVE_DEBUGGING_APP, mNativeDebuggingApp);
}
if (dumpPackage == null) {
- proto.write(ProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
if (mController != null) {
- final long token = proto.start(ProcessesProto.CONTROLLER);
- proto.write(ProcessesProto.Controller.CONTROLLER, mController.toString());
- proto.write(ProcessesProto.Controller.IS_A_MONKEY, mControllerIsAMonkey);
+ final long token = proto.start(ActivityManagerServiceDumpProcessesProto.CONTROLLER);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mController.toString());
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mControllerIsAMonkey);
proto.end(token);
}
- proto.write(ProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
- proto.write(ProcessesProto.PROCESSES_READY, mProcessesReady);
- proto.write(ProcessesProto.SYSTEM_READY, mSystemReady);
- proto.write(ProcessesProto.BOOTED, mBooted);
- proto.write(ProcessesProto.FACTORY_TEST, mFactoryTest);
- proto.write(ProcessesProto.BOOTING, mBooting);
- proto.write(ProcessesProto.CALL_FINISH_BOOTING, mCallFinishBooting);
- proto.write(ProcessesProto.BOOT_ANIMATION_COMPLETE, mBootAnimationComplete);
- proto.write(ProcessesProto.LAST_POWER_CHECK_UPTIME_MS, mLastPowerCheckUptime);
- mStackSupervisor.mGoingToSleep.writeToProto(proto, ProcessesProto.GOING_TO_SLEEP);
- mStackSupervisor.mLaunchingActivity.writeToProto(proto, ProcessesProto.LAUNCHING_ACTIVITY);
- proto.write(ProcessesProto.ADJ_SEQ, mAdjSeq);
- proto.write(ProcessesProto.LRU_SEQ, mLruSeq);
- proto.write(ProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs);
- proto.write(ProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
- proto.write(ProcessesProto.NEW_NUM_SERVICE_PROCS, mNewNumServiceProcs);
- proto.write(ProcessesProto.ALLOW_LOWER_MEM_LEVEL, mAllowLowerMemLevel);
- proto.write(ProcessesProto.LAST_MEMORY_LEVEL, mLastMemoryLevel);
- proto.write(ProcessesProto.LAST_NUM_PROCESSES, mLastNumProcesses);
+ proto.write(ActivityManagerServiceDumpProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PROCESSES_READY, mProcessesReady);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SYSTEM_READY, mSystemReady);
+ proto.write(ActivityManagerServiceDumpProcessesProto.BOOTED, mBooted);
+ proto.write(ActivityManagerServiceDumpProcessesProto.FACTORY_TEST, mFactoryTest);
+ proto.write(ActivityManagerServiceDumpProcessesProto.BOOTING, mBooting);
+ proto.write(ActivityManagerServiceDumpProcessesProto.CALL_FINISH_BOOTING, mCallFinishBooting);
+ proto.write(ActivityManagerServiceDumpProcessesProto.BOOT_ANIMATION_COMPLETE, mBootAnimationComplete);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LAST_POWER_CHECK_UPTIME_MS, mLastPowerCheckUptime);
+ mStackSupervisor.mGoingToSleep.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GOING_TO_SLEEP);
+ mStackSupervisor.mLaunchingActivity.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mLruSeq);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NEW_NUM_SERVICE_PROCS, mNewNumServiceProcs);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ALLOW_LOWER_MEM_LEVEL, mAllowLowerMemLevel);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LAST_MEMORY_LEVEL, mLastMemoryLevel);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LAST_NUM_PROCESSES, mLastNumProcesses);
long now = SystemClock.uptimeMillis();
- ProtoUtils.toDuration(proto, ProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
- proto.write(ProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
+ ProtoUtils.toDuration(proto, ActivityManagerServiceDumpProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
}
}
@@ -17434,15 +17432,15 @@
Iterator it = mRegisteredReceivers.values().iterator();
while (it.hasNext()) {
ReceiverList r = (ReceiverList)it.next();
- r.writeToProto(proto, BroadcastProto.RECEIVER_LIST);
+ r.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_LIST);
}
}
- mReceiverResolver.writeToProto(proto, BroadcastProto.RECEIVER_RESOLVER);
+ mReceiverResolver.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_RESOLVER);
for (BroadcastQueue q : mBroadcastQueues) {
- q.writeToProto(proto, BroadcastProto.BROADCAST_QUEUE);
+ q.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
}
for (int user=0; user<mStickyBroadcasts.size(); user++) {
- long token = proto.start(BroadcastProto.STICKY_BROADCASTS);
+ long token = proto.start(ActivityManagerServiceDumpBroadcastsProto.STICKY_BROADCASTS);
proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user));
for (Map.Entry<String, ArrayList<Intent>> ent
: mStickyBroadcasts.valueAt(user).entrySet()) {
@@ -17457,9 +17455,10 @@
proto.end(token);
}
- long handlerToken = proto.start(BroadcastProto.HANDLER);
- proto.write(BroadcastProto.MainHandler.HANDLER, mHandler.toString());
- mHandler.getLooper().writeToProto(proto, BroadcastProto.MainHandler.LOOPER);
+ long handlerToken = proto.start(ActivityManagerServiceDumpBroadcastsProto.HANDLER);
+ proto.write(ActivityManagerServiceDumpBroadcastsProto.MainHandler.HANDLER, mHandler.toString());
+ mHandler.getLooper().writeToProto(proto,
+ ActivityManagerServiceDumpBroadcastsProto.MainHandler.LOOPER);
proto.end(handlerToken);
}
@@ -18221,17 +18220,17 @@
MemItem mi = items.get(i);
final long token = proto.start(fieldId);
- proto.write(MemInfoProto.MemItem.TAG, tag);
- proto.write(MemInfoProto.MemItem.LABEL, mi.shortLabel);
- proto.write(MemInfoProto.MemItem.IS_PROC, mi.isProc);
- proto.write(MemInfoProto.MemItem.ID, mi.id);
- proto.write(MemInfoProto.MemItem.HAS_ACTIVITIES, mi.hasActivities);
- proto.write(MemInfoProto.MemItem.PSS_KB, mi.pss);
+ proto.write(MemInfoDumpProto.MemItem.TAG, tag);
+ proto.write(MemInfoDumpProto.MemItem.LABEL, mi.shortLabel);
+ proto.write(MemInfoDumpProto.MemItem.IS_PROC, mi.isProc);
+ proto.write(MemInfoDumpProto.MemItem.ID, mi.id);
+ proto.write(MemInfoDumpProto.MemItem.HAS_ACTIVITIES, mi.hasActivities);
+ proto.write(MemInfoDumpProto.MemItem.PSS_KB, mi.pss);
if (dumpSwapPss) {
- proto.write(MemInfoProto.MemItem.SWAP_PSS_KB, mi.swapPss);
+ proto.write(MemInfoDumpProto.MemItem.SWAP_PSS_KB, mi.swapPss);
}
if (mi.subitems != null) {
- dumpMemItems(proto, MemInfoProto.MemItem.SUB_ITEMS, mi.shortLabel, mi.subitems,
+ dumpMemItems(proto, MemInfoDumpProto.MemItem.SUB_ITEMS, mi.shortLabel, mi.subitems,
true, dumpSwapPss);
}
proto.end(token);
@@ -18985,16 +18984,16 @@
if (nativeProcs.size() > 0) {
ProtoOutputStream proto = new ProtoOutputStream(fd);
- proto.write(MemInfoProto.UPTIME_DURATION_MS, uptimeMs);
- proto.write(MemInfoProto.ELAPSED_REALTIME_MS, realtimeMs);
+ proto.write(MemInfoDumpProto.UPTIME_DURATION_MS, uptimeMs);
+ proto.write(MemInfoDumpProto.ELAPSED_REALTIME_MS, realtimeMs);
Debug.MemoryInfo mi = null;
for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
final ProcessCpuTracker.Stats r = nativeProcs.get(i);
final int pid = r.pid;
- final long nToken = proto.start(MemInfoProto.NATIVE_PROCESSES);
+ final long nToken = proto.start(MemInfoDumpProto.NATIVE_PROCESSES);
- proto.write(MemInfoProto.ProcessMemory.PID, pid);
- proto.write(MemInfoProto.ProcessMemory.PROCESS_NAME, r.baseName);
+ proto.write(MemInfoDumpProto.ProcessMemory.PID, pid);
+ proto.write(MemInfoDumpProto.ProcessMemory.PROCESS_NAME, r.baseName);
if (mi == null) {
mi = new Debug.MemoryInfo();
@@ -19026,8 +19025,8 @@
ProtoOutputStream proto = new ProtoOutputStream(fd);
- proto.write(MemInfoProto.UPTIME_DURATION_MS, uptimeMs);
- proto.write(MemInfoProto.ELAPSED_REALTIME_MS, realtimeMs);
+ proto.write(MemInfoDumpProto.UPTIME_DURATION_MS, uptimeMs);
+ proto.write(MemInfoDumpProto.ELAPSED_REALTIME_MS, realtimeMs);
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
@@ -19092,10 +19091,10 @@
}
if (opts.dumpDetails) {
if (opts.localOnly) {
- final long aToken = proto.start(MemInfoProto.APP_PROCESSES);
- final long mToken = proto.start(MemInfoProto.AppData.PROCESS_MEMORY);
- proto.write(MemInfoProto.ProcessMemory.PID, pid);
- proto.write(MemInfoProto.ProcessMemory.PROCESS_NAME, r.processName);
+ final long aToken = proto.start(MemInfoDumpProto.APP_PROCESSES);
+ final long mToken = proto.start(MemInfoDumpProto.AppData.PROCESS_MEMORY);
+ proto.write(MemInfoDumpProto.ProcessMemory.PID, pid);
+ proto.write(MemInfoDumpProto.ProcessMemory.PROCESS_NAME, r.processName);
ActivityThread.dumpMemInfoTable(proto, mi, opts.dumpDalvik,
opts.dumpSummaryOnly, 0, 0, 0, 0, 0, 0);
proto.end(mToken);
@@ -19107,7 +19106,7 @@
thread.dumpMemInfoProto(tp.getWriteFd(),
mi, opts.dumpFullDetails, opts.dumpDalvik, opts.dumpSummaryOnly,
opts.dumpUnreachable, innerArgs);
- proto.write(MemInfoProto.APP_PROCESSES, tp.get());
+ proto.write(MemInfoDumpProto.APP_PROCESSES, tp.get());
} finally {
tp.kill();
}
@@ -19295,13 +19294,13 @@
opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && totalSwapPss != 0;
if (!opts.oomOnly) {
- dumpMemItems(proto, MemInfoProto.TOTAL_PSS_BY_PROCESS, "proc",
+ dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_PROCESS, "proc",
procMems, true, opts.dumpSwapPss);
}
- dumpMemItems(proto, MemInfoProto.TOTAL_PSS_BY_OOM_ADJUSTMENT, "oom",
+ dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_OOM_ADJUSTMENT, "oom",
oomMems, false, opts.dumpSwapPss);
if (!brief && !opts.oomOnly) {
- dumpMemItems(proto, MemInfoProto.TOTAL_PSS_BY_CATEGORY, "cat",
+ dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_CATEGORY, "cat",
catMems, true, opts.dumpSwapPss);
}
MemInfoReader memInfo = new MemInfoReader();
@@ -19319,40 +19318,40 @@
}
}
if (!brief) {
- proto.write(MemInfoProto.TOTAL_RAM_KB, memInfo.getTotalSizeKb());
- proto.write(MemInfoProto.STATUS, mLastMemoryLevel);
- proto.write(MemInfoProto.CACHED_PSS_KB, cachedPss);
- proto.write(MemInfoProto.CACHED_KERNEL_KB, memInfo.getCachedSizeKb());
- proto.write(MemInfoProto.FREE_KB, memInfo.getFreeSizeKb());
+ proto.write(MemInfoDumpProto.TOTAL_RAM_KB, memInfo.getTotalSizeKb());
+ proto.write(MemInfoDumpProto.STATUS, mLastMemoryLevel);
+ proto.write(MemInfoDumpProto.CACHED_PSS_KB, cachedPss);
+ proto.write(MemInfoDumpProto.CACHED_KERNEL_KB, memInfo.getCachedSizeKb());
+ proto.write(MemInfoDumpProto.FREE_KB, memInfo.getFreeSizeKb());
}
long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
- proto.write(MemInfoProto.USED_PSS_KB, totalPss - cachedPss);
- proto.write(MemInfoProto.USED_KERNEL_KB, memInfo.getKernelUsedSizeKb());
- proto.write(MemInfoProto.LOST_RAM_KB, lostRAM);
+ proto.write(MemInfoDumpProto.USED_PSS_KB, totalPss - cachedPss);
+ proto.write(MemInfoDumpProto.USED_KERNEL_KB, memInfo.getKernelUsedSizeKb());
+ proto.write(MemInfoDumpProto.LOST_RAM_KB, lostRAM);
if (!brief) {
if (memInfo.getZramTotalSizeKb() != 0) {
- proto.write(MemInfoProto.TOTAL_ZRAM_KB, memInfo.getZramTotalSizeKb());
- proto.write(MemInfoProto.ZRAM_PHYSICAL_USED_IN_SWAP_KB,
+ proto.write(MemInfoDumpProto.TOTAL_ZRAM_KB, memInfo.getZramTotalSizeKb());
+ proto.write(MemInfoDumpProto.ZRAM_PHYSICAL_USED_IN_SWAP_KB,
memInfo.getSwapTotalSizeKb() - memInfo.getSwapFreeSizeKb());
- proto.write(MemInfoProto.TOTAL_ZRAM_SWAP_KB, memInfo.getSwapTotalSizeKb());
+ proto.write(MemInfoDumpProto.TOTAL_ZRAM_SWAP_KB, memInfo.getSwapTotalSizeKb());
}
final long[] ksm = getKsmInfo();
- proto.write(MemInfoProto.KSM_SHARING_KB, ksm[KSM_SHARING]);
- proto.write(MemInfoProto.KSM_SHARED_KB, ksm[KSM_SHARED]);
- proto.write(MemInfoProto.KSM_UNSHARED_KB, ksm[KSM_UNSHARED]);
- proto.write(MemInfoProto.KSM_VOLATILE_KB, ksm[KSM_VOLATILE]);
+ proto.write(MemInfoDumpProto.KSM_SHARING_KB, ksm[KSM_SHARING]);
+ proto.write(MemInfoDumpProto.KSM_SHARED_KB, ksm[KSM_SHARED]);
+ proto.write(MemInfoDumpProto.KSM_UNSHARED_KB, ksm[KSM_UNSHARED]);
+ proto.write(MemInfoDumpProto.KSM_VOLATILE_KB, ksm[KSM_VOLATILE]);
- proto.write(MemInfoProto.TUNING_MB, ActivityManager.staticGetMemoryClass());
- proto.write(MemInfoProto.TUNING_LARGE_MB, ActivityManager.staticGetLargeMemoryClass());
- proto.write(MemInfoProto.OOM_KB,
+ proto.write(MemInfoDumpProto.TUNING_MB, ActivityManager.staticGetMemoryClass());
+ proto.write(MemInfoDumpProto.TUNING_LARGE_MB, ActivityManager.staticGetLargeMemoryClass());
+ proto.write(MemInfoDumpProto.OOM_KB,
mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ) / 1024);
- proto.write(MemInfoProto.RESTORE_LIMIT_KB,
+ proto.write(MemInfoDumpProto.RESTORE_LIMIT_KB,
mProcessList.getCachedRestoreThresholdKb());
- proto.write(MemInfoProto.IS_LOW_RAM_DEVICE, ActivityManager.isLowRamDeviceStatic());
- proto.write(MemInfoProto.IS_HIGH_END_GFX, ActivityManager.isHighEndGfx());
+ proto.write(MemInfoDumpProto.IS_LOW_RAM_DEVICE, ActivityManager.isLowRamDeviceStatic());
+ proto.write(MemInfoDumpProto.IS_HIGH_END_GFX, ActivityManager.isHighEndGfx());
}
}
@@ -26117,6 +26116,10 @@
return getRecentTasks().isCallerRecents(callingUid);
}
+ public boolean isRecentsComponentHomeActivity(int userId) {
+ return getRecentTasks().isRecentsComponentHomeActivity(userId);
+ }
+
@Override
public boolean isUidActive(int uid) {
synchronized (ActivityManagerService.this) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 3b2a22d..81dae39 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -51,6 +51,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
+import android.opengl.GLES10;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -62,6 +63,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DebugUtils;
@@ -81,16 +83,18 @@
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.Map;
+import java.util.Set;
import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.opengles.GL;
-import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
import static android.app.ActivityManager.RESIZE_MODE_USER;
@@ -1638,6 +1642,11 @@
}
int runSwitchUser(PrintWriter pw) throws RemoteException {
+ UserManager userManager = mInternal.mContext.getSystemService(UserManager.class);
+ if (!userManager.canSwitchUsers()) {
+ getErrPrintWriter().println("Error: disallowed switching user");
+ return -1;
+ }
String user = getNextArgRequired();
mInterface.switchUser(Integer.parseInt(user));
return 0;
@@ -1852,6 +1861,137 @@
}
}
+ /**
+ * Adds all supported GL extensions for a provided EGLConfig to a set by creating an EGLContext
+ * and EGLSurface and querying extensions.
+ *
+ * @param egl An EGL API object
+ * @param display An EGLDisplay to create a context and surface with
+ * @param config The EGLConfig to get the extensions for
+ * @param surfaceSize eglCreatePbufferSurface generic parameters
+ * @param contextAttribs eglCreateContext generic parameters
+ * @param glExtensions A Set<String> to add GL extensions to
+ */
+ private static void addExtensionsForConfig(
+ EGL10 egl,
+ EGLDisplay display,
+ EGLConfig config,
+ int[] surfaceSize,
+ int[] contextAttribs,
+ Set<String> glExtensions) {
+ // Create a context.
+ EGLContext context =
+ egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, contextAttribs);
+ // No-op if we can't create a context.
+ if (context == EGL10.EGL_NO_CONTEXT) {
+ return;
+ }
+
+ // Create a surface.
+ EGLSurface surface = egl.eglCreatePbufferSurface(display, config, surfaceSize);
+ if (surface == EGL10.EGL_NO_SURFACE) {
+ egl.eglDestroyContext(display, context);
+ return;
+ }
+
+ // Update the current surface and context.
+ egl.eglMakeCurrent(display, surface, surface, context);
+
+ // Get the list of extensions.
+ String extensionList = GLES10.glGetString(GLES10.GL_EXTENSIONS);
+ if (!TextUtils.isEmpty(extensionList)) {
+ // The list of extensions comes from the driver separated by spaces.
+ // Split them apart and add them into a Set for deduping purposes.
+ for (String extension : extensionList.split(" ")) {
+ glExtensions.add(extension);
+ }
+ }
+
+ // Tear down the context and surface for this config.
+ egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ egl.eglDestroySurface(display, surface);
+ egl.eglDestroyContext(display, context);
+ }
+
+
+ Set<String> getGlExtensionsFromDriver() {
+ Set<String> glExtensions = new HashSet<>();
+
+ // Get the EGL implementation.
+ EGL10 egl = (EGL10) EGLContext.getEGL();
+ if (egl == null) {
+ getErrPrintWriter().println("Warning: couldn't get EGL");
+ return glExtensions;
+ }
+
+ // Get the default display and initialize it.
+ EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ int[] version = new int[2];
+ egl.eglInitialize(display, version);
+
+ // Call getConfigs() in order to find out how many there are.
+ int[] numConfigs = new int[1];
+ if (!egl.eglGetConfigs(display, null, 0, numConfigs)) {
+ getErrPrintWriter().println("Warning: couldn't get EGL config count");
+ return glExtensions;
+ }
+
+ // Allocate space for all configs and ask again.
+ EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+ if (!egl.eglGetConfigs(display, configs, numConfigs[0], numConfigs)) {
+ getErrPrintWriter().println("Warning: couldn't get EGL configs");
+ return glExtensions;
+ }
+
+ // Allocate surface size parameters outside of the main loop to cut down
+ // on GC thrashing. 1x1 is enough since we are only using it to get at
+ // the list of extensions.
+ int[] surfaceSize =
+ new int[] {
+ EGL10.EGL_WIDTH, 1,
+ EGL10.EGL_HEIGHT, 1,
+ EGL10.EGL_NONE
+ };
+
+ // For when we need to create a GLES2.0 context.
+ final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ int[] gles2 = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
+
+ // For getting return values from eglGetConfigAttrib
+ int[] attrib = new int[1];
+
+ for (int i = 0; i < numConfigs[0]; i++) {
+ // Get caveat for this config in order to skip slow (i.e. software) configs.
+ egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_CAVEAT, attrib);
+ if (attrib[0] == EGL10.EGL_SLOW_CONFIG) {
+ continue;
+ }
+
+ // If the config does not support pbuffers we cannot do an eglMakeCurrent
+ // on it in addExtensionsForConfig(), so skip it here. Attempting to make
+ // it current with a pbuffer will result in an EGL_BAD_MATCH error
+ egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_SURFACE_TYPE, attrib);
+ if ((attrib[0] & EGL10.EGL_PBUFFER_BIT) == 0) {
+ continue;
+ }
+
+ final int EGL_OPENGL_ES_BIT = 0x0001;
+ final int EGL_OPENGL_ES2_BIT = 0x0004;
+ egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_RENDERABLE_TYPE, attrib);
+ if ((attrib[0] & EGL_OPENGL_ES_BIT) != 0) {
+ addExtensionsForConfig(egl, display, configs[i], surfaceSize, null, glExtensions);
+ }
+ if ((attrib[0] & EGL_OPENGL_ES2_BIT) != 0) {
+ addExtensionsForConfig(egl, display, configs[i], surfaceSize, gles2, glExtensions);
+ }
+ }
+
+ // Release all EGL resources.
+ egl.eglTerminate(display);
+
+ return glExtensions;
+ }
+
private void writeDeviceConfig(ProtoOutputStream protoOutputStream, long fieldId,
PrintWriter pw, Configuration config, DisplayManager dm) {
Point stableSize = dm.getStableDisplaySize();
@@ -1900,18 +2040,24 @@
}
}
- /*
- GL10 gl = ((GL10)((EGL10)EGLContext.getEGL()).eglGetCurrentContext().getGL());
- protoOutputStream.write(DeviceConfigurationProto.OPENGL_VERSION,
- gl.glGetString(GL10.GL_VERSION));
- String glExtensions = gl.glGetString(GL10.GL_EXTENSIONS);
- for (String ext : glExtensions.split(" ")) {
- protoOutputStream.write(DeviceConfigurationProto.OPENGL_EXTENSIONS, ext);
+ Set<String> glExtensionsSet = getGlExtensionsFromDriver();
+ String[] glExtensions = new String[glExtensionsSet.size()];
+ glExtensions = glExtensionsSet.toArray(glExtensions);
+ Arrays.sort(glExtensions);
+ for (int i = 0; i < glExtensions.length; i++) {
+ if (protoOutputStream != null) {
+ protoOutputStream.write(DeviceConfigurationProto.OPENGL_EXTENSIONS,
+ glExtensions[i]);
+ }
+ if (pw != null) {
+ pw.print("opengl-extensions: "); pw.println(glExtensions[i]);
+ }
+
}
- */
PackageManager pm = mInternal.mContext.getPackageManager();
List<SharedLibraryInfo> slibs = pm.getSharedLibraries(0);
+ Collections.sort(slibs, Comparator.comparing(SharedLibraryInfo::getName));
for (int i = 0; i < slibs.size(); i++) {
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.SHARED_LIBRARIES,
@@ -1923,6 +2069,8 @@
}
FeatureInfo[] features = pm.getSystemAvailableFeatures();
+ Arrays.sort(features, (o1, o2) ->
+ (o1.name == o2.name ? 0 : (o1.name == null ? -1 : o1.name.compareTo(o2.name))));
for (int i = 0; i < features.length; i++) {
if (features[i].name != null) {
if (protoOutputStream != null) {
@@ -2805,7 +2953,7 @@
pw.println(" crash [--user <USER_ID>] <PACKAGE|PID>");
pw.println(" Induce a VM crash in the specified package or process");
pw.println(" kill [--user <USER_ID> | all | current] <PACKAGE>");
- pw.println(" Kill all processes associated with the given application.");
+ pw.println(" Kill all background processes associated with the given application.");
pw.println(" kill-all");
pw.println(" Kill all processes that are safe to kill (cached, etc).");
pw.println(" make-uid-idle [--user <USER_ID> | all | current] <PACKAGE>");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 978e344..5d5ed55 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -51,6 +51,7 @@
import android.util.StatsLog;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.server.LocalServices;
@@ -74,8 +75,6 @@
private static final long INVALID_START_TIME = -1;
private static final int MSG_CHECK_VISIBILITY = 0;
- private static final int MSG_LOG_APP_TRANSITION = 1;
- private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 2;
// Preallocated strings we are sending to tron, so we don't have to allocate a new one every
// time we log.
@@ -116,13 +115,6 @@
final SomeArgs args = (SomeArgs) msg.obj;
checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
break;
- case MSG_LOG_APP_TRANSITION:
- logAppTransition(msg.arg1, msg.arg2,
- (WindowingModeTransitionInfoSnapshot) msg.obj);
- break;
- case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE:
- logAppStartMemoryStateCapture((WindowingModeTransitionInfo) msg.obj);
- break;
}
}
}
@@ -141,11 +133,13 @@
private final class WindowingModeTransitionInfoSnapshot {
final private ApplicationInfo applicationInfo;
+ final private ProcessRecord processRecord;
final private String packageName;
final private String launchedActivityName;
final private String launchedActivityLaunchedFromPackage;
final private String launchedActivityLaunchToken;
final private String launchedActivityAppRecordRequiredAbi;
+ final private String processName;
final private int reason;
final private int startingWindowDelayMs;
final private int bindApplicationDelayMs;
@@ -166,6 +160,8 @@
bindApplicationDelayMs = info.bindApplicationDelayMs;
windowsDrawnDelayMs = info.windowsDrawnDelayMs;
type = getTransitionType(info);
+ processRecord = findProcessForActivity(info.launchedActivity);
+ processName = info.launchedActivity.processName;
}
}
@@ -505,15 +501,16 @@
// This will avoid any races with other operations that modify the ActivityRecord.
final WindowingModeTransitionInfoSnapshot infoSnapshot =
new WindowingModeTransitionInfoSnapshot(info);
- mHandler.obtainMessage(MSG_LOG_APP_TRANSITION, mCurrentTransitionDeviceUptime,
- mCurrentTransitionDelayMs, infoSnapshot).sendToTarget();
+ final int currentTransitionDeviceUptime = mCurrentTransitionDeviceUptime;
+ final int currentTransitionDelayMs = mCurrentTransitionDelayMs;
+ BackgroundThread.getHandler().post(() -> logAppTransition(
+ currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot));
info.launchedActivity.info.launchToken = null;
- mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget();
}
}
- // This gets called on the handler without holding the activity manager lock.
+ // This gets called on a background thread without holding the activity manager lock.
private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs,
WindowingModeTransitionInfoSnapshot info) {
final LogMaker builder = new LogMaker(APP_TRANSITION);
@@ -572,6 +569,7 @@
launchToken,
packageOptimizationInfo.getCompilationReason(),
packageOptimizationInfo.getCompilationFilter());
+ logAppStartMemoryStateCapture(info);
}
private int convertAppStartTransitionType(int tronType) {
@@ -629,15 +627,14 @@
return -1;
}
- private void logAppStartMemoryStateCapture(WindowingModeTransitionInfo info) {
- final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity);
- if (processRecord == null) {
+ private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) {
+ if (info.processRecord == null) {
if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
return;
}
- final int pid = processRecord.pid;
- final int uid = info.launchedActivity.appInfo.uid;
+ final int pid = info.processRecord.pid;
+ final int uid = info.applicationInfo.uid;
final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
if (memoryStat == null) {
if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
@@ -647,8 +644,8 @@
StatsLog.write(
StatsLog.APP_START_MEMORY_STATE_CAPTURED,
uid,
- info.launchedActivity.processName,
- info.launchedActivity.info.name,
+ info.processName,
+ info.launchedActivityName,
memoryStat.pgfault,
memoryStat.pgmajfault,
memoryStat.rssInBytes,
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8cc9273..ae98ca0 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -230,6 +230,8 @@
private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
+ private static final int MAX_STORED_STATE_TRANSITIONS = 5;
+
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
AppWindowContainerController mWindowContainerController;
@@ -366,6 +368,28 @@
private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
+ private final ArrayList<StateTransition> mRecentTransitions = new ArrayList<>();
+
+ // TODO(b/71506345): Remove once issue has been resolved.
+ private static class StateTransition {
+ final long time;
+ final ActivityState prev;
+ final ActivityState state;
+ final String reason;
+
+ StateTransition(ActivityState prev, ActivityState state, String reason) {
+ time = System.currentTimeMillis();
+ this.prev = prev;
+ this.state = state;
+ this.reason = reason;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + prev + "->" + state + ":" + reason + "@" + time + "]";
+ }
+ }
+
private static String startingWindowStateToString(int state) {
switch (state) {
case STARTING_WINDOW_NOT_SHOWN:
@@ -380,9 +404,18 @@
}
String getLifecycleDescription(String reason) {
+ StringBuilder transitionBuilder = new StringBuilder();
+
+ for (int i = 0, size = mRecentTransitions.size(); i < size; ++i) {
+ transitionBuilder.append(mRecentTransitions.get(i));
+ if (i + 1 < size) {
+ transitionBuilder.append(",");
+ }
+ }
+
return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
+ ", package=" + packageName + ", state=" + mState + ", reason=" + reason
- + ", time=" + System.currentTimeMillis();
+ + ", time=" + System.currentTimeMillis() + " transitions=" + transitionBuilder;
}
void dump(PrintWriter pw, String prefix) {
@@ -1581,24 +1614,15 @@
void setState(ActivityState state, String reason) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ " to:" + state + " reason:" + reason);
- final boolean stateChanged = mState != state;
+ final ActivityState prev = mState;
mState = state;
- if (stateChanged && isState(DESTROYING, DESTROYED)) {
- makeFinishingLocked();
-
- // When moving to the destroyed state, immediately destroy the activity in the
- // associated stack. Most paths for finishing an activity will handle an activity's path
- // to destroy through mechanisms such as ActivityStackSupervisor#mFinishingActivities.
- // However, moving to the destroyed state directly (as in the case of an app dying) and
- // marking it as finished will lead to cleanup steps that will prevent later handling
- // from happening.
- if (isState(DESTROYED)) {
- final ActivityStack stack = getStack();
- if (stack != null) {
- stack.activityDestroyedLocked(this, reason);
- }
+ if (mState != prev) {
+ if (mRecentTransitions.size() == MAX_STORED_STATE_TRANSITIONS) {
+ mRecentTransitions.remove(0);
}
+
+ mRecentTransitions.add(new StateTransition(prev, state, reason));
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4987b33..728c07d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -109,6 +109,7 @@
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
import android.app.servertransaction.ActivityResultItem;
+import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.WindowVisibilityItem;
import android.app.servertransaction.DestroyActivityItem;
@@ -603,6 +604,8 @@
// the one where the home stack is visible since recents isn't visible yet, but the
// divider will be off. I think we should just make the initial bounds that of home
// so that the divider matches and remove this logic.
+ // TODO: This is currently only called when entering split-screen while in another
+ // task, and from the tests
final ActivityStack recentStack = display.getOrCreateStack(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS,
true /* onTop */);
@@ -2607,6 +2610,8 @@
}
try {
+ final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread,
+ next.appToken);
// Deliver all pending results.
ArrayList<ResultInfo> a = next.results;
if (a != null) {
@@ -2614,15 +2619,13 @@
if (!next.finishing && N > 0) {
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Delivering results to " + next + ": " + a);
- mService.mLifecycleManager.scheduleTransaction(next.app.thread,
- next.appToken, ActivityResultItem.obtain(a));
+ transaction.addCallback(ActivityResultItem.obtain(a));
}
}
if (next.newIntents != null) {
- mService.mLifecycleManager.scheduleTransaction(next.app.thread,
- next.appToken, NewIntentItem.obtain(next.newIntents,
- false /* andPause */));
+ transaction.addCallback(NewIntentItem.obtain(next.newIntents,
+ false /* andPause */));
}
// Well the app will no longer be stopped.
@@ -2639,11 +2642,13 @@
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
- mService.mLifecycleManager.scheduleTransaction(next.app.thread, next.appToken,
+
+ transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.repProcState,
mService.isNextTransitionForward())
.setDescription(next.getLifecycleDescription(
"resumeTopActivityInnerLocked")));
+ mService.mLifecycleManager.scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
+ next);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5577186..26ffe95 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -93,6 +93,7 @@
import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS;
import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
@@ -164,7 +165,6 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
-import android.view.RemoteAnimationAdapter;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -2540,6 +2540,11 @@
}
}
+ void deferUpdateRecentsHomeStackBounds() {
+ deferUpdateBounds(ACTIVITY_TYPE_RECENTS);
+ deferUpdateBounds(ACTIVITY_TYPE_HOME);
+ }
+
void deferUpdateBounds(int activityType) {
final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
@@ -2547,6 +2552,11 @@
}
}
+ void continueUpdateRecentsHomeStackBounds() {
+ continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
+ continueUpdateBounds(ACTIVITY_TYPE_HOME);
+ }
+
void continueUpdateBounds(int activityType) {
final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
@@ -2555,7 +2565,7 @@
}
void notifyAppTransitionDone() {
- continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
+ continueUpdateRecentsHomeStackBounds();
for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
final int taskId = mResizingTasksDuringAnimation.valueAt(i);
final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY);
@@ -3760,12 +3770,15 @@
pw.print(prefix); pw.print(prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix);
}
}
+ pw.print(prefix); pw.print("isHomeRecentsComponent=");
+ pw.print(mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser));
mKeyguardController.dump(pw, prefix);
mService.mLockTaskController.dump(pw, prefix);
}
- public void writeToProto(ProtoOutputStream proto) {
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
@@ -3781,6 +3794,9 @@
} else {
proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
}
+ proto.write(IS_HOME_RECENTS_COMPONENT,
+ mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser));
+ proto.end(token);
}
/**
@@ -4546,14 +4562,14 @@
// Defer updating the stack in which recents is until the app transition is done, to
// not run into issues where we still need to draw the task in recents but the
// docked stack is already created.
- deferUpdateBounds(ACTIVITY_TYPE_RECENTS);
+ deferUpdateRecentsHomeStackBounds();
mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
}
task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
activityOptions, ON_TOP);
if (task == null) {
- continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
+ continueUpdateRecentsHomeStackBounds();
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
@@ -4611,6 +4627,11 @@
// window manager can correctly calculate the focus window that can receive
// input keys.
moveHomeStackToFront("startActivityFromRecents: homeVisibleInSplitScreen");
+
+ // Immediately update the minimized docked stack mode, the upcoming animation
+ // for the docked activity (WMS.overridePendingAppTransitionMultiThumbFuture)
+ // will do the animation to the target bounds
+ mWindowManager.checkSplitScreenMinimizedChanged(false /* animate */);
}
}
mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dd2358c..4541acd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1041,7 +1041,9 @@
return;
}
- mStats.updateBluetoothStateLocked(info);
+ synchronized (mStats) {
+ mStats.updateBluetoothStateLocked(info);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 2de84ab..5fd300c 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -279,6 +279,16 @@
}
/**
+ * @return whether the home app is also the active handler of recent tasks.
+ */
+ boolean isRecentsComponentHomeActivity(int userId) {
+ final ComponentName defaultHomeActivity = mService.getPackageManagerInternalLocked()
+ .getDefaultHomeActivity(userId);
+ return defaultHomeActivity != null &&
+ defaultHomeActivity.getPackageName().equals(mRecentsComponent.getPackageName());
+ }
+
+ /**
* @return the recents component.
*/
ComponentName getRecentsComponent() {
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 6dcf041..4b1594c 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -134,6 +134,7 @@
// Fetch all the surface controls and pass them to the client to get the animation
// started
+ mWindowManager.cancelRecentsAnimation();
mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
display.mDisplayId);
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 3bf1cf4..1e071aa 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -124,10 +124,6 @@
updateModeFlags();
}
- boolean isNew() {
- return persistedCreateTime == INVALID_TIME;
- }
-
void grantModes(int modeFlags, UriPermissionOwner owner) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6134d05..af1ab83 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1735,6 +1735,20 @@
return mInjector.getUserManager().getUserIds();
}
+ /**
+ * If {@code userId} is {@link UserHandle#USER_ALL}, then return an array with all running user
+ * IDs. Otherwise return an array whose only element is the given user id.
+ *
+ * It doesn't handle other special user IDs such as {@link UserHandle#USER_CURRENT}.
+ */
+ int[] expandUserId(int userId) {
+ if (userId != UserHandle.USER_ALL) {
+ return new int[] {userId};
+ } else {
+ return getUsers();
+ }
+ }
+
boolean exists(int userId) {
return mInjector.getUserManager().exists(userId);
}
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
index d32db7e..9d34a80 100644
--- a/services/core/java/com/android/server/am/VrController.java
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -24,7 +24,7 @@
import android.util.proto.ProtoUtils;
import com.android.server.LocalServices;
-import com.android.server.am.proto.ProcessesProto.VrControllerProto;
+import com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto.VrControllerProto;
import com.android.server.vr.VrManagerInternal;
/**
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8afa540..8eb8058 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1538,17 +1538,6 @@
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
- // Check if volume update should be send to AVRCP
- if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
- (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.adjustAvrcpAbsoluteVolume(direction);
- }
- }
- }
-
if (isMuteAdjust) {
boolean state;
if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
@@ -1597,8 +1586,20 @@
0);
}
- // Check if volume update should be sent to Hdmi system audio.
int newIndex = mStreamStates[streamType].getIndex(device);
+
+ // Check if volume update should be send to AVRCP
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ synchronized (mA2dpAvrcpLock) {
+ if (mA2dp != null && mAvrcpAbsVolSupported) {
+ mA2dp.setAvrcpAbsoluteVolume(newIndex / 10);
+ }
+ }
+ }
+
+ // Check if volume update should be sent to Hdmi system audio.
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
}
@@ -7038,26 +7039,75 @@
// TODO implement clearing mix attribute matching info in native audio policy
}
- public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
- if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
- + " policy " + pcb.asBinder());
- // error handling
- boolean hasPermissionForPolicy =
+ /**
+ * Checks whether caller has MODIFY_AUDIO_ROUTING permission, and the policy is registered.
+ * @param errorMsg log warning if permission check failed.
+ * @return null if the operation on the audio mixes should be cancelled.
+ */
+ @GuardedBy("mAudioPolicies")
+ private AudioPolicyProxy checkUpdateForPolicy(IAudioPolicyCallback pcb, String errorMsg) {
+ // permission check
+ final boolean hasPermissionForPolicy =
(PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
android.Manifest.permission.MODIFY_AUDIO_ROUTING));
if (!hasPermissionForPolicy) {
- Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
+ Slog.w(TAG, errorMsg + " for pid " +
+ Binder.getCallingPid() + " / uid "
+ Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
- return AudioManager.ERROR;
+ return null;
}
+ // policy registered?
+ final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
+ if (app == null) {
+ Slog.w(TAG, errorMsg + " for pid " +
+ + Binder.getCallingPid() + " / uid "
+ + Binder.getCallingUid() + ", unregistered policy");
+ return null;
+ }
+ return app;
+ }
+ public int addMixForPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb) {
+ if (DEBUG_AP) { Log.d(TAG, "addMixForPolicy for " + pcb.asBinder()
+ + " with config:" + policyConfig); }
synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot add AudioMix in audio policy");
+ if (app == null){
+ return AudioManager.ERROR;
+ }
+ app.addMixes(policyConfig.getMixes());
+ }
+ return AudioManager.SUCCESS;
+ }
+
+ public int removeMixForPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb) {
+ if (DEBUG_AP) { Log.d(TAG, "removeMixForPolicy for " + pcb.asBinder()
+ + " with config:" + policyConfig); }
+ synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot add AudioMix in audio policy");
+ if (app == null) {
+ return AudioManager.ERROR;
+ }
+ app.removeMixes(policyConfig.getMixes());
+ }
+ return AudioManager.SUCCESS;
+ }
+
+ public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
+ if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
+ + " policy " + pcb.asBinder());
+ synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot change audio policy focus properties");
+ if (app == null){
+ return AudioManager.ERROR;
+ }
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
return AudioManager.ERROR;
}
- final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
// is there already one policy managing ducking?
for (AudioPolicyProxy policy : mAudioPolicies.values()) {
@@ -7289,6 +7339,24 @@
Binder.restoreCallingIdentity(identity);
}
+ void addMixes(@NonNull ArrayList<AudioMix> mixes) {
+ // TODO optimize to not have to unregister the mixes already in place
+ synchronized (mMixes) {
+ AudioSystem.registerPolicyMixes(mMixes, false);
+ this.add(mixes);
+ AudioSystem.registerPolicyMixes(mMixes, true);
+ }
+ }
+
+ void removeMixes(@NonNull ArrayList<AudioMix> mixes) {
+ // TODO optimize to not have to unregister the mixes already in place
+ synchronized (mMixes) {
+ AudioSystem.registerPolicyMixes(mMixes, false);
+ this.remove(mixes);
+ AudioSystem.registerPolicyMixes(mMixes, true);
+ }
+ }
+
void connectMixes() {
final long identity = Binder.clearCallingIdentity();
AudioSystem.registerPolicyMixes(mMixes, true);
@@ -7406,7 +7474,8 @@
//======================
// misc
//======================
- private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
+ private final HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
new HashMap<IBinder, AudioPolicyProxy>();
- private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
+ @GuardedBy("mAudioPolicies")
+ private int mAudioPolicyCounter = 0;
}
diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java
index e5d564d..f44afe4 100644
--- a/services/core/java/com/android/server/backup/BackupUtils.java
+++ b/services/core/java/com/android/server/backup/BackupUtils.java
@@ -18,9 +18,12 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.util.Slog;
+import com.android.internal.util.ArrayUtils;
+
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -30,9 +33,10 @@
public class BackupUtils {
private static final String TAG = "BackupUtils";
- private static final boolean DEBUG = false; // STOPSHIP if true
+ private static final boolean DEBUG = false;
- public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
+ public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target,
+ PackageManagerInternal pmi) {
if (target == null) {
return false;
}
@@ -47,48 +51,54 @@
return true;
}
- // Allow unsigned apps, but not signed on one device and unsigned on the other
- // !!! TODO: is this the right policy?
- Signature[] deviceSigs = target.signatures;
- if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
- + " device=" + deviceSigs);
- if ((storedSigHashes == null || storedSigHashes.size() == 0)
- && (deviceSigs == null || deviceSigs.length == 0)) {
- return true;
- }
- if (storedSigHashes == null || deviceSigs == null) {
+ // Don't allow unsigned apps on either end
+ if (ArrayUtils.isEmpty(storedSigHashes)) {
return false;
}
- // !!! TODO: this demands that every stored signature match one
- // that is present on device, and does not demand the converse.
- // Is this this right policy?
- final int nStored = storedSigHashes.size();
- final int nDevice = deviceSigs.length;
-
- // hash each on-device signature
- ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
- for (int i = 0; i < nDevice; i++) {
- deviceHashes.add(hashSignature(deviceSigs[i]));
+ Signature[][] deviceHistorySigs = target.signingCertificateHistory;
+ if (ArrayUtils.isEmpty(deviceHistorySigs)) {
+ Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" +
+ " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
+ return false;
}
- // now ensure that each stored sig (hash) matches an on-device sig (hash)
- for (int n = 0; n < nStored; n++) {
- boolean match = false;
- final byte[] storedHash = storedSigHashes.get(n);
- for (int i = 0; i < nDevice; i++) {
- if (Arrays.equals(storedHash, deviceHashes.get(i))) {
- match = true;
- break;
+ if (DEBUG) {
+ Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
+ + " device=" + deviceHistorySigs);
+ }
+
+ final int nStored = storedSigHashes.size();
+ if (nStored == 1) {
+ // if the app is only signed with one sig, it's possible it has rotated its key
+ // the checks with signing history are delegated to PackageManager
+ // TODO: address the case that app has declared restoreAnyVersion and is restoring
+ // from higher version to lower after having rotated the key (i.e. higher version has
+ // different sig than lower version that we want to restore to)
+ return pmi.isDataRestoreSafe(storedSigHashes.get(0), target.packageName);
+ } else {
+ // the app couldn't have rotated keys, since it was signed with multiple sigs - do
+ // a comprehensive 1-to-1 signatures check
+ // since app hasn't rotated key, we only need to check with deviceHistorySigs[0]
+ ArrayList<byte[]> deviceHashes = hashSignatureArray(deviceHistorySigs[0]);
+ int nDevice = deviceHashes.size();
+
+ // ensure that each stored sig matches an on-device sig
+ for (int i = 0; i < nStored; i++) {
+ boolean match = false;
+ for (int j = 0; j < nDevice; j++) {
+ if (Arrays.equals(storedSigHashes.get(i), deviceHashes.get(j))) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
}
}
- // match is false when no on-device sig matched one of the stored ones
- if (!match) {
- return false;
- }
+ // we have found a match for all stored sigs
+ return true;
}
-
- return true;
}
public static byte[] hashSignature(byte[] signature) {
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 3133a51..ca8823f 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -103,13 +103,15 @@
private static class CameraUsageEvent {
public final int mCameraFacing;
public final String mClientName;
+ public final int mAPILevel;
private boolean mCompleted;
private long mDurationOrStartTimeMs; // Either start time, or duration once completed
- public CameraUsageEvent(int facing, String clientName) {
+ public CameraUsageEvent(int facing, String clientName, int apiLevel) {
mCameraFacing = facing;
mClientName = clientName;
+ mAPILevel = apiLevel;
mDurationOrStartTimeMs = SystemClock.elapsedRealtime();
mCompleted = false;
}
@@ -168,13 +170,13 @@
@Override
public void notifyCameraState(String cameraId, int newCameraState, int facing,
- String clientName) {
+ String clientName, int apiLevel) {
String state = cameraStateToString(newCameraState);
String facingStr = cameraFacingToString(facing);
if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " +
- state + " for client " + clientName);
+ state + " for client " + clientName + " API Level " + apiLevel);
- updateActivityCount(cameraId, newCameraState, facing, clientName);
+ updateActivityCount(cameraId, newCameraState, facing, clientName, apiLevel);
}
};
@@ -293,6 +295,7 @@
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(subtype)
.setLatency(e.getDuration())
+ .addTaggedData(MetricsEvent.FIELD_CAMERA_API_LEVEL, e.mAPILevel)
.setPackageName(e.mClientName);
mLogger.write(l);
}
@@ -368,7 +371,8 @@
return true;
}
- private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) {
+ private void updateActivityCount(String cameraId, int newCameraState, int facing,
+ String clientName, int apiLevel) {
synchronized(mLock) {
// Update active camera list and notify NFC if necessary
boolean wasEmpty = mActiveCameraUsage.isEmpty();
@@ -376,7 +380,7 @@
case ICameraServiceProxy.CAMERA_STATE_OPEN:
break;
case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
- CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName);
+ CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel);
CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent);
if (oldEvent != null) {
Slog.w(TAG, "Camera " + cameraId + " was already marked as active");
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 0c9d70a..776e93d 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -16,6 +16,7 @@
package com.android.server.clipboard;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -24,9 +25,9 @@
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ContentProvider;
+import android.content.Context;
import android.content.IClipboard;
import android.content.IOnPrimaryClipChangedListener;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -37,7 +38,6 @@
import android.os.IBinder;
import android.os.IUserManager;
import android.os.Parcel;
-import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -49,14 +49,10 @@
import com.android.server.SystemService;
-import java.util.HashSet;
-import java.util.List;
-
-import java.lang.Thread;
-import java.lang.Runnable;
-import java.lang.InterruptedException;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.util.HashSet;
+import java.util.List;
// The following class is Android Emulator specific. It is used to read and
// write contents of the host system's clipboard.
@@ -182,7 +178,8 @@
new String[]{"text/plain"},
new ClipData.Item(contents));
synchronized(mClipboards) {
- setPrimaryClipInternal(getClipboard(0), clip);
+ setPrimaryClipInternal(getClipboard(0), clip,
+ android.os.Process.SYSTEM_UID);
}
}
});
@@ -218,7 +215,10 @@
final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
= new RemoteCallbackList<IOnPrimaryClipChangedListener>();
+ /** Current primary clip. */
ClipData primaryClip;
+ /** UID that set {@link #primaryClip}. */
+ int primaryClipUid = android.os.Process.NOBODY_UID;
final HashSet<String> activePermissionOwners
= new HashSet<String>();
@@ -246,58 +246,28 @@
@Override
public void setPrimaryClip(ClipData clip, String callingPackage) {
synchronized (this) {
- if (clip != null && clip.getItemCount() <= 0) {
+ if (clip == null || clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
- if (clip.getItemAt(0).getText() != null &&
- mHostClipboardMonitor != null) {
- mHostClipboardMonitor.setHostClipboard(
- clip.getItemAt(0).getText().toString());
- }
final int callingUid = Binder.getCallingUid();
if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
callingUid)) {
return;
}
checkDataOwnerLocked(clip, callingUid);
- final int userId = UserHandle.getUserId(callingUid);
- PerUserClipboard clipboard = getClipboard(userId);
- revokeUris(clipboard);
- setPrimaryClipInternal(clipboard, clip);
- List<UserInfo> related = getRelatedProfiles(userId);
- if (related != null) {
- int size = related.size();
- if (size > 1) { // Related profiles list include the current profile.
- boolean canCopy = false;
- try {
- canCopy = !mUm.getUserRestrictions(userId).getBoolean(
- UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote Exception calling UserManager: " + e);
- }
- // Copy clip data to related users if allowed. If disallowed, then remove
- // primary clip in related users to prevent pasting stale content.
- if (!canCopy) {
- clip = null;
- } else {
- // We want to fix the uris of the related user's clip without changing the
- // uris of the current user's clip.
- // So, copy the ClipData, and then copy all the items, so that nothing
- // is shared in memmory.
- clip = new ClipData(clip);
- for (int i = clip.getItemCount() - 1; i >= 0; i--) {
- clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
- }
- clip.fixUrisLight(userId);
- }
- for (int i = 0; i < size; i++) {
- int id = related.get(i).id;
- if (id != userId) {
- setPrimaryClipInternal(getClipboard(id), clip);
- }
- }
- }
+ setPrimaryClipInternal(clip, callingUid);
+ }
+ }
+
+ @Override
+ public void clearPrimaryClip(String callingPackage) {
+ synchronized (this) {
+ final int callingUid = Binder.getCallingUid();
+ if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
+ callingUid)) {
+ return;
}
+ setPrimaryClipInternal(null, callingUid);
}
}
@@ -398,13 +368,75 @@
return related;
}
- void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) {
+ void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
+ // Push clipboard to host, if any
+ if (mHostClipboardMonitor != null) {
+ if (clip == null) {
+ // Someone really wants the clipboard cleared, so push empty
+ mHostClipboardMonitor.setHostClipboard("");
+ } else if (clip.getItemCount() > 0) {
+ final CharSequence text = clip.getItemAt(0).getText();
+ if (text != null) {
+ mHostClipboardMonitor.setHostClipboard(text.toString());
+ }
+ }
+ }
+
+ // Update this user
+ final int userId = UserHandle.getUserId(callingUid);
+ setPrimaryClipInternal(getClipboard(userId), clip, callingUid);
+
+ // Update related users
+ List<UserInfo> related = getRelatedProfiles(userId);
+ if (related != null) {
+ int size = related.size();
+ if (size > 1) { // Related profiles list include the current profile.
+ boolean canCopy = false;
+ try {
+ canCopy = !mUm.getUserRestrictions(userId).getBoolean(
+ UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote Exception calling UserManager: " + e);
+ }
+ // Copy clip data to related users if allowed. If disallowed, then remove
+ // primary clip in related users to prevent pasting stale content.
+ if (!canCopy) {
+ clip = null;
+ } else {
+ // We want to fix the uris of the related user's clip without changing the
+ // uris of the current user's clip.
+ // So, copy the ClipData, and then copy all the items, so that nothing
+ // is shared in memmory.
+ clip = new ClipData(clip);
+ for (int i = clip.getItemCount() - 1; i >= 0; i--) {
+ clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
+ }
+ clip.fixUrisLight(userId);
+ }
+ for (int i = 0; i < size; i++) {
+ int id = related.get(i).id;
+ if (id != userId) {
+ setPrimaryClipInternal(getClipboard(id), clip, callingUid);
+ }
+ }
+ }
+ }
+ }
+
+ void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
+ int callingUid) {
+ revokeUris(clipboard);
clipboard.activePermissionOwners.clear();
if (clip == null && clipboard.primaryClip == null) {
return;
}
clipboard.primaryClip = clip;
if (clip != null) {
+ clipboard.primaryClipUid = callingUid;
+ } else {
+ clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
+ }
+ if (clip != null) {
final ClipDescription description = clip.getDescription();
if (description != null) {
description.setTimestamp(System.currentTimeMillis());
@@ -479,12 +511,12 @@
}
}
- private final void grantUriLocked(Uri uri, String pkg, int userId) {
+ private final void grantUriLocked(Uri uri, int primaryClipUid, String pkg, int userId) {
long ident = Binder.clearCallingIdentity();
try {
int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId);
uri = ContentProvider.getUriWithoutUserId(uri);
- mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
+ mAm.grantUriPermissionFromOwner(mPermissionOwner, primaryClipUid, pkg,
uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId);
} catch (RemoteException e) {
} finally {
@@ -492,13 +524,14 @@
}
}
- private final void grantItemLocked(ClipData.Item item, String pkg, int userId) {
+ private final void grantItemLocked(ClipData.Item item, int primaryClipUid, String pkg,
+ int userId) {
if (item.getUri() != null) {
- grantUriLocked(item.getUri(), pkg, userId);
+ grantUriLocked(item.getUri(), primaryClipUid, pkg, userId);
}
Intent intent = item.getIntent();
if (intent != null && intent.getData() != null) {
- grantUriLocked(intent.getData(), pkg, userId);
+ grantUriLocked(intent.getData(), primaryClipUid, pkg, userId);
}
}
@@ -524,7 +557,8 @@
if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
final int N = clipboard.primaryClip.getItemCount();
for (int i=0; i<N; i++) {
- grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid));
+ grantItemLocked(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid, pkg,
+ UserHandle.getUserId(uid));
}
clipboard.activePermissionOwners.add(pkg);
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bb46d5e..c9bdcf1 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -57,6 +57,7 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
+import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
@@ -105,6 +106,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -113,6 +115,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
@@ -131,6 +134,24 @@
// the device idle whitelist during service launch and VPN bootstrap.
private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000;
+ // Settings for how much of the address space should be routed so that Vpn considers
+ // "most" of the address space is routed. This is used to determine whether this Vpn
+ // should be marked with the INTERNET capability.
+ private static final long MOST_IPV4_ADDRESSES_COUNT;
+ private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
+ static {
+ // 85% of the address space must be routed for Vpn to consider this VPN to provide
+ // INTERNET access.
+ final int howManyPercentIsMost = 85;
+
+ final long twoPower32 = 1L << 32;
+ MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
+ final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
+ MOST_IPV6_ADDRESSES_COUNT = twoPower128
+ .multiply(BigInteger.valueOf(howManyPercentIsMost))
+ .divide(BigInteger.valueOf(100));
+ }
+
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
@@ -830,10 +851,39 @@
return lp;
}
+ /**
+ * Analyzes the passed LinkedProperties to figure out whether it routes to most of the IP space.
+ *
+ * This returns true if the passed LinkedProperties contains routes to either most of the IPv4
+ * space or to most of the IPv6 address space, where "most" is defined by the value of the
+ * MOST_IPV{4,6}_ADDRESSES_COUNT constants : if more than this number of addresses are matched
+ * by any of the routes, then it's decided that most of the space is routed.
+ * @hide
+ */
+ @VisibleForTesting
+ static boolean providesRoutesToMostDestinations(LinkProperties lp) {
+ final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
+ TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
+ TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
+ for (final RouteInfo route : lp.getAllRoutes()) {
+ IpPrefix destination = route.getDestination();
+ if (destination.isIPv4()) {
+ ipv4Prefixes.add(destination);
+ } else {
+ ipv6Prefixes.add(destination);
+ }
+ }
+ if (NetworkUtils.routedIPv4AddressCount(ipv4Prefixes) > MOST_IPV4_ADDRESSES_COUNT) {
+ return true;
+ }
+ return NetworkUtils.routedIPv6AddressCount(ipv6Prefixes)
+ .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
+ }
+
private void agentConnect() {
LinkProperties lp = makeLinkProperties();
- if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) {
+ if (providesRoutesToMostDestinations(lp)) {
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
} else {
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index e2aee88..cb53521 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -67,7 +67,7 @@
private static final int MSG_UPDATE_AMBIENT_LUX = 1;
private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
- private static final int MSG_RESET_SHORT_TERM_MODEL = 3;
+ private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
// Length of the ambient light horizon used to calculate the long term estimate of ambient
// light.
@@ -158,9 +158,6 @@
// A ring buffer containing all of the recent ambient light sensor readings.
private AmbientLightRingBuffer mAmbientLightRingBuffer;
- // A ring buffer containing the light sensor readings for the initial horizon period.
- private AmbientLightRingBuffer mInitialHorizonAmbientLightRingBuffer;
-
// The handler
private AutomaticBrightnessHandler mHandler;
@@ -194,6 +191,14 @@
private int mBrightnessAdjustmentSampleOldBrightness;
private float mBrightnessAdjustmentSampleOldGamma;
+ // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
+ // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
+ // The anchor determines what were the light levels when the user has set her preference, and
+ // we use a relative threshold to determine when to revert to the OEM curve.
+ private boolean mShortTermModelValid;
+ private float mShortTermModelAnchor;
+ private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
+
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, BrightnessMappingStrategy mapper, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
@@ -218,12 +223,12 @@
mWeightingIntercept = ambientLightHorizon;
mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
mDynamicHysteresis = dynamicHysteresis;
+ mShortTermModelValid = true;
+ mShortTermModelAnchor = -1;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
- mInitialHorizonAmbientLightRingBuffer =
- new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -284,13 +289,13 @@
final int oldPolicy = mDisplayPolicy;
mDisplayPolicy = policy;
if (DEBUG) {
- Slog.d(TAG, "Display policy transitioning from " + mDisplayPolicy + " to " + policy);
+ Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
}
if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
- mHandler.sendEmptyMessageDelayed(MSG_RESET_SHORT_TERM_MODEL,
+ mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
SHORT_TERM_MODEL_TIMEOUT_MILLIS);
} else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
- mHandler.removeMessages(MSG_RESET_SHORT_TERM_MODEL);
+ mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
}
return true;
}
@@ -308,6 +313,11 @@
return false;
}
mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
+ mShortTermModelValid = true;
+ mShortTermModelAnchor = mAmbientLux;
+ if (DEBUG) {
+ Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
+ }
// Reset the brightness adjustment so that the next time we're queried for brightness we
// return the value the user set.
mScreenAutoBrightnessAdjustment = 0.0f;
@@ -316,6 +326,15 @@
private void resetShortTermModel() {
mBrightnessMapper.clearUserDataPoints();
+ mShortTermModelValid = true;
+ mShortTermModelAnchor = -1;
+ }
+
+ private void invalidateShortTermModel() {
+ if (DEBUG) {
+ Slog.d(TAG, "ShortTermModel: invalidate user data");
+ }
+ mShortTermModelValid = false;
}
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
@@ -345,14 +364,13 @@
pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
pw.println(" mRecentLightSamples=" + mRecentLightSamples);
pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
- pw.println(" mInitialHorizonAmbientLightRingBuffer=" +
- mInitialHorizonAmbientLightRingBuffer);
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
pw.println(" mScreenAutoBrightnessAdjustmentMaxGamma="
+ mScreenAutoBrightnessAdjustmentMaxGamma);
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
pw.println(" mDisplayPolicy=" + mDisplayPolicy);
+ pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
pw.println();
mBrightnessMapper.dump(pw);
@@ -368,17 +386,14 @@
mCurrentLightSensorRate * 1000, mHandler);
return true;
}
- } else {
- if (mLightSensorEnabled) {
- mLightSensorEnabled = false;
- mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
- mRecentLightSamples = 0;
- mAmbientLightRingBuffer.clear();
- mInitialHorizonAmbientLightRingBuffer.clear();
- mCurrentLightSensorRate = -1;
- mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
- mSensorManager.unregisterListener(mLightSensorListener);
- }
+ } else if (mLightSensorEnabled) {
+ mLightSensorEnabled = false;
+ mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
+ mRecentLightSamples = 0;
+ mAmbientLightRingBuffer.clear();
+ mCurrentLightSensorRate = -1;
+ mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
+ mSensorManager.unregisterListener(mLightSensorListener);
}
return false;
}
@@ -397,11 +412,6 @@
private void applyLightSensorMeasurement(long time, float lux) {
mRecentLightSamples++;
- // Store all of the light measurements for the intial horizon period. This is to help
- // diagnose dim wake ups and slow responses in b/27951906.
- if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
- mInitialHorizonAmbientLightRingBuffer.push(time, lux);
- }
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
@@ -414,8 +424,9 @@
// if the light sensor rate changed, update the sensor listener
if (lightSensorRate != mCurrentLightSensorRate) {
if (DEBUG) {
- Slog.d(TAG, "adjustLightSensorRate: previousRate=" + mCurrentLightSensorRate
- + ", currentRate=" + lightSensorRate);
+ Slog.d(TAG, "adjustLightSensorRate: " +
+ "previousRate=" + mCurrentLightSensorRate + ", " +
+ "currentRate=" + lightSensorRate);
}
mCurrentLightSensorRate = lightSensorRate;
mSensorManager.unregisterListener(mLightSensorListener);
@@ -437,12 +448,29 @@
Slog.d(TAG, "setAmbientLux(" + lux + ")");
}
if (lux < 0) {
- Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0.");
+ Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
lux = 0;
}
mAmbientLux = lux;
mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
+
+ // If the short term model was invalidated and the change is drastic enough, reset it.
+ if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
+ final float minAmbientLux =
+ mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
+ final float maxAmbientLux =
+ mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
+ if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
+ Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
+ minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
+ mShortTermModelValid = true;
+ } else {
+ Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux +
+ "(" + minAmbientLux + ", " + maxAmbientLux + ")");
+ resetShortTermModel();
+ }
+ }
}
private float calculateAmbientLux(long now, long horizon) {
@@ -467,9 +495,8 @@
}
if (DEBUG) {
Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=("
- + mAmbientLightRingBuffer.getTime(endIndex) + ", "
- + mAmbientLightRingBuffer.getLux(endIndex)
- + ")");
+ + mAmbientLightRingBuffer.getTime(endIndex) + ", "
+ + mAmbientLightRingBuffer.getLux(endIndex) + ")");
}
float sum = 0;
float totalWeight = 0;
@@ -485,17 +512,18 @@
float weight = calculateWeight(startTime, endTime);
float lux = mAmbientLightRingBuffer.getLux(i);
if (DEBUG) {
- Slog.d(TAG, "calculateAmbientLux: [" +
- (startTime) + ", " +
- (endTime) + "]: lux=" + lux + ", weight=" + weight);
+ Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
+ "lux=" + lux + ", " +
+ "weight=" + weight);
}
totalWeight += weight;
- sum += mAmbientLightRingBuffer.getLux(i) * weight;
+ sum += lux * weight;
endTime = startTime;
}
if (DEBUG) {
- Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight +
- ", newAmbientLux=" + (sum / totalWeight));
+ Slog.d(TAG, "calculateAmbientLux: " +
+ "totalWeight=" + totalWeight + ", " +
+ "newAmbientLux=" + (sum / totalWeight));
}
return sum / totalWeight;
}
@@ -548,9 +576,9 @@
mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
if (time < timeWhenSensorWarmedUp) {
if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "
- + "time=" + time
- + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
+ Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " +
+ "time=" + time + ", " +
+ "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
}
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
timeWhenSensorWarmedUp);
@@ -559,9 +587,9 @@
setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
mAmbientLuxValid = true;
if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Initializing: "
- + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
- + ", mAmbientLux=" + mAmbientLux);
+ Slog.d(TAG, "updateAmbientLux: Initializing: " +
+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
+ "mAmbientLux=" + mAmbientLux);
}
updateAutoBrightness(true);
}
@@ -579,17 +607,20 @@
float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
- if (slowAmbientLux >= mBrighteningLuxThreshold &&
- fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
- || slowAmbientLux <= mDarkeningLuxThreshold
- && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
+ if ((slowAmbientLux >= mBrighteningLuxThreshold &&
+ fastAmbientLux >= mBrighteningLuxThreshold &&
+ nextBrightenTransition <= time)
+ ||
+ (slowAmbientLux <= mDarkeningLuxThreshold &&
+ fastAmbientLux <= mDarkeningLuxThreshold &&
+ nextDarkenTransition <= time)) {
setAmbientLux(fastAmbientLux);
if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: "
- + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
- + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
- + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
- + ", mAmbientLux=" + mAmbientLux);
+ Slog.d(TAG, "updateAmbientLux: " +
+ ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " +
+ "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + ", " +
+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
+ "mAmbientLux=" + mAmbientLux);
}
updateAutoBrightness(true);
nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
@@ -605,8 +636,8 @@
nextTransitionTime =
nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
- + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
+ Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
+ nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
}
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
}
@@ -633,8 +664,10 @@
final float in = value;
value = MathUtils.pow(value, gamma);
if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
- + ", in=" + in + ", out=" + value);
+ Slog.d(TAG, "updateAutoBrightness: " +
+ "gamma=" + gamma + ", " +
+ "in=" + in + ", " +
+ "out=" + value);
}
}
@@ -642,9 +675,9 @@
clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
- + mScreenAutoBrightness + ", newScreenAutoBrightness="
- + newScreenAutoBrightness);
+ Slog.d(TAG, "updateAutoBrightness: " +
+ "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
+ "newScreenAutoBrightness=" + newScreenAutoBrightness);
}
mScreenAutoBrightness = newScreenAutoBrightness;
@@ -687,12 +720,12 @@
mBrightnessAdjustmentSamplePending = false;
if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
if (DEBUG) {
- Slog.d(TAG, "Auto-brightness adjustment changed by user: "
- + "adj=" + mScreenAutoBrightnessAdjustment
- + ", lux=" + mAmbientLux
- + ", brightness=" + mScreenAutoBrightness
- + ", gamma=" + mLastScreenAutoBrightnessGamma
- + ", ring=" + mAmbientLightRingBuffer);
+ Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
+ "adj=" + mScreenAutoBrightnessAdjustment + ", " +
+ "lux=" + mAmbientLux + ", " +
+ "brightness=" + mScreenAutoBrightness + ", " +
+ "gamma=" + mLastScreenAutoBrightnessGamma + ", " +
+ "ring=" + mAmbientLightRingBuffer);
}
EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
@@ -724,8 +757,8 @@
collectBrightnessAdjustmentSample();
break;
- case MSG_RESET_SHORT_TERM_MODEL:
- resetShortTermModel();
+ case MSG_INVALIDATE_SHORT_TERM_MODEL:
+ invalidateShortTermModel();
break;
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 524de91..df60c66 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -70,6 +70,8 @@
import java.util.ArrayList;
import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
@@ -225,15 +227,24 @@
* @return List of recent {@link BrightnessChangeEvent}s
*/
public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId, boolean includePackage) {
- // TODO include apps from any managed profiles in the brightness information.
BrightnessChangeEvent[] events;
synchronized (mEventsLock) {
events = mEvents.toArray();
}
+ int[] profiles = mInjector.getProfileIds(mUserManager, userId);
+ Map<Integer, Boolean> toRedact = new HashMap<>();
+ for (int i = 0; i < profiles.length; ++i) {
+ int profileId = profiles[i];
+ // Include slider interactions when a managed profile app is in the
+ // foreground but always redact the package name.
+ boolean redact = (!includePackage) || profileId != userId;
+ toRedact.put(profiles[i], redact);
+ }
ArrayList<BrightnessChangeEvent> out = new ArrayList<>(events.length);
for (int i = 0; i < events.length; ++i) {
- if (events[i].userId == userId) {
- if (includePackage) {
+ Boolean redact = toRedact.get(events[i].userId);
+ if (redact != null) {
+ if (!redact) {
out.add(events[i]);
} else {
BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]),
@@ -817,6 +828,14 @@
return userManager.getUserHandle(userSerialNumber);
}
+ public int[] getProfileIds(UserManager userManager, int userId) {
+ if (userManager != null) {
+ return userManager.getProfileIds(userId, false);
+ } else {
+ return new int[]{userId};
+ }
+ }
+
public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
return ActivityManager.getService().getFocusedStackInfo();
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 55d5785..0e7e540 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -87,6 +87,7 @@
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
+import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob;
import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
@@ -2937,6 +2938,23 @@
synchronized (mLock) {
mConstants.dump(pw);
pw.println();
+
+ pw.println(" Heartbeat:");
+ pw.print(" Current: "); pw.println(mHeartbeat);
+ pw.println(" Next");
+ pw.print(" ACTIVE: "); pw.println(mNextBucketHeartbeat[0]);
+ pw.print(" WORKING: "); pw.println(mNextBucketHeartbeat[1]);
+ pw.print(" FREQUENT: "); pw.println(mNextBucketHeartbeat[2]);
+ pw.print(" RARE: "); pw.println(mNextBucketHeartbeat[3]);
+ pw.print(" Last heartbeat: ");
+ TimeUtils.formatDuration(mLastHeartbeatTime, nowElapsed, pw);
+ pw.println();
+ pw.print(" Next heartbeat: ");
+ TimeUtils.formatDuration(mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME,
+ nowElapsed, pw);
+ pw.println();
+ pw.println();
+
pw.println("Started users: " + Arrays.toString(mStartedUsers));
pw.print("Registered ");
pw.print(mJobs.size());
@@ -2954,6 +2972,10 @@
}
job.dump(pw, " ", true, nowElapsed);
+ pw.print(" Last run heartbeat: ");
+ pw.print(heartbeatWhenJobsLastRun(job));
+ pw.println();
+
pw.print(" Ready: ");
pw.print(isReadyToBeExecutedLocked(job));
pw.print(" (job=");
@@ -3096,6 +3118,16 @@
synchronized (mLock) {
mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS);
+ proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat);
+ proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]);
+ proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]);
+ proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[2]);
+ proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[3]);
+ proto.write(JobSchedulerServiceDumpProto.LAST_HEARTBEAT_TIME_MILLIS,
+ mLastHeartbeatTime - nowUptime);
+ proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS,
+ mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime);
+
for (int u : mStartedUsers) {
proto.write(JobSchedulerServiceDumpProto.STARTED_USERS, u);
}
@@ -3134,6 +3166,7 @@
}
proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT,
componentPresent);
+ proto.write(RegisteredJob.LAST_RUN_HEARTBEAT, heartbeatWhenJobsLastRun(job));
proto.end(rjToken);
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5267f54..729ac0c 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -459,7 +459,7 @@
private final PendingIntent mWakeupIntent;
private final PendingIntent mTimeoutIntent;
- private final IAppOpsService mAppOpsService;
+ private final AppOpsManager mAppOps;
private final IBatteryStats mBatteryStats;
// Current list of underlying location clients.
@@ -782,8 +782,7 @@
mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
// App ops service to keep track of who is accessing the GPS
- mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
- Context.APP_OPS_SERVICE));
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
// Battery statistics service to be notified when GPS turns on or off
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
@@ -1490,26 +1489,16 @@
if (newChains != null) {
for (int i = 0; i < newChains.size(); ++i) {
final WorkChain newChain = newChains.get(i);
- try {
- mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_GPS, newChain.getAttributionUid(),
- newChain.getAttributionTag());
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException", e);
- }
+ mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(),
+ newChain.getAttributionTag());
}
}
if (goneChains != null) {
for (int i = 0; i < goneChains.size(); i++) {
final WorkChain goneChain = goneChains.get(i);
- try {
- mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
- goneChain.getAttributionTag());
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException", e);
- }
+ mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
+ goneChain.getAttributionTag());
}
}
@@ -1525,24 +1514,15 @@
// Update sources that were not previously tracked.
if (newWork != null) {
for (int i = 0; i < newWork.size(); i++) {
- try {
- mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_GPS, newWork.get(i), newWork.getName(i));
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException", e);
- }
+ mAppOps.startOpNoThrow(AppOpsManager.OP_GPS,
+ newWork.get(i), newWork.getName(i));
}
}
// Update sources that are no longer tracked.
if (goneWork != null) {
for (int i = 0; i < goneWork.size(); i++) {
- try {
- mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException", e);
- }
+ mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9e00819..a572cdf 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1983,6 +1983,14 @@
}
@Override
+ public void initRecoveryServiceWithSigFile(@NonNull String rootCertificateAlias,
+ @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile)
+ throws RemoteException {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(rootCertificateAlias,
+ recoveryServiceCertFile, recoveryServiceSigFile);
+ }
+
+ @Override
public KeyChainSnapshot getKeyChainSnapshot() throws RemoteException {
return mRecoverableKeyStoreManager.getKeyChainSnapshot();
}
@@ -2079,6 +2087,11 @@
}
@Override
+ public String importKey(@NonNull String alias, byte[] keyBytes) throws RemoteException {
+ return mRecoverableKeyStoreManager.importKey(alias, keyBytes);
+ }
+
+ @Override
public String getKey(@NonNull String alias) throws RemoteException {
return mRecoverableKeyStoreManager.getKey(alias);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
index 2fe3f4e..7ebe8bf 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
@@ -16,6 +16,8 @@
package com.android.server.locksettings.recoverablekeystore;
+import android.annotation.NonNull;
+
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import java.security.InvalidKeyException;
@@ -25,20 +27,24 @@
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+// TODO: Rename RecoverableKeyGenerator to RecoverableKeyManager as it can import a key too now
/**
- * Generates keys and stores them both in AndroidKeyStore and on disk, in wrapped form.
+ * Generates/imports keys and stores them both in AndroidKeyStore and on disk, in wrapped form.
*
- * <p>Generates 256-bit AES keys, which can be used for encrypt / decrypt with AES/GCM/NoPadding.
+ * <p>Generates/imports 256-bit AES keys, which can be used for encrypt and decrypt with AES-GCM.
* They are synced to disk wrapped by a platform key. This allows them to be exported to a remote
* service.
*
* @hide
*/
public class RecoverableKeyGenerator {
+
private static final int RESULT_CANNOT_INSERT_ROW = -1;
- private static final String KEY_GENERATOR_ALGORITHM = "AES";
- private static final int KEY_SIZE_BITS = 256;
+ private static final String SECRET_KEY_ALGORITHM = "AES";
+
+ static final int KEY_SIZE_BITS = 256;
/**
* A new {@link RecoverableKeyGenerator} instance.
@@ -52,7 +58,7 @@
throws NoSuchAlgorithmException {
// NB: This cannot use AndroidKeyStore as the provider, as we need access to the raw key
// material, so that it can be synced to disk in encrypted form.
- KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(SECRET_KEY_ALGORITHM);
return new RecoverableKeyGenerator(keyGenerator, database);
}
@@ -102,4 +108,41 @@
mDatabase.setShouldCreateSnapshot(userId, uid, true);
return key.getEncoded();
}
+
+ /**
+ * Imports an AES key with the given alias.
+ *
+ * <p>Stores in the AndroidKeyStore, as well as persisting in wrapped form to disk. It is
+ * persisted to disk so that it can be synced remotely, and then recovered on another device.
+ * The generated key allows encrypt/decrypt only using AES/GCM/NoPadding.
+ *
+ * @param platformKey The user's platform key, with which to wrap the generated key.
+ * @param userId The user ID of the profile to which the calling app belongs.
+ * @param uid The uid of the application that will own the key.
+ * @param alias The alias by which the key will be known in the recoverable key store.
+ * @param keyBytes The raw bytes of the AES key to be imported.
+ * @throws RecoverableKeyStorageException if there is some error persisting the key either to
+ * the database.
+ * @throws KeyStoreException if there is a KeyStore error wrapping the generated key.
+ * @throws InvalidKeyException if the platform key cannot be used to wrap keys.
+ *
+ * @hide
+ */
+ public void importKey(
+ @NonNull PlatformEncryptionKey platformKey, int userId, int uid, @NonNull String alias,
+ @NonNull byte[] keyBytes)
+ throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
+ SecretKey key = new SecretKeySpec(keyBytes, SECRET_KEY_ALGORITHM);
+
+ WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key);
+ long result = mDatabase.insertKey(userId, uid, alias, wrappedKey);
+
+ if (result == RESULT_CANNOT_INSERT_ROW) {
+ throw new RecoverableKeyStorageException(
+ String.format(
+ Locale.US, "Failed writing (%d, %s) to database.", uid, alias));
+ }
+
+ mDatabase.setShouldCreateSnapshot(userId, uid, true);
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 22e99c4..20f3403 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -16,12 +16,14 @@
package com.android.server.locksettings.recoverablekeystore;
-import static android.security.keystore.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT;
-import static android.security.keystore.RecoveryController.ERROR_DECRYPTION_FAILED;
-import static android.security.keystore.RecoveryController.ERROR_INSECURE_USER;
-import static android.security.keystore.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
-import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
-import static android.security.keystore.RecoveryController.ERROR_SESSION_EXPIRED;
+import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT;
+import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED;
+import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER;
+import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
+import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
+import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
+import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
+import static android.security.keystore.recovery.RecoveryController.ERROR_SESSION_EXPIRED;
import android.Manifest;
import android.annotation.NonNull;
@@ -42,6 +44,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
+import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils;
+import com.android.server.locksettings.recoverablekeystore.certificate.SigXml;
import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException;
import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException;
@@ -58,10 +62,8 @@
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertPath;
-import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
@@ -160,6 +162,9 @@
}
}
+ /**
+ * @deprecated Use {@link #initRecoveryServiceWithSigFile(String, byte[], byte[])} instead.
+ */
public void initRecoveryService(
@NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile)
throws RemoteException {
@@ -167,8 +172,6 @@
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
- // TODO: Check the public-key signature on the whole file before parsing it
-
CertXml certXml;
try {
certXml = CertXml.parse(recoveryServiceCertFile);
@@ -204,7 +207,7 @@
} catch (CertValidationException e) {
Log.e(TAG, "Invalid endpoint cert", e);
throw new ServiceSpecificException(
- ERROR_BAD_CERTIFICATE_FORMAT, "Failed to validate certificate.");
+ ERROR_INVALID_CERTIFICATE, "Failed to validate certificate.");
}
try {
Log.d(TAG, "Saving the randomly chosen endpoint certificate to database");
@@ -219,6 +222,50 @@
}
}
+ /**
+ * Initializes the recovery service with the two files {@code recoveryServiceCertFile} and
+ * {@code recoveryServiceSigFile}.
+ *
+ * @param rootCertificateAlias the alias for the root certificate that is used for validating
+ * the recovery service certificates.
+ * @param recoveryServiceCertFile the content of the XML file containing a list of certificates
+ * for the recovery service.
+ * @param recoveryServiceSigFile the content of the XML file containing the public-key signature
+ * over the entire content of {@code recoveryServiceCertFile}.
+ */
+ public void initRecoveryServiceWithSigFile(
+ @NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile,
+ @NonNull byte[] recoveryServiceSigFile)
+ throws RemoteException {
+ if (recoveryServiceCertFile == null || recoveryServiceSigFile == null) {
+ Log.d(TAG, "The given cert or sig file is null");
+ throw new ServiceSpecificException(
+ ERROR_BAD_CERTIFICATE_FORMAT, "The given cert or sig file is null.");
+ }
+
+ SigXml sigXml;
+ try {
+ sigXml = SigXml.parse(recoveryServiceSigFile);
+ } catch (CertParsingException e) {
+ Log.d(TAG, "Failed to parse the sig file: " + HexDump.toHexString(
+ recoveryServiceSigFile));
+ throw new ServiceSpecificException(
+ ERROR_BAD_CERTIFICATE_FORMAT, "Failed to parse the sig file.");
+ }
+
+ try {
+ sigXml.verifyFileSignature(TrustedRootCert.TRUSTED_ROOT_CERT, recoveryServiceCertFile);
+ } catch (CertValidationException e) {
+ Log.d(TAG, "The signature over the cert file is invalid."
+ + " Cert: " + HexDump.toHexString(recoveryServiceCertFile)
+ + " Sig: " + HexDump.toHexString(recoveryServiceSigFile));
+ throw new ServiceSpecificException(
+ ERROR_INVALID_CERTIFICATE, "The signature over the cert file is invalid.");
+ }
+
+ initRecoveryService(rootCertificateAlias, recoveryServiceCertFile);
+ }
+
private PublicKey parseEcPublicKey(@NonNull byte[] bytes) throws ServiceSpecificException {
try {
KeyFactory kf = KeyFactory.getInstance("EC");
@@ -392,7 +439,7 @@
// verifierPublicKey; otherwise, the user secret may be decrypted by a key that is not owned
// by the original recovery service.
if (!publicKeysMatch(publicKey, vaultParams)) {
- throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT,
+ throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE,
"The public keys given in verifierPublicKey and vaultParams do not match.");
}
@@ -447,12 +494,14 @@
"Failed decode the certificate path");
}
- // TODO: Validate the cert path according to the root of trust
-
- if (certPath.getCertificates().isEmpty()) {
- throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT,
- "The given CertPath is empty");
+ try {
+ CertUtils.validateCertPath(TrustedRootCert.TRUSTED_ROOT_CERT, certPath);
+ } catch (CertValidationException e) {
+ Log.e(TAG, "Failed to validate the given cert path", e);
+ // TODO: Change this to ERROR_INVALID_CERTIFICATE once ag/3666620 is submitted
+ throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT, e.getMessage());
}
+
byte[] verifierPublicKey = certPath.getCertificates().get(0).getPublicKey().getEncoded();
if (verifierPublicKey == null) {
Log.e(TAG, "Failed to encode verifierPublicKey");
@@ -507,6 +556,7 @@
*
* <p>TODO: Once AndroidKeyStore has added move api, do not return raw bytes.
*
+ * @deprecated
* @hide
*/
public byte[] generateAndStoreKey(@NonNull String alias) throws RemoteException {
@@ -583,6 +633,57 @@
}
/**
+ * Imports a 256-bit AES-GCM key named {@code alias}. The key is stored in system service
+ * keystore namespace.
+ *
+ * @param alias the alias provided by caller as a reference to the key.
+ * @param keyBytes the raw bytes of the 256-bit AES key.
+ * @return grant alias, which caller can use to access the key.
+ * @throws RemoteException if the given key is invalid or some internal errors occur.
+ *
+ * @hide
+ */
+ public String importKey(@NonNull String alias, @NonNull byte[] keyBytes)
+ throws RemoteException {
+ if (keyBytes == null ||
+ keyBytes.length != RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE) {
+ Log.e(TAG, "The given key for import doesn't have the required length "
+ + RecoverableKeyGenerator.KEY_SIZE_BITS);
+ throw new ServiceSpecificException(ERROR_INVALID_KEY_FORMAT,
+ "The given key does not contain " + RecoverableKeyGenerator.KEY_SIZE_BITS
+ + " bits.");
+ }
+
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+
+ // TODO: Refactor RecoverableKeyGenerator to wrap the PlatformKey logic
+
+ PlatformEncryptionKey encryptionKey;
+ try {
+ encryptionKey = mPlatformKeyManager.getEncryptKey(userId);
+ } catch (NoSuchAlgorithmException e) {
+ // Impossible: all algorithms must be supported by AOSP
+ throw new RuntimeException(e);
+ } catch (KeyStoreException | UnrecoverableKeyException e) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ } catch (InsecureUserException e) {
+ throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
+ }
+
+ try {
+ // Wrap the key by the platform key and store the wrapped key locally
+ mRecoverableKeyGenerator.importKey(encryptionKey, userId, uid, alias, keyBytes);
+
+ // Import the key to Android KeyStore and get grant
+ mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, keyBytes);
+ return mApplicationKeyStorage.getGrantAlias(userId, uid, alias);
+ } catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ /**
* Gets a key named {@code alias} in caller's namespace.
*
* @return grant alias, which caller can use to access the key.
@@ -632,14 +733,6 @@
}
}
- private String constructLoggingMessage(String key, byte[] value) {
- if (value == null) {
- return key + " is null";
- } else {
- return key + ": " + HexDump.toHexString(value);
- }
- }
-
/**
* Uses {@code recoveryKey} to decrypt {@code applicationKeys}.
*
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
index d85e89e..0077242 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
@@ -16,7 +16,7 @@
package com.android.server.locksettings.recoverablekeystore;
-import android.security.keystore.RecoveryController;
+import android.security.keystore.recovery.RecoveryController;
import android.util.Log;
import java.security.InvalidAlgorithmParameterException;
@@ -107,7 +107,7 @@
* @param keyMaterial The encrypted bytes of the key material.
* @param platformKeyGenerationId The generation ID of the key used to wrap this key.
*
- * @see RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS
+ * @see RecoveryController#RECOVERY_STATUS_SYNC_IN_PROGRESS
* @hide
*/
public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
index 09ec5ad..6e08949 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
@@ -40,6 +40,7 @@
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
@@ -292,6 +293,42 @@
return certPath;
}
+ /**
+ * Validates a given {@code CertPath} against the trusted root certificate.
+ *
+ * @param trustedRoot the trusted root certificate
+ * @param certPath the certificate path to be validated
+ * @throws CertValidationException if the given certificate path is invalid, e.g., is expired,
+ * or does not have a valid signature
+ */
+ public static void validateCertPath(X509Certificate trustedRoot, CertPath certPath)
+ throws CertValidationException {
+ validateCertPath(/*validationDate=*/ null, trustedRoot, certPath);
+ }
+
+ /**
+ * Validates a given {@code CertPath} against a given {@code validationDate}. If the given
+ * validation date is null, the current date will be used.
+ */
+ @VisibleForTesting
+ static void validateCertPath(@Nullable Date validationDate, X509Certificate trustedRoot,
+ CertPath certPath) throws CertValidationException {
+ if (certPath.getCertificates().isEmpty()) {
+ throw new CertValidationException("The given certificate path is empty");
+ }
+ if (!(certPath.getCertificates().get(0) instanceof X509Certificate)) {
+ throw new CertValidationException(
+ "The given certificate path does not contain X509 certificates");
+ }
+
+ List<X509Certificate> certificates = (List<X509Certificate>) certPath.getCertificates();
+ X509Certificate leafCert = certificates.get(0);
+ List<X509Certificate> intermediateCerts =
+ certificates.subList(/*fromIndex=*/ 1, certificates.size());
+
+ validateCert(validationDate, trustedRoot, intermediateCerts, leafCert);
+ }
+
@VisibleForTesting
static CertPath buildCertPath(PKIXParameters pkixParams) throws CertValidationException {
CertPathBuilder certPathBuilder;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 600a534..3d97623 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -16,15 +16,13 @@
package com.android.server.locksettings.recoverablekeystore.storage;
-import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
+import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
import android.annotation.Nullable;
import android.os.ServiceSpecificException;
import android.security.Credentials;
-import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
-import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.KeyStore;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 1cb5d91..8983ec3 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -70,6 +70,122 @@
}
/**
+ * Table holding encrypted snapshots of the recoverable key store.
+ */
+ static class SnapshotsEntry implements BaseColumns {
+ static final String TABLE_NAME = "snapshots";
+
+ /**
+ * The version number of the snapshot.
+ */
+ static final String COLUMN_NAME_VERSION = "version";
+
+ /**
+ * The ID of the user whose keystore was snapshotted.
+ */
+ static final String COLUMN_NAME_USER_ID = "user_id";
+
+ /**
+ * The UID of the app that owns the snapshot (i.e., the recovery agent).
+ */
+ static final String COLUMN_NAME_UID = "uid";
+
+ /**
+ * The maximum number of attempts allowed to attempt to decrypt the recovery key.
+ */
+ static final String COLUMN_NAME_MAX_ATTEMPTS = "max_attempts";
+
+ /**
+ * The ID of the counter in the trusted hardware module.
+ */
+ static final String COLUMN_NAME_COUNTER_ID = "counter_id";
+
+ /**
+ * Server parameters used to help identify the device (during recovery).
+ */
+ static final String SERVER_PARAMS = "server_params";
+
+ /**
+ * The public key of the trusted hardware module. This key has been used to encrypt the
+ * snapshot, to ensure that it can only be read by the trusted module.
+ */
+ static final String TRUSTED_HARDWARE_PUBLIC_KEY = "thm_public_key";
+
+ /**
+ * {@link java.security.cert.CertPath} signing the trusted hardware module to whose public
+ * key this snapshot is encrypted.
+ */
+ static final String CERT_PATH = "cert_path";
+
+ /**
+ * The recovery key, encrypted with the user's lock screen and the trusted hardware module's
+ * public key.
+ */
+ static final String ENCRYPTED_RECOVERY_KEY = "encrypted_recovery_key";
+ }
+
+ /**
+ * Table holding encrypted keys belonging to a particular snapshot.
+ */
+ static class SnapshotKeysEntry implements BaseColumns {
+ static final String TABLE_NAME = "snapshot_keys";
+
+ /**
+ * ID of the associated snapshot entry in {@link SnapshotsEntry}.
+ */
+ static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id";
+
+ /**
+ * Alias of the key.
+ */
+ static final String COLUMN_NAME_ALIAS = "alias";
+
+ /**
+ * Key material, encrypted with the recovery key from the snapshot.
+ */
+ static final String COLUMN_NAME_ENCRYPTED_BYTES = "encrypted_key_bytes";
+ }
+
+ /**
+ * A layer of protection associated with a snapshot.
+ */
+ static class SnapshotProtectionParams implements BaseColumns {
+ static final String TABLE_NAME = "snapshot_protection_params";
+
+ /**
+ * ID of the associated snapshot entry in {@link SnapshotsEntry}.
+ */
+ static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id";
+
+ /**
+ * Type of secret used to generate recovery key. One of
+ * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_LOCKSCREEN} or
+ * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_CUSTOM_PASSWORD}.
+ */
+ static final String COLUMN_NAME_SECRET_TYPE = "secret_type";
+
+ /**
+ * If a lock screen, the type of UI used. One of
+ * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PATTERN},
+ * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PIN}, or
+ * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PASSWORD}.
+ */
+ static final String COLUMN_NAME_LOCKSCREEN_UI_TYPE = "lock_screen_ui_type";
+
+ /**
+ * The algorithm used to derive cryptographic material from the key and salt. One of
+ * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SHA256} or
+ * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_ARGON2ID}.
+ */
+ static final String COLUMN_NAME_KEY_DERIVATION_ALGORITHM = "key_derivation_algorithm";
+
+ /**
+ * The salt used along with the secret to generate cryptographic material.
+ */
+ static final String COLUMN_NAME_KEY_DERIVATION_SALT = "key_derivation_salt";
+ }
+
+ /**
* Recoverable KeyStore metadata for a specific user profile.
*/
static class UserMetadataEntry implements BaseColumns {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4b432a3a..b110e88 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -521,10 +521,10 @@
synchronized (mLock) {
// List to keep the session services that need be removed because they don't exist
// in the 'services' above.
- Set<SessionToken2> sessionTokensToRemove = new HashSet<>(mSessionRecords.keySet());
- for (SessionToken2 token : sessionTokensToRemove) {
- if (token.getType() == TYPE_SESSION) {
- sessionTokensToRemove.remove(token);
+ Set<SessionToken2> sessionTokensToRemove = new HashSet<>();
+ for (SessionToken2 token : mSessionRecords.keySet()) {
+ if (token.getType() != TYPE_SESSION) {
+ sessionTokensToRemove.add(token);
}
}
diff --git a/services/core/java/com/android/server/media/MediaUpdateService.java b/services/core/java/com/android/server/media/MediaUpdateService.java
index 6921ccd..f38b353 100644
--- a/services/core/java/com/android/server/media/MediaUpdateService.java
+++ b/services/core/java/com/android/server/media/MediaUpdateService.java
@@ -16,27 +16,21 @@
package com.android.server.media;
-import android.content.Context;
-import android.content.Intent;
-import android.media.IMediaResourceMonitor;
-import android.os.Binder;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.Slog;
-import com.android.server.SystemService;
-
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.media.IMediaExtractorUpdateService;
import android.os.IBinder;
+import android.os.Handler;
import android.os.PatternMatcher;
import android.os.ServiceManager;
-import android.media.IMediaExtractorUpdateService;
-
-import java.lang.Exception;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import com.android.server.SystemService;
/** This class provides a system service that manages media framework updates. */
public class MediaUpdateService extends SystemService {
@@ -46,9 +40,11 @@
private static final String EXTRACTOR_UPDATE_SERVICE_NAME = "media.extractor.update";
private IMediaExtractorUpdateService mMediaExtractorUpdateService;
+ final Handler mHandler;
public MediaUpdateService(Context context) {
super(context);
+ mHandler = new Handler();
}
@Override
@@ -77,7 +73,12 @@
}
if (binder != null) {
mMediaExtractorUpdateService = IMediaExtractorUpdateService.Stub.asInterface(binder);
- packageStateChanged();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ packageStateChanged();
+ }
+ });
} else {
Slog.w(TAG, EXTRACTOR_UPDATE_SERVICE_NAME + " not found.");
}
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 896480f..c0c66b2 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -45,8 +46,6 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-import android.os.SystemClock;
-
/**
* This {@link NotificationSignalExtractor} attempts to validate
* people references. Also elevates the priority of real people.
@@ -231,7 +230,6 @@
private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras,
List<String> peopleOverride, float[] affinityOut) {
- long start = SystemClock.elapsedRealtime();
float affinity = NONE;
if (extras == null) {
return null;
@@ -239,7 +237,7 @@
final Set<String> people = new ArraySet<>(peopleOverride);
final String[] notificationPeople = getExtraPeople(extras);
if (notificationPeople != null ) {
- people.addAll(Arrays.asList(getExtraPeople(extras)));
+ people.addAll(Arrays.asList(notificationPeople));
}
if (VERBOSE) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId());
@@ -283,7 +281,31 @@
// VisibleForTesting
public static String[] getExtraPeople(Bundle extras) {
- Object people = extras.get(Notification.EXTRA_PEOPLE_LIST);
+ String[] peopleList = getExtraPeopleForKey(extras, Notification.EXTRA_PEOPLE_LIST);
+ String[] legacyPeople = getExtraPeopleForKey(extras, Notification.EXTRA_PEOPLE);
+ return combineLists(legacyPeople, peopleList);
+ }
+
+ private static String[] combineLists(String[] first, String[] second) {
+ if (first == null) {
+ return second;
+ }
+ if (second == null) {
+ return first;
+ }
+ ArraySet<String> people = new ArraySet<>(first.length + second.length);
+ for (String person: first) {
+ people.add(person);
+ }
+ for (String person: second) {
+ people.add(person);
+ }
+ return (String[]) people.toArray();
+ }
+
+ @Nullable
+ private static String[] getExtraPeopleForKey(Bundle extras, String key) {
+ Object people = extras.get(key);
if (people instanceof String[]) {
return (String[]) people;
}
@@ -458,7 +480,6 @@
@Override
public void work() {
- long start = SystemClock.elapsedRealtime();
if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey);
long timeStartMs = System.currentTimeMillis();
for (final String handle: mPendingLookups) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 8591304..e315bc5 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -146,6 +146,12 @@
Intent intent = registerReceiver(null, filter);
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+ boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+
+ if (!present) {
+ // No battery, treat as if 100%, no possibility of draining battery.
+ return 100;
+ }
if (level < 0 || scale <= 0) {
// Battery data unavailable. This should never happen, so assume the worst.
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index 98f421e..16b4368 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import android.annotation.AnyThread;
+import android.annotation.WorkerThread;
import android.app.IInstantAppResolver;
import android.app.InstantAppResolverService;
import android.content.ComponentName;
@@ -37,6 +39,7 @@
import android.util.TimedRemoteCaller;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
import java.util.ArrayList;
import java.util.List;
@@ -68,6 +71,7 @@
private static final int STATE_IDLE = 0; // no bind operation is ongoing
private static final int STATE_BINDING = 1; // someone is binding and waiting
private static final int STATE_PENDING = 2; // a bind is pending, but the caller is not waiting
+ private final Handler mBgHandler;
@GuardedBy("mLock")
private int mBindState = STATE_IDLE;
@@ -78,6 +82,7 @@
Context context, ComponentName componentName, String action) {
mContext = context;
mIntent = new Intent(action).setComponent(componentName);
+ mBgHandler = BackgroundThread.getHandler();
}
public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(Intent sanitizedIntent,
@@ -131,6 +136,7 @@
}
}
+ @WorkerThread
private IInstantAppResolver getRemoteInstanceLazy(String token)
throws ConnectionException, TimeoutException, InterruptedException {
long binderToken = Binder.clearCallingIdentity();
@@ -157,6 +163,7 @@
}
}
+ @WorkerThread
private IInstantAppResolver bind(String token)
throws ConnectionException, TimeoutException, InterruptedException {
boolean doUnbind = false;
@@ -241,6 +248,19 @@
}
}
+ @AnyThread
+ void optimisticBind() {
+ mBgHandler.post(() -> {
+ try {
+ if (bind("Optimistic Bind") != null && DEBUG_INSTANT) {
+ Slog.i(TAG, "Optimistic bind succeeded.");
+ }
+ } catch (ConnectionException | TimeoutException | InterruptedException e) {
+ Slog.e(TAG, "Optimistic bind failed.", e);
+ }
+ });
+ }
+
@Override
public void binderDied() {
if (DEBUG_INSTANT) {
@@ -249,6 +269,7 @@
synchronized (mLock) {
handleBinderDiedLocked();
}
+ optimisticBind();
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 256fb42..98fb18a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -176,6 +176,7 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.ParseFlags;
import android.content.pm.PackageParser.ServiceIntentInfo;
+import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
@@ -6691,7 +6692,9 @@
return result;
}
final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
- if (ps == null) {
+ if (ps == null
+ || ps.getUserState().get(userId) == null
+ || !ps.getUserState().get(userId).isEnabled(mInstantAppInstallerActivity, 0)) {
return result;
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
@@ -20870,6 +20873,16 @@
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.systemReady();
+
+ if (mInstantAppResolverConnection != null) {
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mInstantAppResolverConnection.optimisticBind();
+ mContext.unregisterReceiver(this);
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }
}
public void waitForAppDataPrepared() {
@@ -23320,6 +23333,39 @@
}
@Override
+ public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
+ SigningDetails sd = getSigningDetails(packageName);
+ if (sd == null) {
+ return false;
+ }
+ return sd.hasSha256Certificate(restoringFromSigHash,
+ SigningDetails.CertCapabilities.INSTALLED_DATA);
+ }
+
+ @Override
+ public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
+ SigningDetails sd = getSigningDetails(packageName);
+ if (sd == null) {
+ return false;
+ }
+ return sd.hasCertificate(restoringFromSig,
+ SigningDetails.CertCapabilities.INSTALLED_DATA);
+ }
+
+ private SigningDetails getSigningDetails(String packageName) {
+ synchronized (mPackages) {
+ if (packageName == null) {
+ return null;
+ }
+ PackageParser.Package p = mPackages.get(packageName);
+ if (p == null) {
+ return null;
+ }
+ return p.mSigningDetails;
+ }
+ }
+
+ @Override
public int getPermissionFlagsTEMP(String permName, String packageName, int userId) {
return PackageManagerService.this.getPermissionFlags(permName, packageName, userId);
}
@@ -23556,6 +23602,11 @@
}
@Override
+ public ComponentName getDefaultHomeActivity(int userId) {
+ return PackageManagerService.this.getDefaultHomeActivity(userId);
+ }
+
+ @Override
public void setDeviceAndProfileOwnerPackages(
int deviceOwnerUserId, String deviceOwnerPackage,
SparseArray<String> profileOwnerPackages) {
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index cedf476..0fecb63 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -230,7 +230,7 @@
out.startTag(null, TAG_ROOT);
ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
- getPackageInfo().saveToXml(out, forBackup);
+ getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
for (int i = 0; i < size; i++) {
final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index c11c099..92e261a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1348,7 +1348,7 @@
ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
- getPackageInfo().saveToXml(out, forBackup);
+ getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
for (int j = 0; j < size; j++) {
saveShortcut(out, mShortcuts.valueAt(j), forBackup,
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 3d37229..44dd924 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -18,10 +18,12 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupUtils;
import libcore.util.HexEncoding;
@@ -48,6 +50,7 @@
private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time";
private static final String ATTR_BACKUP_SOURCE_VERSION = "bk_src_version";
private static final String ATTR_BACKUP_ALLOWED = "allow-backup";
+ private static final String ATTR_BACKUP_ALLOWED_INITIALIZED = "allow-backup-initialized";
private static final String ATTR_BACKUP_SOURCE_BACKUP_ALLOWED = "bk_src_backup-allowed";
private static final String ATTR_SHADOW = "shadow";
@@ -136,7 +139,8 @@
//@DisabledReason
public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) {
- if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) {
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage, pmi)) {
Slog.w(TAG, "Can't restore: Package signature mismatch");
return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
}
@@ -187,7 +191,11 @@
mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
}
- public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException {
+ public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
+ throws IOException {
+ if (forBackup && !mBackupAllowedInitialized) {
+ s.wtf("Backup happened before mBackupAllowed is initialized.");
+ }
out.startTag(null, TAG_ROOT);
@@ -196,6 +204,10 @@
ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
ShortcutService.writeAttr(out, ATTR_BACKUP_ALLOWED, mBackupAllowed);
+ // We don't need to save this field (we don't even read it back), but it'll show up
+ // in the dumpsys in the backup / restore payload.
+ ShortcutService.writeAttr(out, ATTR_BACKUP_ALLOWED_INITIALIZED, mBackupAllowedInitialized);
+
ShortcutService.writeAttr(out, ATTR_BACKUP_SOURCE_VERSION, mBackupSourceVersionCode);
ShortcutService.writeAttr(out,
ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, mBackupSourceBackupAllowed);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 076f81f..70fb616 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3125,7 +3125,8 @@
try {
return mIPackageManager.getPackageInfo(
packageName, PACKAGE_MATCH_FLAGS
- | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId);
+ | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0),
+ userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3545,9 +3546,11 @@
// Update the signatures for all packages.
user.forAllPackageItems(spi -> spi.refreshPackageSignatureAndSave());
+ // Rescan all apps; this will also update the version codes and "allow-backup".
+ user.forAllPackages(pkg -> pkg.rescanPackageIfNeeded(
+ /*isNewApp=*/ false, /*forceRescan=*/ true));
+
// Set the version code for the launchers.
- // We shouldn't do this for publisher packages, because we don't want to update the
- // version code without rescanning the manifest.
user.forAllLaunchers(launcher -> launcher.ensurePackageInfo());
// Save to the filesystem.
@@ -3566,7 +3569,9 @@
Slog.w(TAG, "Backup failed.", e);
return null;
}
- return os.toByteArray();
+ byte[] payload = os.toByteArray();
+ mShortcutDumpFiles.save("backup-1-payload.txt", payload);
+ return payload;
}
}
@@ -3846,6 +3851,8 @@
pw.print(next);
pw.print("] ");
pw.print(formatTime(next));
+ pw.println();
+ pw.println();
pw.print(" Config:");
pw.print(" Max icon dim: ");
@@ -4241,7 +4248,6 @@
}
// Injection point.
- @VisibleForTesting
String injectBuildFingerprint() {
return Build.FINGERPRINT;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index c044c1c..505e4ee 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,7 +23,6 @@
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -62,6 +61,7 @@
// Suffix "2" was added to force rescan all packages after the next OTA.
private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
+ private static final String ATTR_RESTORE_SOURCE_FINGERPRINT = "restore-from-fp";
private static final String KEY_USER_ID = "userId";
private static final String KEY_LAUNCHERS = "launchers";
private static final String KEY_PACKAGES = "packages";
@@ -128,6 +128,7 @@
private long mLastAppScanTime;
private String mLastAppScanOsFingerprint;
+ private String mRestoreFromOsFingerprint;
public ShortcutUser(ShortcutService service, int userId) {
mService = service;
@@ -340,8 +341,13 @@
mLastAppScanTime);
ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
mLastAppScanOsFingerprint);
+ ShortcutService.writeAttr(out, ATTR_RESTORE_SOURCE_FINGERPRINT,
+ mRestoreFromOsFingerprint);
ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
+ } else {
+ ShortcutService.writeAttr(out, ATTR_RESTORE_SOURCE_FINGERPRINT,
+ mService.injectBuildFingerprint());
}
// Can't use forEachPackageItem due to the checked exceptions.
@@ -387,6 +393,8 @@
ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
+ ret.mRestoreFromOsFingerprint = ShortcutService.parseStringAttribute(parser,
+ ATTR_RESTORE_SOURCE_FINGERPRINT);
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -524,6 +532,8 @@
restored.mLaunchers.clear();
restored.mPackages.clear();
+ mRestoreFromOsFingerprint = restored.mRestoreFromOsFingerprint;
+
Slog.i(TAG, "Restored: L=" + restoredLaunchers[0]
+ " P=" + restoredPackages[0]
+ " S=" + restoredShortcuts[0]);
@@ -539,14 +549,21 @@
pw.print(" Last app scan: [");
pw.print(mLastAppScanTime);
pw.print("] ");
- pw.print(ShortcutService.formatTime(mLastAppScanTime));
- pw.print(" Last app scan FP: ");
- pw.print(mLastAppScanOsFingerprint);
- pw.println();
+ pw.println(ShortcutService.formatTime(mLastAppScanTime));
prefix += prefix + " ";
pw.print(prefix);
+ pw.print("Last app scan FP: ");
+ pw.println(mLastAppScanOsFingerprint);
+
+ pw.print(prefix);
+ pw.print("Restore from FP: ");
+ pw.print(mRestoreFromOsFingerprint);
+ pw.println();
+
+
+ pw.print(prefix);
pw.print("Cached launcher: ");
pw.print(mCachedLauncher);
pw.println();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index de7e21a..2c7df6c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2584,9 +2584,6 @@
Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
return null;
}
- if (ActivityManager.isLowRamDeviceStatic()) {
- return null;
- }
final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 41570c4..b5d8326 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -565,21 +565,21 @@
break;
case UserManager.DISALLOW_AMBIENT_DISPLAY:
if (newValue) {
- android.provider.Settings.Secure.putString(
+ android.provider.Settings.Secure.putIntForUser(
context.getContentResolver(),
- Settings.Secure.DOZE_ENABLED, "0");
- android.provider.Settings.Secure.putString(
+ Settings.Secure.DOZE_ENABLED, 0, userId);
+ android.provider.Settings.Secure.putIntForUser(
context.getContentResolver(),
- Settings.Secure.DOZE_ALWAYS_ON, "0");
- android.provider.Settings.Secure.putString(
+ Settings.Secure.DOZE_ALWAYS_ON, 0, userId);
+ android.provider.Settings.Secure.putIntForUser(
context.getContentResolver(),
- Settings.Secure.DOZE_PULSE_ON_PICK_UP, "0");
- android.provider.Settings.Secure.putString(
+ Settings.Secure.DOZE_PULSE_ON_PICK_UP, 0, userId);
+ android.provider.Settings.Secure.putIntForUser(
context.getContentResolver(),
- Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, "0");
- android.provider.Settings.Secure.putString(
+ Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, 0, userId);
+ android.provider.Settings.Secure.putIntForUser(
context.getContentResolver(),
- Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, "0");
+ Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, 0, userId);
}
break;
case UserManager.DISALLOW_CONFIG_LOCATION:
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e40dc4f..eaa17ca 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -485,7 +485,7 @@
boolean mSafeMode;
private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
WindowState mStatusBar = null;
- int mStatusBarHeight;
+ private final int[] mStatusBarHeightForRotation = new int[4];
WindowState mNavigationBar = null;
boolean mHasNavigationBar = false;
boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
@@ -785,6 +785,9 @@
private int mCurrentUserId;
+ /* Whether accessibility is magnifying the screen */
+ private boolean mScreenMagnificationActive;
+
// Maps global key codes to the components that will handle them.
private GlobalKeyManager mGlobalKeyManager;
@@ -2765,8 +2768,12 @@
Context uiContext = getSystemUiContext();
final Resources res = uiContext.getResources();
- mStatusBarHeight =
- res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ mStatusBarHeightForRotation[mPortraitRotation] =
+ mStatusBarHeightForRotation[mUpsideDownRotation] = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_portrait);
+ mStatusBarHeightForRotation[mLandscapeRotation] =
+ mStatusBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_landscape);
// Height of the navigation bar when presented horizontally at bottom
mNavigationBarHeightForRotationDefault[mPortraitRotation] =
@@ -2881,11 +2888,11 @@
// of the screen.
// TODO(multi-display): Support status bars on secondary displays.
if (displayId == DEFAULT_DISPLAY) {
- int statusBarHeight = mStatusBarHeight;
+ int statusBarHeight = mStatusBarHeightForRotation[rotation];
if (displayCutout != null) {
// If there is a cutout, it may already have accounted for some part of the status
// bar height.
- statusBarHeight = Math.max(0, mStatusBarHeight - displayCutout.getSafeInsetTop());
+ statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
}
return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayId,
displayCutout) - statusBarHeight;
@@ -4646,7 +4653,8 @@
displayFrames.mDisplayCutout);
// For layout, the status bar is always at the top with our fixed height.
- displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeight;
+ displayFrames.mStable.top = displayFrames.mUnrestricted.top
+ + mStatusBarHeightForRotation[displayFrames.mRotation];
boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
boolean statusBarTranslucent = (sysui
@@ -5639,9 +5647,7 @@
final int fl = PolicyControl.getWindowFlags(null,
mTopFullscreenOpaqueWindowState.getAttrs());
if (localLOGV) {
- Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
- + " shown position: "
- + mTopFullscreenOpaqueWindowState.getShownPositionLw());
+ Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
+ " lp.flags=0x" + Integer.toHexString(fl));
}
@@ -6935,7 +6941,7 @@
// Navigation bar and status bar.
getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
- outInsets.top = Math.max(outInsets.top, mStatusBarHeight);
+ outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
}
@Override
@@ -8164,7 +8170,11 @@
*/
private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
boolean freeformStackVisible, boolean isDockedDividerResizing) {
- if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
+ if (mScreenMagnificationActive) {
+ // When the screen is magnified, the nav bar should be opaque since its background
+ // can vary as the user pans and zooms
+ visibility = setNavBarOpaqueFlag(visibility);
+ } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
visibility = setNavBarOpaqueFlag(visibility);
}
@@ -8319,6 +8329,14 @@
}
@Override
+ public void onScreenMagnificationStateChanged(boolean active) {
+ synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+ mScreenMagnificationActive = active;
+ updateSystemUiVisibilityLw();
+ }
+ }
+
+ @Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(LAST_SYSTEM_UI_FLAGS, mLastSystemUiFlags);
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index dde4bc8..a07f5eb 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -232,14 +232,6 @@
public Rect getFrameLw();
/**
- * Retrieve the current position of the window that is actually shown.
- * Must be called with the window manager lock held.
- *
- * @return Point The point holding the shown window position.
- */
- public Point getShownPositionLw();
-
- /**
* Retrieve the frame of the display that this window was last
* laid out in. Must be called with the
* window manager lock held.
@@ -1700,6 +1692,13 @@
boolean canDismissBootAnimation();
/**
+ * Called when the magnification state changes.
+ *
+ * @param active Whether magnification is active (that is, we are zoomed in).
+ */
+ void onScreenMagnificationStateChanged(boolean active);
+
+ /**
* Convert the user rotation mode to a human readable format.
*/
static String userRotationModeToString(int mode) {
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 08dc97e..16336b3 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -68,6 +68,7 @@
private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
+ private static final String KEY_AOD_DISABLED = "aod_disabled";
private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
@@ -200,11 +201,17 @@
private boolean mForceBackgroundCheck;
/**
- * Weather to show non-essential sensors (e.g. edge sensors) or not.
+ * Whether to show non-essential sensors (e.g. edge sensors) or not.
*/
@GuardedBy("mLock")
private boolean mOptionalSensorsDisabled;
+ /**
+ * Whether AOD is enabled or not.
+ */
+ @GuardedBy("mLock")
+ private boolean mAodDisabled;
+
@GuardedBy("mLock")
private Context mContext;
@@ -339,6 +346,7 @@
mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
+ mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
// Get default value from Settings.Secure
final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
@@ -375,6 +383,7 @@
if (mLaunchBoostDisabled) sb.append("l");
if (mOptionalSensorsDisabled) sb.append("S");
+ if (mAodDisabled) sb.append("o");
sb.append(mGpsMode);
@@ -437,6 +446,9 @@
case ServiceType.OPTIONAL_SENSORS:
return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
.build();
+ case ServiceType.AOD:
+ return builder.setBatterySaverEnabled(mAodDisabled)
+ .build();
default:
return builder.setBatterySaverEnabled(realMode)
.build();
@@ -491,6 +503,7 @@
pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
+ pw.println(" " + KEY_AOD_DISABLED + "=" + mAodDisabled);
pw.println();
pw.print(" Interactive File values:\n");
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 3072f21..b729b6a 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -91,7 +91,7 @@
private final Context mContext;
private final IBatteryStats mBatteryStats;
- private final IAppOpsService mAppOps;
+ private final AppOpsManager mAppOps;
private final SuspendBlocker mSuspendBlocker;
private final WindowManagerPolicy mPolicy;
private final ActivityManagerInternal mActivityManagerInternal;
@@ -134,11 +134,10 @@
private boolean mUserActivityPending;
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
- IAppOpsService appOps, SuspendBlocker suspendBlocker,
- WindowManagerPolicy policy) {
+ SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
mContext = context;
mBatteryStats = batteryStats;
- mAppOps = appOps;
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
mSuspendBlocker = suspendBlocker;
mPolicy = policy;
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -194,8 +193,7 @@
mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
monitorType, unimportantForLogging);
// XXX need to deal with disabled operations.
- mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
- AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
+ mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
}
} catch (RemoteException ex) {
// Ignore
@@ -295,8 +293,7 @@
} else {
mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
historyTag, monitorType);
- mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
- AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
+ mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
}
} catch (RemoteException ex) {
// Ignore
@@ -539,12 +536,11 @@
try {
mBatteryStats.noteWakeUp(reason, reasonUid);
if (opPackageName != null) {
- mAppOps.noteOperation(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);
+ mAppOps.noteOpNoThrow(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);
}
} catch (RemoteException ex) {
// Ignore
}
-
}
/**
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d67acc4..f77b0ee 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -759,8 +759,7 @@
// with the animations and other critical functions of the power manager.
mBatteryStats = BatteryStatsService.getService();
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
- mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
- mPolicy);
+ createSuspendBlockerLocked("PowerManagerService.Broadcasts"), mPolicy);
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 32f38b7..a9a1456 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -347,7 +347,7 @@
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
.putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, enabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 95c30d1..6e017cd 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -100,6 +100,7 @@
private final PendingIntent mAnomalyAlarmIntent;
private final PendingIntent mPullingAlarmIntent;
+ private final PendingIntent mPeriodicAlarmIntent;
private final BroadcastReceiver mAppUpdateReceiver;
private final BroadcastReceiver mUserUpdateReceiver;
private final ShutdownEventReceiver mShutdownEventReceiver;
@@ -123,6 +124,8 @@
new Intent(mContext, AnomalyAlarmReceiver.class), 0);
mPullingAlarmIntent = PendingIntent.getBroadcast(
mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
+ mPeriodicAlarmIntent = PendingIntent.getBroadcast(
+ mContext, 0, new Intent(mContext, PeriodicAlarmReceiver.class), 0);
mAppUpdateReceiver = new AppUpdateReceiver();
mUserUpdateReceiver = new BroadcastReceiver() {
@Override
@@ -329,7 +332,28 @@
}
}
- private final static class ShutdownEventReceiver extends BroadcastReceiver {
+ public final static class PeriodicAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG)
+ Slog.d(TAG, "Time to poll something.");
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ sStatsd.informAlarmForSubscriberTriggeringFired();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
+ }
+ }
+ // AlarmManager releases its own wakelock here.
+ }
+ }
+
+ public final static class ShutdownEventReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
/**
@@ -385,6 +409,35 @@
}
@Override // Binder call
+ public void setAlarmForSubscriberTriggering(long timestampMs) {
+ enforceCallingPermission();
+ if (DEBUG)
+ Slog.d(TAG, "Setting periodic alarm at " + timestampMs);
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+ // only fire when it awakens.
+ // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ }
+
+ @Override // Binder call
+ public void cancelAlarmForSubscriberTriggering() {
+ enforceCallingPermission();
+ if (DEBUG)
+ Slog.d(TAG, "Cancelling periodic alarm");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ mAlarmManager.cancel(mPeriodicAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ }
+
+ @Override // Binder call
public void setPullingAlarms(long timestampMs, long intervalMs) {
enforceCallingPermission();
if (DEBUG)
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 659253f..c31cdec 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -87,6 +87,8 @@
private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
+ private boolean mScreenMagnificationActive;
+
public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
if (callbacks != null) {
if (mDisplayMagnifier != null) {
@@ -136,6 +138,11 @@
if (mWindowsForAccessibilityObserver != null) {
mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
+ boolean nowActive = !spec.isNop();
+ if (nowActive != mScreenMagnificationActive) {
+ mScreenMagnificationActive = nowActive;
+ mService.mPolicy.onScreenMagnificationStateChanged(nowActive);
+ }
}
public void getMagnificationRegionLocked(Region outMagnificationRegion) {
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index db95634..3cd3e8b 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -53,8 +53,7 @@
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
mAppToken = appToken;
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService);
mWidth = thumbnailHeader.getWidth();
mHeight = thumbnailHeader.getHeight();
@@ -145,11 +144,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mAppToken.destroyAfterPendingTransaction(surface);
- }
-
- @Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
t.setLayer(leash, Integer.MAX_VALUE);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 277a04b..c2cc7c9 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1620,7 +1620,15 @@
@Override
public SurfaceControl getAnimationLeashParent() {
- return getAppAnimationLayer();
+ // All normal app transitions take place in an animation layer which is below the pinned
+ // stack but may be above the parent stacks of the given animating apps.
+ // For transitions in the pinned stack (menu activity) we just let them occur as a child
+ // of the pinned stack.
+ if (!inPinnedWindowingMode()) {
+ return getAppAnimationLayer();
+ } else {
+ return getStack().getSurfaceControl();
+ }
}
boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
@@ -1709,6 +1717,10 @@
frame.set(win.mFrame);
} else if (win.isLetterboxedAppWindow()) {
frame.set(getTask().getBounds());
+ } else if (win.isDockedResizing()) {
+ // If we are animating while docked resizing, then use the stack bounds as the
+ // animation target (which will be different than the task bounds)
+ frame.set(getTask().getParent().getBounds());
} else {
frame.set(win.mContainingFrame);
}
@@ -1763,10 +1775,18 @@
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
-
// The leash is parented to the animation layer. We need to preserve the z-order by using
// the prefix order index, but we boost if necessary.
- int layer = getPrefixOrderIndex();
+ int layer = 0;
+ if (!inPinnedWindowingMode()) {
+ layer = getPrefixOrderIndex();
+ } else {
+ // Pinned stacks have animations take place within themselves rather than an animation
+ // layer so we need to preserve the order relative to the stack (e.g. the order of our
+ // task/parent).
+ layer = getParent().getPrefixOrderIndex();
+ }
+
if (mNeedsZBoost) {
layer += Z_BOOST_BASE;
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 4394a99..a180a3a 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -55,11 +55,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mHost.destroyAfterPendingTransaction(surface);
- }
-
- @Override
public SurfaceControl.Builder makeAnimationLeash() {
return mHost.makeAnimationLeash();
}
@@ -119,7 +114,7 @@
if (!mDimming) {
mDimLayer.destroy();
}
- }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService);
+ }, mHost.mService);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 75a6338..59bece0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -382,11 +382,6 @@
*/
private int mSurfaceSize;
- /**
- * A list of surfaces to be destroyed after {@link #mPendingTransaction} is applied.
- */
- private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
-
/** Temporary float array to retrieve 3x3 matrix values. */
private final float[] mTmpFloats = new float[9];
@@ -747,7 +742,14 @@
mDividerControllerLocked = new DockedStackDividerController(service, this);
mPinnedStackControllerLocked = new PinnedStackController(service, this);
- mSurfaceSize = Math.max(mBaseDisplayHeight, mBaseDisplayWidth);
+ // We use this as our arbitrary surface size for buffer-less parents
+ // that don't impose cropping on their children. It may need to be larger
+ // than the display size because fullscreen windows can be shifted offscreen
+ // due to surfaceInsets. 2 times the largest display dimension feels like an
+ // appropriately arbitrary number. Eventually we would like to give SurfaceFlinger
+ // layers the ability to match their parent sizes and be able to skip
+ // such arbitrary size settings.
+ mSurfaceSize = Math.max(mBaseDisplayHeight, mBaseDisplayWidth) * 2;
final SurfaceControl.Builder b = mService.makeSurfaceBuilder(mSession)
.setSize(mSurfaceSize, mSurfaceSize)
@@ -1954,10 +1956,6 @@
}
}
mService.mAnimator.removeDisplayLocked(mDisplayId);
-
- // The pending transaction won't be applied so we should
- // just clean up any surfaces pending destruction.
- onPendingTransactionApplied();
} finally {
mRemovingDisplay = false;
}
@@ -2600,18 +2598,6 @@
}, false /* traverseTopToBottom */);
}
- void enableSurfaceTrace(FileDescriptor fd) {
- forAllWindows(w -> {
- w.mWinAnimator.enableSurfaceTrace(fd);
- }, true /* traverseTopToBottom */);
- }
-
- void disableSurfaceTrace() {
- forAllWindows(w -> {
- w.mWinAnimator.disableSurfaceTrace();
- }, true /* traverseTopToBottom */);
- }
-
/**
* Starts the Keyguard exit animation on all windows that don't belong to an app token.
*/
@@ -3583,7 +3569,7 @@
if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
t.setLayer(mSplitScreenDividerAnchor, layer++);
}
- if (s.isSelfOrChildAnimating()) {
+ if (s.isAppAnimating() && state != ALWAYS_ON_TOP_STATE) {
// Ensure the animation layer ends up above the
// highest animating stack and no higher.
layerForAnimationLayer = layer++;
@@ -3632,6 +3618,11 @@
super(name, service);
}
+ @Override
+ void assignChildLayers(SurfaceControl.Transaction t) {
+ assignChildLayers(t, null /* imeContainer */);
+ }
+
void assignChildLayers(SurfaceControl.Transaction t, WindowContainer imeContainer) {
boolean needAssignIme = imeContainer != null
&& imeContainer.getSurfaceControl() != null;
@@ -3874,22 +3865,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterPendingTransaction}.
- */
- void onPendingTransactionApplied() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
- @Override
void prepareSurfaces() {
final ScreenRotationAnimation screenRotationAnimation =
mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
@@ -3903,6 +3878,7 @@
mPendingTransaction.setAlpha(mWindowingLayer,
screenRotationAnimation.getEnterTransformation().getAlpha());
}
+
super.prepareSurfaces();
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index 0e12838..e3e4a46 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -50,7 +50,9 @@
}
if (mContainer == null) {
- throw new IllegalArgumentException("Trying to add displayId=" + displayId);
+ throw new IllegalArgumentException("Trying to add displayId=" + displayId
+ + " display=" + display
+ + " dc=" + mRoot.getDisplayContent(displayId));
}
}
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 46c59c5..1f1efc4 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -620,7 +620,12 @@
if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
&& appTransition != TRANSIT_NONE &&
!AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
- mService.showRecentApps();
+ if (mService.mAmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) {
+ // When the home activity is the recents component and we are already minimized,
+ // then there is nothing to do here since home is already visible
+ } else {
+ mService.showRecentApps();
+ }
}
}
@@ -641,7 +646,7 @@
return mMinimizedDock;
}
- private void checkMinimizeChanged(boolean animate) {
+ void checkMinimizeChanged(boolean animate) {
if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
return;
}
@@ -693,7 +698,7 @@
final boolean imeChanged = clearImeAdjustAnimation();
boolean minimizedChange = false;
if (isHomeStackResizable()) {
- notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */,
+ notifyDockedStackMinimizedChanged(minimizedDock, animate,
true /* isHomeStackResizable */);
minimizedChange = true;
} else {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 31b5c69..f7344b2 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -219,7 +219,7 @@
private void addAnimation(Task task) {
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
- mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
+ mService);
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
task.commitPendingTransaction();
@@ -256,18 +256,20 @@
void cancelAnimation() {
if (DEBUG) Log.d(TAG, "cancelAnimation()");
- if (mCanceled) {
- // We've already canceled the animation
- return;
+ synchronized (mService.getWindowManagerLock()) {
+ if (mCanceled) {
+ // We've already canceled the animation
+ return;
+ }
+ mCanceled = true;
+ try {
+ mRunner.onAnimationCanceled();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
+ }
}
- mCanceled = true;
- try {
- mRunner.onAnimationCanceled();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to cancel recents animation", e);
- }
-
// Clean up and return to the previous app
+ // Don't hold the WM lock here as it calls back to AM/RecentsAnimation
mCallbacks.onAnimationFinished(false /* moveHomeToTop */);
}
diff --git a/services/core/java/com/android/server/wm/RemoteEventTrace.java b/services/core/java/com/android/server/wm/RemoteEventTrace.java
deleted file mode 100644
index b214d35..0000000
--- a/services/core/java/com/android/server/wm/RemoteEventTrace.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2016 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 java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.DataOutputStream;
-
-import android.os.StrictMode;
-import android.util.Slog;
-import android.os.Debug;
-
-// Counterpart to remote surface trace for events which are not tied to a particular surface.
-class RemoteEventTrace {
- private static final String TAG = "RemoteEventTrace";
-
- // We terminate all our messages with a recognizable marker, to avoid issues
- // with partial reads (which ADB makes impossible to avoid).
- static final byte[] sigil = {(byte)0xfc, (byte)0xfc, (byte)0xfc, (byte)0xfc};
-
- private final WindowManagerService mService;
- private final DataOutputStream mOut;
-
- RemoteEventTrace(WindowManagerService service, FileDescriptor fd) {
- mService = service;
- mOut = new DataOutputStream(new FileOutputStream(fd, false));
- }
-
- void openSurfaceTransaction() {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- mOut.writeUTF("OpenTransaction");
- writeSigil();
- } catch (Exception e) {
- logException(e);
- mService.disableSurfaceTrace();
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
-
- void closeSurfaceTransaction() {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- mOut.writeUTF("CloseTransaction");
- writeSigil();
- } catch (Exception e) {
- logException(e);
- mService.disableSurfaceTrace();
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
-
- private void writeSigil() throws Exception {
- mOut.write(RemoteEventTrace.sigil, 0, 4);
- }
-
- static void logException(Exception e) {
- Slog.i(TAG, "Exception writing to SurfaceTrace (client vanished?): " + e.toString());
- }
-}
diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
deleted file mode 100644
index 33e560f..0000000
--- a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2016 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.graphics.Rect;
-import android.graphics.Region;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.StrictMode;
-import android.util.Slog;
-import android.view.SurfaceControl;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.DataOutputStream;
-
-// A surface control subclass which logs events to a FD in binary format.
-// This can be used in our CTS tests to enable a pattern similar to mocking
-// the surface control.
-//
-// See cts/hostsidetests/../../SurfaceTraceReceiver.java for parsing side.
-class RemoteSurfaceTrace extends SurfaceControl {
- static final String TAG = "RemoteSurfaceTrace";
-
- final FileDescriptor mWriteFd;
- final DataOutputStream mOut;
-
- final WindowManagerService mService;
- final WindowState mWindow;
-
- RemoteSurfaceTrace(FileDescriptor fd, SurfaceControl wrapped,
- WindowState window) {
- super(wrapped);
-
- mWriteFd = fd;
- mOut = new DataOutputStream(new FileOutputStream(fd, false));
-
- mWindow = window;
- mService = mWindow.mService;
- }
-
- @Override
- public void setAlpha(float alpha) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeFloatEvent("Alpha", alpha);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setAlpha(alpha);
- }
-
- @Override
- public void setLayer(int zorder) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeIntEvent("Layer", zorder);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setLayer(zorder);
- }
-
- @Override
- public void setPosition(float x, float y) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeFloatEvent("Position", x, y);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setPosition(x, y);
- }
-
- @Override
- public void setGeometryAppliesWithResize() {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeEvent("GeometryAppliesWithResize");
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setGeometryAppliesWithResize();
- }
-
- @Override
- public void setSize(int w, int h) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeIntEvent("Size", w, h);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setSize(w, h);
- }
-
- @Override
- public void setWindowCrop(Rect crop) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeRectEvent("Crop", crop);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setWindowCrop(crop);
- }
-
- @Override
- public void setFinalCrop(Rect crop) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeRectEvent("FinalCrop", crop);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setFinalCrop(crop);
- }
-
- @Override
- public void setLayerStack(int layerStack) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeIntEvent("LayerStack", layerStack);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setLayerStack(layerStack);
- }
-
- @Override
- public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeFloatEvent("Matrix", dsdx, dtdx, dsdy, dtdy);
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.setMatrix(dsdx, dtdx, dsdy, dtdy);
- }
-
- @Override
- public void hide() {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeEvent("Hide");
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.hide();
- }
-
- @Override
- public void show() {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- writeEvent("Show");
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- super.show();
- }
-
- private void writeEvent(String tag) {
- try {
- mOut.writeUTF(tag);
- mOut.writeUTF(mWindow.getWindowTag().toString());
- writeSigil();
- } catch (Exception e) {
- RemoteEventTrace.logException(e);
- mService.disableSurfaceTrace();
- }
- }
-
- private void writeIntEvent(String tag, int... values) {
- try {
- mOut.writeUTF(tag);
- mOut.writeUTF(mWindow.getWindowTag().toString());
- for (int value: values) {
- mOut.writeInt(value);
- }
- writeSigil();
- } catch (Exception e) {
- RemoteEventTrace.logException(e);
- mService.disableSurfaceTrace();
- }
- }
-
- private void writeFloatEvent(String tag, float... values) {
- try {
- mOut.writeUTF(tag);
- mOut.writeUTF(mWindow.getWindowTag().toString());
- for (float value: values) {
- mOut.writeFloat(value);
- }
- writeSigil();
- } catch (Exception e) {
- RemoteEventTrace.logException(e);
- mService.disableSurfaceTrace();
- }
- }
-
- private void writeRectEvent(String tag, Rect value) {
- writeFloatEvent(tag, value.left, value.top, value.right, value.bottom);
- }
-
- private void writeSigil() throws Exception {
- mOut.write(RemoteEventTrace.sigil, 0, 4);
- }
-}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6356a35..f32c275 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -29,9 +29,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Slog;
@@ -50,9 +48,6 @@
import java.util.List;
import java.util.function.Consumer;
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_DEFAULT;
-import static android.app.AppOpsManager.OP_NONE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
@@ -68,8 +63,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -130,13 +123,6 @@
private final ArrayList<TaskStack> mTmpStackList = new ArrayList();
private final ArrayList<Integer> mTmpStackIds = new ArrayList<>();
- // State for the RemoteSurfaceTrace system used in testing. If this is enabled SurfaceControl
- // instances will be replaced with an instance that writes a binary representation of all
- // commands to mSurfaceTraceFd.
- boolean mSurfaceTraceEnabled;
- ParcelFileDescriptor mSurfaceTraceFd;
- RemoteEventTrace mRemoteEventTrace;
-
final WallpaperController mWallpaperController;
private final Handler mHandler;
@@ -427,12 +413,7 @@
void updateAppOpsState() {
forAllWindows((w) -> {
- if (w.mAppOp == OP_NONE) {
- return;
- }
- final int mode = mService.mAppOps.noteOpNoThrow(w.mAppOp, w.getOwningUid(),
- w.getOwningPackage());
- w.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT);
+ w.updateAppOpsState();
}, false /* traverseTopToBottom */);
}
@@ -814,7 +795,6 @@
mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
@@ -1014,30 +994,6 @@
}
}
- void enableSurfaceTrace(ParcelFileDescriptor pfd) {
- final FileDescriptor fd = pfd.getFileDescriptor();
- if (mSurfaceTraceEnabled) {
- disableSurfaceTrace();
- }
- mSurfaceTraceEnabled = true;
- mRemoteEventTrace = new RemoteEventTrace(mService, fd);
- mSurfaceTraceFd = pfd;
- for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent dc = mChildren.get(displayNdx);
- dc.enableSurfaceTrace(fd);
- }
- }
-
- void disableSurfaceTrace() {
- mSurfaceTraceEnabled = false;
- mRemoteEventTrace = null;
- mSurfaceTraceFd = null;
- for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent dc = mChildren.get(displayNdx);
- dc.disableSurfaceTrace();
- }
- }
-
void dumpDisplayContents(PrintWriter pw) {
pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
if (mService.mDisplayReady) {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 83baee1..76f5396 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,7 +33,6 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -60,21 +59,17 @@
/**
* @param animatable The object to animate.
* @param animationFinishedCallback Callback to invoke when an animation has finished running.
- * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
- * surfaces in WM. Can be implemented differently during testing.
*/
SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
- Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
+ WindowManagerService service) {
mAnimatable = animatable;
mService = service;
mAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
- addAfterPrepareSurfaces);
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
}
private OnAnimationFinishedCallback getFinishedCallback(
- @Nullable Runnable animationFinishedCallback,
- Consumer<Runnable> addAfterPrepareSurfaces) {
+ @Nullable Runnable animationFinishedCallback) {
return anim -> {
synchronized (mService.mWindowMap) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -83,30 +78,13 @@
return;
}
- // TODO: This should use pendingTransaction eventually, but right now things
- // happening on the animation finished callback are happening on the global
- // transaction.
- // For now we need to run this after it's guaranteed that the transaction that
- // reparents the surface onto the leash is executed already. Otherwise this may be
- // executed first, leading to surface loss, as the reparent operations wouldn't
- // be in order.
- addAfterPrepareSurfaces.accept(() -> {
- if (anim != mAnimation) {
- // Callback was from another animation - ignore.
- return;
- }
- final Transaction t = new Transaction();
- SurfaceControl.openTransaction();
- try {
- reset(t, true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
- }
- } finally {
- SurfaceControl.mergeToGlobalTransaction(t);
- SurfaceControl.closeTransaction();
- }
- });
+ if (anim != mAnimation) {
+ return;
+ }
+ reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
+ if (animationFinishedCallback != null) {
+ animationFinishedCallback.run();
+ }
}
};
}
@@ -282,15 +260,19 @@
final SurfaceControl surface = mAnimatable.getSurfaceControl();
final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+ boolean scheduleAnim = false;
+
// If the surface was destroyed, we don't care to reparent it back.
final boolean destroy = mLeash != null && surface != null && parent != null;
if (destroy) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
t.reparent(surface, parent.getHandle());
+ scheduleAnim = true;
}
mService.mAnimationTransferMap.remove(mAnimation);
if (mLeash != null && destroyLeash) {
- mAnimatable.destroyAfterPendingTransaction(mLeash);
+ t.destroy(mLeash);
+ scheduleAnim = true;
}
mLeash = null;
mAnimation = null;
@@ -298,6 +280,11 @@
// Make sure to inform the animatable after the leash was destroyed.
if (destroy) {
mAnimatable.onAnimationLeashDestroyed(t);
+ scheduleAnim = true;
+ }
+
+ if (scheduleAnim) {
+ mService.scheduleAnimationLocked();
}
}
@@ -379,13 +366,6 @@
void onAnimationLeashDestroyed(Transaction t);
/**
- * Destroy a given surface after executing {@link #getPendingTransaction}.
- *
- * @see WindowContainer#destroyAfterPendingTransaction
- */
- void destroyAfterPendingTransaction(SurfaceControl surface);
-
- /**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
*/
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ba08fcd2..b5d00a7 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -751,8 +751,11 @@
int getStackOutset() {
if (inPinnedWindowingMode()) {
final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
- return mService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP,
- displayMetrics);
+
+ // We multiply by two to match the client logic for converting view elevation
+ // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
+ return (int)Math.ceil(mService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP,
+ displayMetrics) * 2);
}
return 0;
}
@@ -824,6 +827,7 @@
}
updateDisplayInfo(bounds);
+ updateSurfaceBounds();
}
/**
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index a7d51f1..2873b6d 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -275,6 +275,8 @@
}
boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
+ int xOffset = 0;
+ int yOffset = 0;
boolean rawChanged = false;
// Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
// match the behavior of most Launchers
@@ -286,11 +288,8 @@
if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetX;
}
- boolean changed = wallpaperWin.mXOffset != offset;
- if (changed) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
- wallpaperWin.mXOffset = offset;
- }
+ xOffset = offset;
+
if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
wallpaperWin.mWallpaperX = wpx;
wallpaperWin.mWallpaperXStep = wpxs;
@@ -304,17 +303,16 @@
if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetY;
}
- if (wallpaperWin.mYOffset != offset) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
- changed = true;
- wallpaperWin.mYOffset = offset;
- }
+ yOffset = offset;
+
if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
wallpaperWin.mWallpaperY = wpy;
wallpaperWin.mWallpaperYStep = wpys;
rawChanged = true;
}
+ boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
+
if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
try {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 2ae5c7b..ddda027 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -74,10 +74,6 @@
for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
final WindowState wallpaper = mChildren.get(wallpaperNdx);
if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
- final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
- winAnimator.computeShownFrameLocked();
- // No need to lay out the windows - we can just set the wallpaper position directly.
- winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
// We only want to be synchronous with one wallpaper.
sync = false;
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 20349b9..ab10197 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -226,13 +226,6 @@
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
- final int numDisplays = mDisplayContentsAnimators.size();
- for (int i = 0; i < numDisplays; i++) {
- final int displayId = mDisplayContentsAnimators.keyAt(i);
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- dc.onPendingTransactionApplied();
- }
-
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
boolean doRequest = false;
if (mBulkUpdateParams != 0) {
@@ -266,7 +259,6 @@
}
mService.destroyPreservedSurfaceLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
executeAfterPrepareSurfacesRunnables();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1f7caff..b7525c0 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -109,8 +109,7 @@
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- service.mAnimator::addAfterPrepareSurfacesRunnable, service);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
}
@Override
@@ -286,8 +285,9 @@
}
if (mSurfaceControl != null) {
- destroyAfterPendingTransaction(mSurfaceControl);
+ getPendingTransaction().destroy(mSurfaceControl);
mSurfaceControl = null;
+ scheduleAnimation();
}
if (mParent != null) {
@@ -406,6 +406,10 @@
}
break;
default:
+ // TODO: Removing the child before reinserting requires the caller to provide a
+ // position that takes into account the removed child (if the index of the
+ // child < position, then the position should be adjusted). We should consider
+ // doing this adjustment here and remove any adjustments in the callers.
mChildren.remove(child);
mChildren.add(position, child);
}
@@ -1075,19 +1079,6 @@
return mSurfaceControl;
}
- /**
- * Destroy a given surface after executing mPendingTransaction. This is
- * largely a workaround for destroy not being part of transactions
- * rather than an intentional design, so please take care when
- * expanding use.
- */
- @Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- if (mParent != null) {
- mParent.destroyAfterPendingTransaction(surface);
- }
- }
-
@Override
public Transaction getPendingTransaction() {
return mPendingTransaction;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index be1aa46..0c6429a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -100,15 +100,15 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.WindowManagerServiceProto.APP_TRANSITION;
-import static com.android.server.wm.proto.WindowManagerServiceProto.DISPLAY_FROZEN;
-import static com.android.server.wm.proto.WindowManagerServiceProto.FOCUSED_APP;
-import static com.android.server.wm.proto.WindowManagerServiceProto.FOCUSED_WINDOW;
-import static com.android.server.wm.proto.WindowManagerServiceProto.INPUT_METHOD_WINDOW;
-import static com.android.server.wm.proto.WindowManagerServiceProto.LAST_ORIENTATION;
-import static com.android.server.wm.proto.WindowManagerServiceProto.POLICY;
-import static com.android.server.wm.proto.WindowManagerServiceProto.ROOT_WINDOW_CONTAINER;
-import static com.android.server.wm.proto.WindowManagerServiceProto.ROTATION;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.APP_TRANSITION;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.DISPLAY_FROZEN;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.FOCUSED_APP;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.FOCUSED_WINDOW;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.INPUT_METHOD_WINDOW;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.LAST_ORIENTATION;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.POLICY;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
+import static com.android.server.wm.proto.WindowManagerServiceDumpProto.ROTATION;
import android.Manifest;
import android.Manifest.permission;
@@ -822,9 +822,6 @@
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
synchronized (mWindowMap) {
- if (mRoot.mSurfaceTraceEnabled) {
- mRoot.mRemoteEventTrace.openSurfaceTransaction();
- }
SurfaceControl.openTransaction();
}
} finally {
@@ -843,9 +840,6 @@
try {
traceStateLocked(where);
} finally {
- if (mRoot.mSurfaceTraceEnabled) {
- mRoot.mRemoteEventTrace.closeSurfaceTransaction();
- }
SurfaceControl.closeTransaction();
}
}
@@ -1384,14 +1378,8 @@
win.attach();
mWindowMap.put(client.asBinder(), win);
- if (win.mAppOp != AppOpsManager.OP_NONE) {
- int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
- win.getOwningPackage());
- if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
- (startOpResult != AppOpsManager.MODE_DEFAULT)) {
- win.setAppOpVisibilityLw(false);
- }
- }
+
+ win.initAppOpsState();
final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
@@ -1595,30 +1583,6 @@
return false;
}
- @Override
- public void enableSurfaceTrace(ParcelFileDescriptor pfd) {
- final int callingUid = Binder.getCallingUid();
- if (callingUid != SHELL_UID && callingUid != ROOT_UID) {
- throw new SecurityException("Only shell can call enableSurfaceTrace");
- }
-
- synchronized (mWindowMap) {
- mRoot.enableSurfaceTrace(pfd);
- }
- }
-
- @Override
- public void disableSurfaceTrace() {
- final int callingUid = Binder.getCallingUid();
- if (callingUid != SHELL_UID && callingUid != ROOT_UID &&
- callingUid != SYSTEM_UID) {
- throw new SecurityException("Only shell can call disableSurfaceTrace");
- }
- synchronized (mWindowMap) {
- mRoot.disableSurfaceTrace();
- }
- }
-
/**
* Set mScreenCaptureDisabled for specific user
*/
@@ -1656,9 +1620,8 @@
void postWindowRemoveCleanupLocked(WindowState win) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win);
mWindowMap.remove(win.mClient.asBinder());
- if (win.mAppOp != AppOpsManager.OP_NONE) {
- mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
- }
+
+ win.resetAppOpsState();
if (mCurrentFocus == null) {
mWinRemovedSinceNullFocus.add(win);
@@ -2125,6 +2088,10 @@
win.setLastReportedMergedConfiguration(mergedConfiguration);
+ // Update the last inset values here because the values are sent back to the client.
+ // The last inset values represent the last client state.
+ win.updateLastInsetValues();
+
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
outContentInsets.set(win.mContentInsets);
@@ -2697,7 +2664,6 @@
IRecentsAnimationRunner recentsAnimationRunner,
RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId) {
synchronized (mWindowMap) {
- cancelRecentsAnimation();
mRecentsAnimationController = new RecentsAnimationController(this,
recentsAnimationRunner, callbacks, displayId);
mRecentsAnimationController.initialize();
@@ -2722,12 +2688,12 @@
}
public void cancelRecentsAnimation() {
- synchronized (mWindowMap) {
- if (mRecentsAnimationController != null) {
- // This call will call through to cleanupAnimation() below after the animation is
- // canceled
- mRecentsAnimationController.cancelAnimation();
- }
+ // Note: Do not hold the WM lock, this will lock appropriately in the call which also
+ // calls through to AM/RecentsAnimation.onAnimationFinished()
+ if (mRecentsAnimationController != null) {
+ // This call will call through to cleanupAnimation() below after the animation is
+ // canceled
+ mRecentsAnimationController.cancelAnimation();
}
}
@@ -2778,6 +2744,13 @@
mDockedStackCreateBounds = bounds;
}
+ public void checkSplitScreenMinimizedChanged(boolean animate) {
+ synchronized (mWindowMap) {
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ displayContent.getDockedDividerController().checkMinimizeChanged(animate);
+ }
+ }
+
public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
@@ -6184,7 +6157,7 @@
/**
* Write to a protocol buffer output stream. Protocol buffer message definition is at
- * {@link com.android.server.wm.proto.WindowManagerServiceProto}.
+ * {@link com.android.server.wm.proto.WindowManagerServiceDumpProto}.
*
* @param proto Stream to write the WindowContainer object to.
* @param trim If true, reduce the amount of data written.
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index e24c393..ab139db 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -74,8 +74,6 @@
return runSetScreenCapture(pw);
case "dismiss-keyguard":
return runDismissKeyguard(pw);
- case "surface-trace":
- return runSurfaceTrace(pw);
case "tracing":
// XXX this should probably be changed to use openFileForSystem() to create
// the output trace file, so the shell gets the correct semantics for where
@@ -235,46 +233,6 @@
return 0;
}
- private int runSurfaceTrace(PrintWriter pw) throws RemoteException {
- final ParcelFileDescriptor pfd;
- try {
- pfd = ParcelFileDescriptor.dup(getOutFileDescriptor());
- } catch (IOException e) {
- getErrPrintWriter().println("Unable to dup output stream: " + e.getMessage());
- return -1;
- }
- mInternal.enableSurfaceTrace(pfd);
-
- // Read input until an explicit quit command is sent or the stream is closed (meaning
- // the user killed the command).
- try {
- InputStream input = getRawInputStream();
- InputStreamReader converter = new InputStreamReader(input);
- BufferedReader in = new BufferedReader(converter);
- String line;
-
- while ((line = in.readLine()) != null) {
- if (line.length() <= 0) {
- // no-op
- } else if ("q".equals(line) || "quit".equals(line)) {
- break;
- } else {
- pw.println("Invalid command: " + line);
- }
- }
- } catch (IOException e) {
- e.printStackTrace(pw);
- } finally {
- mInternal.disableSurfaceTrace();
- try {
- pfd.close();
- } catch (IOException e) {
- }
- }
-
- return 0;
- }
-
private int parseDimension(String s) throws NumberFormatException {
if (s.endsWith("px")) {
return Integer.parseInt(s.substring(0, s.length() - 2));
@@ -311,8 +269,6 @@
pw.println(" Enable or disable screen capture.");
pw.println(" dismiss-keyguard");
pw.println(" Dismiss the keyguard, prompting user for auth if necessary.");
- pw.println(" surface-trace");
- pw.println(" Log surface commands to stdout in a binary format.");
if (!IS_USER) {
pw.println(" tracing (start | stop)");
pw.println(" Start or stop window tracing.");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b706096..c5b270e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -17,6 +17,9 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.OP_NONE;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -138,7 +141,6 @@
import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT;
import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT;
import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH;
-import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION;
import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS;
import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
@@ -298,12 +300,6 @@
private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
/**
- * Actual position of the surface shown on-screen (may be modified by animation). These are
- * in the screen's coordinate space (WITH the compatibility scale applied).
- */
- final Point mShownPosition = new Point();
-
- /**
* Insets that determine the actually visible area. These are in the application's
* coordinate space (without compatibility scale applied).
*/
@@ -462,10 +458,6 @@
int mWallpaperDisplayOffsetX = Integer.MIN_VALUE;
int mWallpaperDisplayOffsetY = Integer.MIN_VALUE;
- // Wallpaper windows: pixels offset based on above variables.
- int mXOffset;
- int mYOffset;
-
/**
* This is set after IWindowSession.relayout() has been called at
* least once for the window. It allows us to detect the situation
@@ -771,8 +763,6 @@
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
- mXOffset = 0;
- mYOffset = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
@@ -1138,11 +1128,6 @@
}
@Override
- public Point getShownPositionLw() {
- return mShownPosition;
- }
-
- @Override
public Rect getDisplayFrameLw() {
return mDisplayFrame;
}
@@ -2571,7 +2556,7 @@
}
}
- public void setAppOpVisibilityLw(boolean state) {
+ private void setAppOpVisibilityLw(boolean state) {
if (mAppOpVisibility != state) {
mAppOpVisibility = state;
if (state) {
@@ -2588,6 +2573,49 @@
}
}
+ void initAppOpsState() {
+ if (mAppOp == OP_NONE || !mAppOpVisibility) {
+ return;
+ }
+ // If the app op was MODE_DEFAULT we would have checked the permission
+ // and add the window only if the permission was granted. Therefore, if
+ // the mode is MODE_DEFAULT we want the op to succeed as the window is
+ // shown.
+ final int mode = mService.mAppOps.startOpNoThrow(mAppOp,
+ getOwningUid(), getOwningPackage(), true);
+ if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) {
+ setAppOpVisibilityLw(false);
+ }
+ }
+
+ void resetAppOpsState() {
+ if (mAppOp != OP_NONE && mAppOpVisibility) {
+ mService.mAppOps.finishOp(mAppOp, getOwningUid(), getOwningPackage());
+ }
+ }
+
+ void updateAppOpsState() {
+ if (mAppOp == OP_NONE) {
+ return;
+ }
+ final int uid = getOwningUid();
+ final String packageName = getOwningPackage();
+ if (mAppOpVisibility) {
+ // There is a race between the check and the finish calls but this is fine
+ // as this would mean we will get another change callback and will reconcile.
+ int mode = mService.mAppOps.checkOpNoThrow(mAppOp, uid, packageName);
+ if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) {
+ mService.mAppOps.finishOp(mAppOp, uid, packageName);
+ setAppOpVisibilityLw(false);
+ }
+ } else {
+ final int mode = mService.mAppOps.startOpNoThrow(mAppOp, uid, packageName);
+ if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
+ setAppOpVisibilityLw(true);
+ }
+ }
+ }
+
public void hidePermanentlyLw() {
if (!mPermanentlyHidden) {
mPermanentlyHidden = true;
@@ -3136,7 +3164,6 @@
mContentInsets.writeToProto(proto, CONTENT_INSETS);
mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS);
mSurfacePosition.writeToProto(proto, SURFACE_POSITION);
- mShownPosition.writeToProto(proto, SHOWN_POSITION);
mWinAnimator.writeToProto(proto, ANIMATOR);
proto.write(ANIMATING_EXIT, mAnimatingExit);
for (int i = 0; i < mChildren.size(); i++) {
@@ -3252,10 +3279,6 @@
pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded);
}
- if (mXOffset != 0 || mYOffset != 0) {
- pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
- pw.print(" y="); pw.println(mYOffset);
- }
if (dumpAll) {
pw.print(prefix); pw.print("mGivenContentInsets=");
mGivenContentInsets.printShortString(pw);
@@ -3274,7 +3297,6 @@
pw.println(getLastReportedConfiguration());
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
- pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
if (dumpAll) {
@@ -4013,7 +4035,9 @@
final boolean hasSurface = mWinAnimator.hasSurface();
if (hasSurface) {
- mWinAnimator.hide("onExitAnimationDone");
+ // Use pendingTransaction here so hide is done the same transaction as the other
+ // animations when exiting
+ mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
}
// If we have an app token, we ask it to destroy the surface for us, so that it can take
@@ -4195,9 +4219,8 @@
final int width = mFrame.width();
final int height = mFrame.height();
- // Compute the offset of the window in relation to the decor rect.
- final int left = mXOffset + mFrame.left;
- final int top = mYOffset + mFrame.top;
+ final int left = mFrame.left;
+ final int top = mFrame.top;
// Initialize the decor rect to the entire frame.
if (isDockedResizing()) {
@@ -4299,14 +4322,9 @@
// When we change the Surface size, in scenarios which may require changing
// the surface position in sync with the resize, we use a preserved surface
// so we can freeze it while waiting for the client to report draw on the newly
- // sized surface. Don't preserve surfaces if the insets change while animating the pinned
- // stack since it can lead to issues if a new surface is created while calculating the
- // scale for the animation using the source hint rect
- // (see WindowStateAnimator#setSurfaceBoundariesLocked()).
- if (isDragResizeChanged()
- || (surfaceInsetsChanging() && !inPinnedWindowingMode())) {
- mLastSurfaceInsets.set(mAttrs.surfaceInsets);
-
+ // sized surface. At the moment this logic is only in place for switching
+ // in and out of the big surface for split screen resize.
+ if (isDragResizeChanged()) {
setDragResizing();
// We can only change top level windows to the full-screen surface when
// resizing (as we only have one full-screen surface). So there is no need
@@ -4391,8 +4409,8 @@
float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
- int x = mSurfacePosition.x + mShownPosition.x;
- int y = mSurfacePosition.y + mShownPosition.y;
+ int x = mSurfacePosition.x;
+ int y = mSurfacePosition.y;
// If changed, also adjust transformFrameToSurfacePosition
final WindowContainer parent = getParent();
@@ -4554,9 +4572,16 @@
}
transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
+
if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) {
t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
+ if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) {
+ mLastSurfaceInsets.set(mAttrs.surfaceInsets);
+ t.deferTransactionUntil(mSurfaceControl,
+ mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
+ mAttrs.frameNumber);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9ce0537..13f05e0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -164,6 +164,8 @@
private boolean mAnimationStartDelayed;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
/** The pixel format of the underlying SurfaceControl */
int mSurfaceFormat;
@@ -209,6 +211,12 @@
float mExtraHScale = (float) 1.0;
float mExtraVScale = (float) 1.0;
+ // An offset in pixel of the surface contents from the window position. Used for Wallpaper
+ // to provide the effect of scrolling within a large surface. We just use these values as
+ // a cache.
+ int mXOffset = 0;
+ int mYOffset = 0;
+
private final Rect mTmpSize = new Rect();
private final SurfaceControl.Transaction mReparentTransaction = new SurfaceControl.Transaction();
@@ -280,16 +288,21 @@
}
}
- void hide(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (!mLastHidden) {
//dump();
mLastHidden = true;
if (mSurfaceController != null) {
- mSurfaceController.hideInTransaction(reason);
+ mSurfaceController.hide(transaction, reason);
}
}
}
+ void hide(String reason) {
+ hide(mTmpTransaction, reason);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+ }
+
boolean finishDrawingLocked() {
final boolean startingWindow =
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -438,7 +451,7 @@
flags |= SurfaceControl.SECURE;
}
- mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
+ mTmpSize.set(0, 0, 0, 0);
calculateSurfaceBounds(w, attrs);
final int width = mTmpSize.width();
final int height = mTmpSize.height();
@@ -679,8 +692,8 @@
// WindowState.prepareSurfaces expands for surface insets (in order they don't get
// clipped by the WindowState surface), so we need to go into the other direction here.
- tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
- mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
+ tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left,
+ mWin.mAttrs.surfaceInsets.top);
// "convert" it into SurfaceFlinger's format
@@ -695,9 +708,6 @@
mDtDx = tmpFloats[Matrix.MSKEW_Y];
mDtDy = tmpFloats[Matrix.MSKEW_X];
mDsDy = tmpFloats[Matrix.MSCALE_Y];
- float x = tmpFloats[Matrix.MTRANS_X];
- float y = tmpFloats[Matrix.MTRANS_Y];
- mWin.mShownPosition.set(Math.round(x), Math.round(y));
// Now set the alpha... but because our current hardware
// can't do alpha transformation on a non-opaque surface,
@@ -707,8 +717,7 @@
mShownAlpha = mAlpha;
if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
- || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
- && x == frame.left && y == frame.top))) {
+ || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
//Slog.i(TAG_WM, "Applying alpha transform");
if (screenAnimation) {
mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
@@ -738,10 +747,6 @@
TAG, "computeShownFrameLocked: " + this +
" not attached, mAlpha=" + mAlpha);
- // WindowState.prepareSurfaces expands for surface insets (in order they don't get
- // clipped by the WindowState surface), so we need to go into the other direction here.
- mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
- mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
mShownAlpha = mAlpha;
mHaveMatrix = false;
mDsDx = mWin.mGlobalScale;
@@ -792,12 +797,6 @@
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
+ " fullscreen=" + fullscreen);
- if (isFreeformResizing && !w.isChildWindow()) {
- // For freeform resizing non child windows, we are using the big surface positioned
- // at 0,0. Thus we must express the crop in that coordinate space.
- clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
- }
-
w.expandForSurfaceInsets(clipRect);
// The clip rect was generated assuming (0,0) as the window origin,
@@ -834,7 +833,7 @@
final LayoutParams attrs = mWin.getAttrs();
final Task task = w.getTask();
- mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
+ mTmpSize.set(0, 0, 0, 0);
calculateSurfaceBounds(w, attrs);
mExtraHScale = (float) 1.0;
@@ -870,17 +869,19 @@
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
+ final Rect insets = attrs.surfaceInsets;
+
if (isForceScaled()) {
- int hInsets = attrs.surfaceInsets.left + attrs.surfaceInsets.right;
- int vInsets = attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
+ int hInsets = insets.left + insets.right;
+ int vInsets = insets.top + insets.bottom;
float surfaceContentWidth = surfaceWidth - hInsets;
float surfaceContentHeight = surfaceHeight - vInsets;
if (!mForceScaleUntilResize) {
mSurfaceController.forceScaleableInTransaction(true);
}
- int posX = mTmpSize.left;
- int posY = mTmpSize.top;
+ int posX = 0;
+ int posY = 0;
task.mStack.getDimBounds(mTmpStackBounds);
boolean allowStretching = false;
@@ -927,9 +928,19 @@
posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left);
posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top);
- // Always clip to the stack bounds since the surface can be larger with the current
- // scale
- clipRect = null;
+ // In pinned mode the clip rectangle applied to us by our stack has been
+ // expanded outwards to allow for shadows. However in case of source bounds set
+ // we need to crop to within the surface. The code above has scaled and positioned
+ // the surface to fit the unexpanded stack bounds, but now we need to reapply
+ // the cropping that the stack would have applied if it weren't expanded. This
+ // can be different in each direction based on the source bounds.
+ clipRect = mTmpClipRect;
+ clipRect.set((int)((insets.left + mTmpSourceBounds.left) * tw),
+ (int)((insets.top + mTmpSourceBounds.top) * th),
+ insets.left + (int)(surfaceWidth
+ - (tw* (surfaceWidth - mTmpSourceBounds.right))),
+ insets.top + (int)(surfaceHeight
+ - (th * (surfaceHeight - mTmpSourceBounds.bottom))));
} else {
// We want to calculate the scaling based on the content area, not based on
// the entire surface, so that we scale in sync with windows that don't have insets.
@@ -955,8 +966,8 @@
// non inset content at the same position, we have to shift the whole window
// forward. Likewise for scaling up, we've increased this distance, and we need
// to shift by a negative number to compensate.
- posX += attrs.surfaceInsets.left * (1 - mExtraHScale);
- posY += attrs.surfaceInsets.top * (1 - mExtraVScale);
+ posX += insets.left * (1 - mExtraHScale);
+ posY += insets.top * (1 - mExtraVScale);
mSurfaceController.setPositionInTransaction((float) Math.floor(posX),
(float) Math.floor(posY), recoveringMemory);
@@ -970,8 +981,7 @@
mForceScaleUntilResize = true;
} else {
if (!w.mSeamlesslyRotated) {
- mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
- recoveringMemory);
+ mSurfaceController.setPositionInTransaction(0, 0, recoveringMemory);
}
}
@@ -1139,24 +1149,26 @@
mSurfaceController.setTransparentRegionHint(region);
}
- void setWallpaperOffset(Point shownPosition) {
- final LayoutParams attrs = mWin.getAttrs();
- final int left = shownPosition.x - attrs.surfaceInsets.left;
- final int top = shownPosition.y - attrs.surfaceInsets.top;
+ boolean setWallpaperOffset(int dx, int dy) {
+ if (mXOffset == dx && mYOffset == dy) {
+ return false;
+ }
+ mXOffset = dx;
+ mYOffset = dy;
try {
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
mService.openSurfaceTransaction();
- mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
- mWin.mFrame.top + top, false);
+ mSurfaceController.setPositionInTransaction(dx, dy, false);
applyCrop(null, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
- + " pos=(" + left + "," + top + ")", e);
+ + " pos=(" + dx + "," + dy + ")", e);
} finally {
mService.closeSurfaceTransaction("setWallpaperOffset");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION setWallpaperOffset");
+ return true;
}
}
@@ -1451,22 +1463,6 @@
DsDy * w.mVScale, false);
}
- void enableSurfaceTrace(FileDescriptor fd) {
- if (mSurfaceController != null) {
- mSurfaceController.installRemoteTrace(fd);
- }
- }
-
- void disableSurfaceTrace() {
- if (mSurfaceController != null) {
- try {
- mSurfaceController.removeRemoteTrace();
- } catch (ClassCastException e) {
- Slog.e(TAG, "Disable surface trace for " + this + " but its not enabled");
- }
- }
- }
-
/** The force-scaled state for a given window can persist past
* the state for it's stack as the windows complete resizing
* independently of one another.
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 554a600..9d6f8f7 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -86,6 +86,8 @@
private final int mWindowType;
private final Session mWindowSession;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
@@ -110,21 +112,8 @@
.setMetadata(windowType, ownerUid);
mSurfaceControl = b.build();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-
- if (mService.mRoot.mSurfaceTraceEnabled) {
- installRemoteTrace(mService.mRoot.mSurfaceTraceFd.getFileDescriptor());
- }
}
- void installRemoteTrace(FileDescriptor fd) {
- mSurfaceControl = new RemoteSurfaceTrace(fd, mSurfaceControl, mAnimator.mWin);
- }
-
- void removeRemoteTrace() {
- mSurfaceControl = new SurfaceControl(mSurfaceControl);
- }
-
-
private void logSurface(String msg, RuntimeException where) {
String str = " SURFACE " + msg + ": " + title;
if (where != null) {
@@ -148,21 +137,23 @@
}
}
- void hideInTransaction(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
mAnimator.destroyPreservedSurfaceLocked();
- updateVisibility();
+ if (mSurfaceShown) {
+ hideSurface(transaction);
+ }
}
- private void hideSurface() {
+ private void hideSurface(SurfaceControl.Transaction transaction) {
if (mSurfaceControl == null) {
return;
}
setShown(false);
try {
- mSurfaceControl.hide();
+ transaction.hide(mSurfaceControl);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + this);
}
@@ -421,7 +412,8 @@
private boolean updateVisibility() {
if (mHiddenForCrop || mHiddenForOtherReasons) {
if (mSurfaceShown) {
- hideSurface();
+ hideSurface(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 66c7293..4179590 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -21,6 +21,7 @@
import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
@@ -102,7 +103,6 @@
}
private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
- private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
private final Runnable mPerformSurfacePlacement;
@@ -608,6 +608,10 @@
if (transit == TRANSIT_NONE) {
return TRANSIT_NONE;
}
+ // Never update the transition for the wallpaper if we are just docking from recents
+ if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ return TRANSIT_DOCK_TASK_FROM_RECENTS;
+ }
// if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
@@ -697,25 +701,6 @@
}
}
- /**
- * Puts the {@param surface} into a pending list to be destroyed after the current transaction
- * has been committed.
- */
- void destroyAfterTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
- */
- void destroyPendingSurfaces() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 3557dc9..4020a52 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -172,4 +172,8 @@
public long forceSecurityLogs() {
return 0;
}
+
+ @Override
+ public void setDefaultSmsApplication(ComponentName admin, String packageName) {
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0a6ff6d..6a468b1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -160,6 +160,7 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -206,6 +207,7 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
@@ -219,6 +221,7 @@
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.UserRestrictionsUtils;
+import com.android.server.storage.DeviceStorageMonitorInternal;
import com.google.android.collect.Sets;
@@ -8217,6 +8220,16 @@
}
@Override
+ public void setDefaultSmsApplication(ComponentName admin, String packageName) {
+ Preconditions.checkNotNull(admin, "ComponentName is null");
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ mInjector.binderWithCleanCallingIdentity(() ->
+ SmsApplication.setDefaultApplication(packageName, mContext));
+ }
+
+ @Override
public boolean setApplicationRestrictionsManagingPackage(ComponentName admin,
String packageName) {
try {
@@ -8873,13 +8886,40 @@
final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
&& UserManager.isDeviceInDemoMode(mContext);
final boolean leaveAllSystemAppsEnabled = (flags & LEAVE_ALL_SYSTEM_APPS_ENABLED) != 0;
+ final int targetSdkVersion;
+
// Create user.
UserHandle user = null;
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ final int callingUid = mInjector.binderGetCallingUid();
final long id = mInjector.binderClearCallingIdentity();
try {
+ targetSdkVersion = mInjector.getPackageManagerInternal().getUidTargetSdkVersion(
+ callingUid);
+
+ // Return detail error code for checks inside
+ // UserManagerService.createUserInternalUnchecked.
+ DeviceStorageMonitorInternal deviceStorageMonitorInternal =
+ LocalServices.getService(DeviceStorageMonitorInternal.class);
+ if (deviceStorageMonitorInternal.isMemoryLow()) {
+ if (targetSdkVersion >= Build.VERSION_CODES.P) {
+ throw new ServiceSpecificException(
+ UserManager.USER_OPERATION_ERROR_LOW_STORAGE, "low device storage");
+ } else {
+ return null;
+ }
+ }
+ if (!mUserManager.canAddMoreUsers()) {
+ if (targetSdkVersion >= Build.VERSION_CODES.P) {
+ throw new ServiceSpecificException(
+ UserManager.USER_OPERATION_ERROR_MAX_USERS, "user limit reached");
+ } else {
+ return null;
+ }
+ }
+
int userInfoFlags = 0;
if (ephemeral) {
userInfoFlags |= UserInfo.FLAG_EPHEMERAL;
@@ -8903,7 +8943,12 @@
}
}
if (user == null) {
- return null;
+ if (targetSdkVersion >= Build.VERSION_CODES.P) {
+ throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN,
+ "failed to create user");
+ } else {
+ return null;
+ }
}
final int userHandle = user.getIdentifier();
@@ -8949,7 +8994,12 @@
return user;
} catch (Throwable re) {
mUserManager.removeUser(userHandle);
- return null;
+ if (targetSdkVersion >= Build.VERSION_CODES.P) {
+ throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN,
+ re.getMessage());
+ } else {
+ return null;
+ }
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -9030,24 +9080,24 @@
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
Log.w(LOG_TAG, "Managed profile cannot be started in background");
- return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
+ return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
final long id = mInjector.binderClearCallingIdentity();
try {
if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
Log.w(LOG_TAG, "Cannot start more users in background");
- return DevicePolicyManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
+ return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
}
if (mInjector.getIActivityManager().startUserInBackground(userId)) {
- return DevicePolicyManager.USER_OPERATION_SUCCESS;
+ return UserManager.USER_OPERATION_SUCCESS;
} else {
- return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
}
} catch (RemoteException e) {
// Same process, should not happen.
- return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -9065,7 +9115,7 @@
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
Log.w(LOG_TAG, "Managed profile cannot be stopped");
- return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
+ return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
return stopUserUnchecked(userId);
@@ -9086,7 +9136,7 @@
if (isManagedProfile(callingUserId)) {
Log.w(LOG_TAG, "Managed profile cannot be logout");
- return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
+ return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
final long id = mInjector.binderClearCallingIdentity();
@@ -9094,11 +9144,11 @@
if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) {
Log.w(LOG_TAG, "Failed to switch to primary user");
// This should never happen as target user is UserHandle.USER_SYSTEM
- return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
}
} catch (RemoteException e) {
// Same process, should not happen.
- return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -9111,15 +9161,15 @@
try {
switch (mInjector.getIActivityManager().stopUser(userId, true /*force*/, null)) {
case ActivityManager.USER_OP_SUCCESS:
- return DevicePolicyManager.USER_OPERATION_SUCCESS;
+ return UserManager.USER_OPERATION_SUCCESS;
case ActivityManager.USER_OP_IS_CURRENT:
- return DevicePolicyManager.USER_OPERATION_ERROR_CURRENT_USER;
+ return UserManager.USER_OPERATION_ERROR_CURRENT_USER;
default:
- return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
}
} catch (RemoteException e) {
// Same process, should not happen.
- return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN;
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5b5de0e..ccfadc0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -23,6 +23,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
@@ -331,6 +332,8 @@
// The system server should never make non-oneway calls
Binder.setWarnOnBlocking(true);
+ // The system server should always load safe labels
+ PackageItemInfo.setForceSafeLabels(true);
// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
SQLiteCompatibilityWalFlags.init(null);
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index 8372778..f603a09 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -19,6 +19,7 @@
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
+
import static com.android.server.backup.testing.TransportData.backupTransport;
import static com.google.common.truth.Truth.assertThat;
@@ -103,18 +104,10 @@
@Config(
manifest = Config.NONE,
sdk = 26,
- shadows = {
- ShadowBackupDataInput.class,
- ShadowBackupDataOutput.class,
- ShadowQueuedWork.class
- }
+ shadows = {ShadowBackupDataInput.class, ShadowBackupDataOutput.class, ShadowQueuedWork.class}
)
@SystemLoaderPackages({"com.android.server.backup", "android.app.backup"})
-@SystemLoaderClasses({
- IBackupTransport.class,
- IBackupAgent.class,
- PackageInfo.class
-})
+@SystemLoaderClasses({IBackupTransport.class, IBackupAgent.class, PackageInfo.class})
@Presubmit
public class PerformBackupTaskTest {
private static final String PACKAGE_1 = "com.example.package1";
@@ -581,6 +574,7 @@
return task;
}
+ /** Matches {@link PackageInfo} whose package name is {@code packageName}. */
private static ArgumentMatcher<PackageInfo> packageInfo(String packageName) {
// We have to test for packageInfo nulity because of Mockito's own stubbing with argThat().
// E.g. if you do:
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 02514b8..7d1b6c86 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -42,6 +42,7 @@
import android.annotation.Nullable;
import android.app.backup.BackupManager;
+import android.app.backup.BackupTransport;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -86,18 +87,11 @@
private static final String PACKAGE_A = "some.package.a";
private static final String PACKAGE_B = "some.package.b";
- /**
- * GMSCore depends on this constant so we define it here on top of the definition in {@link
- * TransportManager} to verify this extra is passed
- */
- private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";
-
@Mock private OnTransportRegisteredListener mListener;
@Mock private TransportClientManager mTransportClientManager;
private TransportData mTransportA1;
private TransportData mTransportA2;
private TransportData mTransportB1;
-
private ShadowPackageManager mShadowPackageManager;
private Context mContext;
@@ -210,7 +204,8 @@
verify(mTransportClientManager)
.getTransportClient(
eq(mTransportA1.getTransportComponent()),
- argThat(bundle -> bundle.getBoolean(EXTRA_TRANSPORT_REGISTRATION)),
+ argThat(bundle ->
+ bundle.getBoolean(BackupTransport.EXTRA_TRANSPORT_REGISTRATION)),
anyString());
}
diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index 4ac00f0..03792b1 100644
--- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -25,8 +25,10 @@
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
@@ -37,8 +39,11 @@
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.RestoreSet;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.os.Looper;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import com.android.server.EventLogTags;
@@ -51,7 +56,9 @@
import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderPackages;
import com.android.server.testing.shadows.ShadowEventLog;
+import com.android.server.testing.shadows.ShadowPerformUnifiedRestoreTask;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,15 +67,25 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowBinder;
import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.shadows.ShadowPackageManager;
+
+import java.util.ArrayDeque;
@RunWith(FrameworkRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, sdk = 26, shadows = ShadowEventLog.class)
+@Config(
+ manifest = Config.NONE,
+ sdk = 26,
+ shadows = {ShadowEventLog.class, ShadowPerformUnifiedRestoreTask.class, ShadowBinder.class}
+)
@SystemLoaderPackages({"com.android.server.backup"})
@Presubmit
public class ActiveRestoreSessionTest {
private static final String PACKAGE_1 = "com.example.package1";
private static final String PACKAGE_2 = "com.example.package2";
+ public static final long TOKEN_1 = 1L;
+ public static final long TOKEN_2 = 2L;
@Mock private BackupManagerService mBackupManagerService;
@Mock private TransportManager mTransportManager;
@@ -80,6 +97,7 @@
private TransportData mTransport;
private RestoreSet mRestoreSet1;
private RestoreSet mRestoreSet2;
+ private ShadowPackageManager mShadowPackageManager;
@Before
public void setUp() throws Exception {
@@ -87,12 +105,14 @@
mTransport = backupTransport();
- mRestoreSet1 = new RestoreSet("name1", "device1", 1L);
- mRestoreSet2 = new RestoreSet("name2", "device2", 2L);
+ mRestoreSet1 = new RestoreSet("name1", "device1", TOKEN_1);
+ mRestoreSet2 = new RestoreSet("name2", "device2", TOKEN_2);
Application application = RuntimeEnvironment.application;
mShadowApplication = shadowOf(application);
+ mShadowPackageManager = shadowOf(application.getPackageManager());
+
Looper backupLooper = startBackupThreadAndGetLooper();
mShadowBackupLooper = shadowOf(backupLooper);
BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
@@ -106,6 +126,12 @@
application.getPackageManager(),
backupHandler,
mWakeLock);
+ when(mBackupManagerService.getPendingRestores()).thenReturn(new ArrayDeque<>());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ ShadowPerformUnifiedRestoreTask.reset();
}
@Test
@@ -193,12 +219,348 @@
assertThat(mWakeLock.isHeld()).isFalse();
}
+ @Test
+ public void testRestoreAll() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ doCallRealMethod().when(mBackupManagerService).setRestoreInProgress(anyBoolean());
+ when(mBackupManagerService.isRestoreInProgress()).thenCallRealMethod();
+ TransportMock transportMock = setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor);
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(result).isEqualTo(0);
+ verify(mTransportManager)
+ .disposeOfTransportClient(eq(transportMock.transportClient), any());
+ assertThat(mWakeLock.isHeld()).isFalse();
+ assertThat(mBackupManagerService.isRestoreInProgress()).isFalse();
+ // Verify it created the task properly
+ ShadowPerformUnifiedRestoreTask shadowTask =
+ ShadowPerformUnifiedRestoreTask.getLastCreated();
+ assertThat(shadowTask.isFullSystemRestore()).isTrue();
+ assertThat(shadowTask.getFilterSet()).isNull();
+ assertThat(shadowTask.getPackage()).isNull();
+ }
+
+ @Test
+ public void testRestoreAll_whenNoRestoreSets() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
+
+ int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor);
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestoreAll_whenSinglePackageSession() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1);
+
+ int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor);
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestoreAll_whenSessionEnded() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+ restoreSession.endRestoreSession();
+ mShadowBackupLooper.runToEndOfTasks();
+
+ expectThrows(
+ IllegalStateException.class,
+ () -> restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor));
+ }
+
+ @Test
+ public void testRestoreAll_whenTransportNotRegistered() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport.unregistered());
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor);
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestoreAll_whenRestoreInProgress_addsToPendingRestores() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ when(mBackupManagerService.isRestoreInProgress()).thenReturn(true);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor);
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(result).isEqualTo(0);
+ assertThat(mBackupManagerService.getPendingRestores()).hasSize(1);
+ }
+
+ @Test
+ public void testRestoreSome_for2Packages() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ TransportMock transportMock = setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ int result =
+ restoreSession.restoreSome(
+ TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2});
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(result).isEqualTo(0);
+ verify(mTransportManager)
+ .disposeOfTransportClient(eq(transportMock.transportClient), any());
+ assertThat(mWakeLock.isHeld()).isFalse();
+ assertThat(mBackupManagerService.isRestoreInProgress()).isFalse();
+ ShadowPerformUnifiedRestoreTask shadowTask =
+ ShadowPerformUnifiedRestoreTask.getLastCreated();
+ assertThat(shadowTask.getFilterSet()).asList().containsExactly(PACKAGE_1, PACKAGE_2);
+ assertThat(shadowTask.getPackage()).isNull();
+ }
+
+ @Test
+ public void testRestoreSome_for2Packages_createsSystemRestoreTask() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ restoreSession.restoreSome(
+ TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2});
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore()).isTrue();
+ }
+
+ @Test
+ public void testRestoreSome_for1Package() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+
+ mShadowBackupLooper.runToEndOfTasks();
+ ShadowPerformUnifiedRestoreTask shadowTask =
+ ShadowPerformUnifiedRestoreTask.getLastCreated();
+ assertThat(shadowTask.getFilterSet()).asList().containsExactly(PACKAGE_1);
+ assertThat(shadowTask.getPackage()).isNull();
+ }
+
+ @Test
+ public void testRestoreSome_for1Package_createsNonSystemRestoreTask() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore())
+ .isFalse();
+ }
+
+ @Test
+ public void testRestoreSome_whenNoRestoreSets() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
+
+ int result =
+ restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestoreSome_whenSinglePackageSession() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1);
+
+ int result =
+ restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_2});
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestoreSome_whenSessionEnded() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+ restoreSession.endRestoreSession();
+ mShadowBackupLooper.runToEndOfTasks();
+
+ expectThrows(
+ IllegalStateException.class,
+ () ->
+ restoreSession.restoreSome(
+ TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1}));
+ }
+
+ @Test
+ public void testRestoreSome_whenTransportNotRegistered() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpTransport(mTransport.unregistered());
+ IRestoreSession restoreSession =
+ createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
+
+ int result =
+ restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestorePackage_whenCallerIsPackage() throws Exception {
+ // No need for BACKUP permission in this case
+ mShadowApplication.denyPermissions(android.Manifest.permission.BACKUP);
+ ShadowBinder.setCallingUid(1);
+ setUpPackage(PACKAGE_1, /* uid */ 1);
+ when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1);
+ TransportMock transportMock = setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);
+
+ int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor);
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(result).isEqualTo(0);
+ verify(mTransportManager)
+ .disposeOfTransportClient(eq(transportMock.transportClient), any());
+ assertThat(mWakeLock.isHeld()).isFalse();
+ assertThat(mBackupManagerService.isRestoreInProgress()).isFalse();
+ ShadowPerformUnifiedRestoreTask shadowTask =
+ ShadowPerformUnifiedRestoreTask.getLastCreated();
+ assertThat(shadowTask.isFullSystemRestore()).isFalse();
+ assertThat(shadowTask.getFilterSet()).isNull();
+ assertThat(shadowTask.getPackage().packageName).isEqualTo(PACKAGE_1);
+ }
+
+ @Test
+ public void testRestorePackage_whenPackageNullWhenCreated() throws Exception {
+ ShadowBinder.setCallingUid(1);
+ setUpPackage(PACKAGE_1, /* uid */ 1);
+ when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
+
+ int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor);
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(result).isEqualTo(0);
+ }
+
+ @Test
+ public void testRestorePackage_whenCallerIsNotPackageAndPermissionGranted() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ ShadowBinder.setCallingUid(1);
+ setUpPackage(PACKAGE_1, /* uid */ 2);
+ when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);
+
+ int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor);
+
+ mShadowBackupLooper.runToEndOfTasks();
+ assertThat(result).isEqualTo(0);
+ }
+
+ @Test
+ public void testRestorePackage_whenCallerIsNotPackageAndPermissionDenied() throws Exception {
+ mShadowApplication.denyPermissions(android.Manifest.permission.BACKUP);
+ ShadowBinder.setCallingUid(1);
+ setUpPackage(PACKAGE_1, /* uid */ 2);
+ when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);
+
+ expectThrows(
+ SecurityException.class,
+ () -> restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor));
+ }
+
+ @Test
+ public void testRestorePackage_whenPackageNotFound() throws Exception {
+ mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
+ setUpPackage(PACKAGE_1, /* uid */ 1);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
+
+ int result = restoreSession.restorePackage(PACKAGE_2, mObserver, mMonitor);
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ @Test
+ public void testRestorePackage_whenSessionEnded() throws Exception {
+ ShadowBinder.setCallingUid(1);
+ setUpPackage(PACKAGE_1, /* uid */ 1);
+ setUpTransport(mTransport);
+ IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
+ restoreSession.endRestoreSession();
+ mShadowBackupLooper.runToEndOfTasks();
+
+ expectThrows(
+ IllegalStateException.class,
+ () -> restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor));
+ }
+
+ @Test
+ public void testRestorePackage_whenTransportNotRegistered() throws Exception {
+ ShadowBinder.setCallingUid(1);
+ setUpPackage(PACKAGE_1, /* uid */ 1);
+ setUpTransport(mTransport.unregistered());
+ IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
+
+ int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor);
+
+ assertThat(result).isEqualTo(-1);
+ }
+
+ // TODO: Create a builder for PackageInfo/ApplicationInfo and unify usage with
+ // TransportManagerTest
+ private void setUpPackage(String packageName, int uid) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.uid = uid;
+ mShadowPackageManager.addPackage(packageInfo);
+ }
+
private IRestoreSession createActiveRestoreSession(
String packageName, TransportData transport) {
return new ActiveRestoreSession(
mBackupManagerService, packageName, transport.transportName);
}
+ private IRestoreSession createActiveRestoreSessionWithRestoreSets(
+ String packageName, TransportData transport, RestoreSet... restoreSets)
+ throws RemoteException {
+ ActiveRestoreSession restoreSession =
+ new ActiveRestoreSession(
+ mBackupManagerService, packageName, transport.transportName);
+ restoreSession.setRestoreSets(restoreSets);
+ return restoreSession;
+ }
+
private TransportMock setUpTransport(TransportData transport) throws Exception {
return TransportTestUtils.setUpTransport(mTransportManager, transport);
}
diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 3c0234b..c210fde 100644
--- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -34,8 +34,9 @@
import java.lang.Thread.UncaughtExceptionHandler;
+/** Test utils for {@link BackupManagerService} and friends. */
public class BackupManagerServiceTestUtils {
- /** Sets up a basic mocks for {@link BackupManagerService} */
+ /** Sets up basic mocks for {@link BackupManagerService}. */
public static void setUpBackupManagerServiceBasics(
BackupManagerService backupManagerService,
Context context,
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
index 565c7e6..c00a61d 100644
--- a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
@@ -115,6 +115,7 @@
.thenReturn(transportDirName);
when(transportManager.getTransportDirName(eq(transportComponent)))
.thenReturn(transportDirName);
+ when(transportManager.isTransportRegistered(eq(transportName))).thenReturn(true);
// TODO: Mock rest of description methods
} else {
// Transport not registered
@@ -127,6 +128,7 @@
.thenThrow(TransportNotRegisteredException.class);
when(transportManager.getTransportDirName(eq(transportComponent)))
.thenThrow(TransportNotRegisteredException.class);
+ when(transportManager.isTransportRegistered(eq(transportName))).thenReturn(false);
}
return transportMock;
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
new file mode 100644
index 0000000..0f93c7a
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 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.testing.shadows;
+
+import android.annotation.Nullable;
+import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IRestoreObserver;
+import android.content.pm.PackageInfo;
+
+import com.android.server.backup.BackupManagerService;
+import com.android.server.backup.internal.OnTaskFinishedListener;
+import com.android.server.backup.restore.PerformUnifiedRestoreTask;
+import com.android.server.backup.transport.TransportClient;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(PerformUnifiedRestoreTask.class)
+public class ShadowPerformUnifiedRestoreTask {
+ @Nullable private static ShadowPerformUnifiedRestoreTask sLastShadow;
+
+ /**
+ * Retrieves the shadow for the last {@link PerformUnifiedRestoreTask} object created.
+ *
+ * @return The shadow or {@code null} if no object created since last {@link #reset()}.
+ */
+ @Nullable
+ public static ShadowPerformUnifiedRestoreTask getLastCreated() {
+ return sLastShadow;
+ }
+
+ public static void reset() {
+ sLastShadow = null;
+ }
+
+ private BackupManagerService mBackupManagerService;
+ @Nullable private PackageInfo mPackage;
+ private boolean mIsFullSystemRestore;
+ @Nullable private String[] mFilterSet;
+ private OnTaskFinishedListener mListener;
+
+ @Implementation
+ public void __constructor__(
+ BackupManagerService backupManagerService,
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long restoreSetToken,
+ @Nullable PackageInfo targetPackage,
+ int pmToken,
+ boolean isFullSystemRestore,
+ @Nullable String[] filterSet,
+ OnTaskFinishedListener listener) {
+ mBackupManagerService = backupManagerService;
+ mPackage = targetPackage;
+ mIsFullSystemRestore = isFullSystemRestore;
+ mFilterSet = filterSet;
+ mListener = listener;
+ sLastShadow = this;
+ }
+
+ @Implementation
+ public void execute() {
+ mBackupManagerService.setRestoreInProgress(false);
+ mListener.onFinished("ShadowPerformUnifiedRestoreTask.execute()");
+ }
+
+ public PackageInfo getPackage() {
+ return mPackage;
+ }
+
+ public String[] getFilterSet() {
+ return mFilterSet;
+ }
+
+ public boolean isFullSystemRestore() {
+ return mIsFullSystemRestore;
+ }
+}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index b3fac48..356e64b 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -42,6 +42,7 @@
android.test.base android.test.runner \
LOCAL_PACKAGE_NAME := FrameworksServicesTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index 2433f05..b62f1ce 100644
--- a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -70,12 +70,12 @@
import com.android.server.AppStateTracker.Listener;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -191,6 +191,9 @@
private final HashMap<String, Integer> mGlobalSettings = new HashMap<>();
+ private Answer<List<PackageOps>> mGetPackagesForOps =
+ inv -> new ArrayList<PackageOps>();
+
@Before
public void setUp() {
mMainHandler = new Handler(Looper.getMainLooper());
@@ -230,7 +233,7 @@
.thenAnswer(inv -> getPowerSaveState());
when(mMockAppOpsManager.getPackagesForOps(
any(int[].class)
- )).thenAnswer(inv -> new ArrayList<AppOpsManager.PackageOps>());
+ )).thenAnswer(mGetPackagesForOps);
mMockContentResolver = new MockContentResolver();
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
@@ -661,7 +664,6 @@
areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE);
}
- @Ignore("b/73792882")
@Test
public void loadPersistedAppOps() throws Exception {
final AppStateTrackerTestable instance = newInstance();
@@ -706,6 +708,13 @@
ops.add(new PackageOps(PACKAGE_3, UID_10_3, entries));
+ mGetPackagesForOps = inv -> {
+ final int[] arg = (int[]) inv.getArgument(0);
+ assertEquals(1, arg.length);
+ assertEquals(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, arg[0]);
+ return ops;
+ };
+
callStart(instance);
assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_1, PACKAGE_1));
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index bfc3133..a527e17 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -111,8 +111,6 @@
assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
}
- // TODO: b/71582913
- @Ignore("b/71582913")
@Test
public void testPausingWhenVisibleFromStopped() throws Exception {
final MutableBoolean pauseFound = new MutableBoolean(false);
@@ -204,20 +202,4 @@
verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected),
anyInt(), anyInt(), eq(record.info));
}
-
- @Test
- public void testFinishingAfterDestroying() throws Exception {
- assertFalse(mActivity.finishing);
- mActivity.setState(DESTROYING, "testFinishingAfterDestroying");
- assertTrue(mActivity.isState(DESTROYING));
- assertTrue(mActivity.finishing);
- }
-
- @Test
- public void testFinishingAfterDestroyed() throws Exception {
- assertFalse(mActivity.finishing);
- mActivity.setState(DESTROYED, "testFinishingAfterDestroyed");
- assertTrue(mActivity.isState(DESTROYED));
- assertTrue(mActivity.finishing);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index ce3528b..c62820e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -408,6 +408,10 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(display,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final TestActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final TestActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
@@ -415,6 +419,10 @@
assertTrue(display.getStackAboveHome() == fullscreenStack1);
display.moveHomeStackBehindStack(fullscreenStack2);
assertTrue(display.getStackAboveHome() == fullscreenStack2);
+ display.moveHomeStackBehindStack(fullscreenStack4);
+ assertTrue(display.getStackAboveHome() == fullscreenStack4);
+ display.moveHomeStackBehindStack(fullscreenStack2);
+ assertTrue(display.getStackAboveHome() == fullscreenStack2);
}
private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
index 86c83d6..8ccacb8 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
@@ -18,9 +18,14 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Process;
import android.platform.test.annotations.Presubmit;
@@ -30,6 +35,7 @@
import com.android.server.backup.BackupManagerService;
import com.android.server.backup.testutils.PackageManagerStub;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +51,14 @@
private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
- private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
+ private PackageManagerStub mPackageManagerStub;
+ private PackageManagerInternal mMockPackageManagerInternal;
+
+ @Before
+ public void setUp() throws Exception {
+ mPackageManagerStub = new PackageManagerStub();
+ mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+ }
@Test
public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() throws Exception {
@@ -358,7 +371,8 @@
@Test
public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -369,7 +383,8 @@
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isTrue();
}
@@ -378,10 +393,11 @@
public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[] {SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -390,10 +406,11 @@
public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[] {SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -404,11 +421,11 @@
signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[0];
+ packageInfo.signingCertificateHistory = new Signature[0][0];
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1},
- packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -418,11 +435,11 @@
signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = null;
+ packageInfo.signingCertificateHistory = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1},
- packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -431,10 +448,11 @@
public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = null;
+ packageInfo.signingCertificateHistory = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -443,10 +461,11 @@
public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[0];
+ packageInfo.signingCertificateHistory = new Signature[0][0];
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -458,11 +477,14 @@
Signature signature3Copy = new Signature(SIGNATURE_3.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature3Copy, signature1Copy, signature2Copy}, packageInfo);
+ new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isTrue();
}
@@ -473,11 +495,14 @@
Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature2Copy, signature1Copy}, packageInfo);
+ new Signature[]{signature2Copy, signature1Copy}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isTrue();
}
@@ -488,11 +513,14 @@
Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{signature1Copy, signature2Copy};
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {signature1Copy, signature2Copy}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo);
+ new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -503,11 +531,76 @@
Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo);
+ new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
+ throws Exception {
+ Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+ packageInfo.packageName);
+
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo, mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
+ throws Exception {
+ Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know signature1Copy is in history, and we want to assume it has
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+ packageInfo.packageName);
+
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo, mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void
+ signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
+ throws Exception {
+ Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know signature1Copy is in history, but we want to assume it does not have
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+ packageInfo.packageName);
+
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo, mMockPackageManagerInternal);
assertThat(result).isFalse();
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index 0cdf04b..5f052ce 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -28,6 +28,9 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -37,6 +40,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.Process;
@@ -79,6 +83,7 @@
@Mock private BytesReadListener mBytesReadListenerMock;
@Mock private IBackupManagerMonitor mBackupManagerMonitorMock;
+ @Mock private PackageManagerInternal mMockPackageManagerInternal;
private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
private Context mContext;
@@ -139,7 +144,8 @@
Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
fileMetadata);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
- mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+ mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
+ mMockPackageManagerInternal);
assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -152,7 +158,8 @@
signatures = tarBackupReader.readAppManifestAndReturnSignatures(
fileMetadata);
restorePolicy = tarBackupReader.chooseRestorePolicy(
- mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+ mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
+ mMockPackageManagerInternal);
assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -214,7 +221,8 @@
mBytesReadListenerMock, mBackupManagerMonitorMock);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, new FileMetadata(), null /* signatures */);
+ true /* allowApks */, new FileMetadata(), null /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
verifyZeroInteractions(mBackupManagerMonitorMock);
@@ -234,7 +242,8 @@
PackageManagerStub.sPackageInfo = null;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, info, new Signature[0] /* signatures */);
+ true /* allowApks */, info, new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -258,7 +267,8 @@
PackageManagerStub.sPackageInfo = null;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, info, new Signature[0] /* signatures */);
+ true /* allowApks */, info, new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -283,7 +293,8 @@
PackageManagerStub.sPackageInfo = null;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+ false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -307,7 +318,8 @@
PackageManagerStub.sPackageInfo = packageInfo;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+ false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -333,7 +345,8 @@
PackageManagerStub.sPackageInfo = packageInfo;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+ false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -358,11 +371,11 @@
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_2};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_2}};
PackageManagerStub.sPackageInfo = packageInfo;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), signatures);
+ false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -383,16 +396,19 @@
Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |=
ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.SYSTEM_UID;
packageInfo.applicationInfo.backupAgentName = "backup.agent";
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), signatures);
+ false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -412,16 +428,19 @@
Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |=
ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), signatures);
+ false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -444,17 +463,20 @@
info.version = 1;
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
packageInfo.versionCode = 2;
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, info, signatures);
+ false /* allowApks */, info, signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -479,17 +501,20 @@
info.hasApk = true;
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
packageInfo.versionCode = 1;
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, info, signatures);
+ true /* allowApks */, info, signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
verifyNoMoreInteractions(mBackupManagerMonitorMock);
@@ -510,17 +535,20 @@
info.version = 2;
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
packageInfo.versionCode = 1;
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, info, signatures);
+ false /* allowApks */, info, signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 501f966..b4f8474 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -338,6 +338,26 @@
assertFalse(event.isDefaultBrightnessConfig);
assertEquals(1.0, event.powerBrightnessFactor, FLOAT_DELTA);
assertFalse(event.isUserSetBrightness);
+
+ // Pretend user 1 is a profile of user 0.
+ mInjector.mProfiles = new int[]{0, 1};
+ events = tracker.getEvents(0, true).getList();
+ // Both events should now be returned.
+ assertEquals(2, events.size());
+ BrightnessChangeEvent userZeroEvent;
+ BrightnessChangeEvent userOneEvent;
+ if (events.get(0).userId == 0) {
+ userZeroEvent = events.get(0);
+ userOneEvent = events.get(1);
+ } else {
+ userZeroEvent = events.get(1);
+ userOneEvent = events.get(0);
+ }
+ assertEquals(0, userZeroEvent.userId);
+ assertEquals("com.example.app", userZeroEvent.packageName);
+ assertEquals(1, userOneEvent.userId);
+ // Events from user 1 should have the package name redacted
+ assertNull(userOneEvent.packageName);
}
@Test
@@ -597,6 +617,7 @@
Handler mHandler;
boolean mIdleScheduled;
boolean mInteractive = true;
+ int[] mProfiles;
public TestInjector(Handler handler) {
mHandler = handler;
@@ -682,6 +703,15 @@
}
@Override
+ public int[] getProfileIds(UserManager userManager, int userId) {
+ if (mProfiles != null) {
+ return mProfiles;
+ } else {
+ return new int[]{userId};
+ }
+ }
+
+ @Override
public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
ActivityManager.StackInfo focusedStack = new ActivityManager.StackInfo();
focusedStack.userId = 0;
@@ -689,15 +719,18 @@
return focusedStack;
}
+ @Override
public void scheduleIdleJob(Context context) {
// Don't actually schedule jobs during unit tests.
mIdleScheduled = true;
}
+ @Override
public void cancelIdleJob(Context context) {
mIdleScheduled = false;
}
+ @Override
public boolean isInteractive(Context context) {
return mInteractive;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
index 8a461ac..fd8b319 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -39,6 +39,7 @@
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
+import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
@@ -51,7 +52,7 @@
private static final int TEST_GENERATION_ID = 3;
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
private static final String KEY_ALGORITHM = "AES";
- private static final int KEY_SIZE_BYTES = 32;
+ private static final int KEY_SIZE_BYTES = RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE;
private static final String KEY_WRAP_ALGORITHM = "AES/GCM/NoPadding";
private static final String TEST_ALIAS = "karlin";
private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
@@ -71,7 +72,7 @@
mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
- AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+ AndroidKeyStoreSecretKey platformKey = generatePlatformKey();
mPlatformKey = new PlatformEncryptionKey(TEST_GENERATION_ID, platformKey);
mDecryptKey = new PlatformDecryptionKey(TEST_GENERATION_ID, platformKey);
mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mRecoverableKeyStoreDb);
@@ -117,7 +118,21 @@
assertArrayEquals(rawMaterial, unwrappedMaterial);
}
- private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ @Test
+ public void importKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
+ byte[] rawMaterial = randomBytes(KEY_SIZE_BYTES);
+ mRecoverableKeyGenerator.importKey(
+ mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial);
+
+ WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
+ Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, mDecryptKey.getKey(),
+ new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
+ byte[] unwrappedMaterial = cipher.doFinal(wrappedKey.getKeyMaterial());
+ assertArrayEquals(rawMaterial, unwrappedMaterial);
+ }
+
+ private AndroidKeyStoreSecretKey generatePlatformKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
@@ -132,4 +147,10 @@
private static byte[] getUtf8Bytes(String s) {
return s.getBytes(StandardCharsets.UTF_8);
}
+
+ private static byte[] randomBytes(int n) {
+ byte[] bytes = new byte[n];
+ new Random().nextBytes(bytes);
+ return bytes;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index b67659d..0ceb558 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -132,6 +132,7 @@
private static final String TEST_ALIAS = "nick";
private static final String TEST_ALIAS2 = "bob";
private static final int RECOVERABLE_KEY_SIZE_BYTES = 32;
+ private static final int APPLICATION_KEY_SIZE_BYTES = 32;
private static final int GENERATION_ID = 1;
private static final byte[] NONCE = getUtf8Bytes("nonce");
private static final byte[] KEY_MATERIAL = getUtf8Bytes("keymaterial");
@@ -209,6 +210,39 @@
}
@Test
+ public void importKey_storesTheKey() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES);
+
+ mRecoverableKeyStoreManager.importKey(TEST_ALIAS, keyMaterial);
+
+ assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ }
+
+ @Test
+ public void importKey_throwsIfInvalidLength() throws Exception {
+ byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES - 1);
+ try {
+ mRecoverableKeyStoreManager.importKey(TEST_ALIAS, keyMaterial);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("not contain 256 bits");
+ }
+ }
+
+ @Test
+ public void importKey_throwsIfNullKey() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.importKey(TEST_ALIAS, /*keyBytes=*/ null);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("not contain 256 bits");
+ }
+ }
+
+ @Test
public void removeKey_removesAKey() throws Exception {
int uid = Binder.getCallingUid();
mRecoverableKeyStoreManager.generateAndStoreKey(TEST_ALIAS);
@@ -243,7 +277,7 @@
}
@Test
- public void initRecoveryService_succeeds() throws Exception {
+ public void initRecoveryService_succeedsWithCertFile() throws Exception {
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
long certSerial = 1000L;
@@ -261,6 +295,18 @@
}
@Test
+ public void initRecoveryService_throwsIfInvalidCert() throws Exception {
+ byte[] modifiedCertXml = TestData.getCertXml();
+ modifiedCertXml[modifiedCertXml.length - 50] ^= 1; // Flip a bit in the certificate
+ try {
+ mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, modifiedCertXml);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("validate cert");
+ }
+ }
+
+ @Test
public void initRecoveryService_updatesWithLargerSerial() throws Exception {
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
@@ -321,6 +367,70 @@
}
@Test
+ public void initRecoveryServiceWithSigFile_succeeds() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml());
+
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+ TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfNullCertFile() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, /*recoveryServiceCertFile=*/ null,
+ TestData.getSigXml());
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("is null");
+ }
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfNullSigFile() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(),
+ /*recoveryServiceSigFile=*/ null);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("is null");
+ }
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfWrongSigFileFormat() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(),
+ getUtf8Bytes("wrong-sig-file-format"));
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("parse the sig file");
+ }
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfInvalidFileSignature() throws Exception {
+ byte[] modifiedCertXml = TestData.getCertXml();
+ modifiedCertXml[modifiedCertXml.length - 1] = 0; // Change the last new line char to a zero
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, modifiedCertXml, TestData.getSigXml());
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("is invalid");
+ }
+ }
+
+ @Test
public void startRecoverySession_checksPermissionFirst() throws Exception {
mRecoverableKeyStoreManager.startRecoverySession(
TEST_SESSION_ID,
@@ -532,7 +642,31 @@
TEST_SECRET)));
fail("should have thrown");
} catch (ServiceSpecificException e) {
- assertThat(e.getMessage()).contains("CertPath is empty");
+ assertThat(e.getMessage()).contains("empty");
+ }
+ }
+
+ @Test
+ public void startRecoverySessionWithCertPath_throwsIfInvalidCertPath() throws Exception {
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ CertPath shortCertPath = certFactory.generateCertPath(
+ TestData.CERT_PATH_1.getCertificates()
+ .subList(0, TestData.CERT_PATH_1.getCertificates().size() - 1));
+ try {
+ mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
+ TEST_SESSION_ID,
+ RecoveryCertPath.createRecoveryCertPath(shortCertPath),
+ TEST_VAULT_PARAMS,
+ TEST_VAULT_CHALLENGE,
+ ImmutableList.of(
+ new KeyChainProtectionParams(
+ TYPE_LOCKSCREEN,
+ UI_FORMAT_PASSWORD,
+ KeyDerivationParams.createSha256Params(TEST_SALT),
+ TEST_SECRET)));
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ // expected
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
index 0e4f91b..b5d6ce8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
@@ -9,6 +9,7 @@
public final class TestData {
+ private static final long DEFAULT_SERIAL = 1000;
private static final String CERT_PATH_ENCODING = "PkiPath";
private static final String CERT_PATH_1_BASE64 = ""
@@ -89,10 +90,11 @@
private static final String THM_CERT_XML_BEFORE_SERIAL = ""
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- + "<certificates>\n"
- + " <metadata>\n"
- + " <serial>\n";
- private static final String THM_CERT_XML_AFTER_SERIAL = ""
+ + "<certificates>\n"
+ + " <metadata>\n"
+ + " <serial>\n"
+ + " ";
+ private static final String THM_CERT_XML_AFTER_SERIAL = "\n"
+ " </serial>\n"
+ " <creation-time>\n"
+ " 1515697631\n"
@@ -163,6 +165,53 @@
+ " </cert>\n"
+ " </endpoints>\n"
+ "</certificates>\n";
+ private static final String THM_SIG_XML = ""
+ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ + "<signature>\n"
+ + " <intermediates>\n"
+ + " </intermediates>\n"
+ + " <certificate>\n"
+ + " MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
+ + " Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
+ + " M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
+ + " ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
+ + " vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
+ + " hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
+ + " 6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
+ + " qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
+ + " /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
+ + " PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
+ + " miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
+ + " 4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
+ + " ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
+ + " uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
+ + " k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
+ + " QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
+ + " HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
+ + " AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
+ + " mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
+ + " xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
+ + " 7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
+ + " t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
+ + " SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
+ + " 0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
+ + " ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
+ + " AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
+ + " KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
+ + " St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
+ + " </certificate>\n"
+ + " <value>\n"
+ + " uKJ4W8BPCdVaIBe2ZiMxxk5L5vGBV9QwaOEGU80LgtA/gEqkiO2IMUBlQJFqvvhh6RSph5lWpLuv\n"
+ + " /Xt7WBzDsZOcxXNffg2+pWNpbpwZdHohlwQEI1OqiVYVnfG4euAkzeWZZLsRUuAjHfcWVIzDoSoK\n"
+ + " wC+gqdUQHBV+pWyn6PXVslS0JIldeegbiwF076M1D7ybeCABXoQelSZRHkx1szO8UnxSR3X7Cemu\n"
+ + " p9De/7z9+WPPclqybINVIPy6Kvl8mHrGSlzawQRDKtoMrJa8bo93PookF8sbg5EoGapV0yNpMEiA\n"
+ + " spq3DEcdXB6mGDGPnLbS2WXq4zjKopASRKkZvOMdgfS6NdUMDtKS1TsOrv2KKTkLnGYfvdAeWiMg\n"
+ + " oFbuyYQ0mnDlLH1UW6anI8RxXn+wmdyZA+/ksapGvRmkvz0Mb997WzqNl7v7UTr0SU3Ws01hFsm6\n"
+ + " lW++MsotkyfpR9mWB8/dqVNVShLmIlt7U/YFVfziYSrVdjcAdIlgJ6Ihxb92liQHOU+Qr1YDOmm1\n"
+ + " JSnhlQVvFxWZG7hm5laNL6lqXz5VV6Gk5IeLtMb8kdHz3zj4ascdldapVPLJIa5741GNNgQNU0nH\n"
+ + " FhAyKk0zN7PbL1/XGWPU+s5lai4HE6JM2CKA7jE7cYrdaDZxbba+9iWzQ4YEBDr5Z3OoloK5dvs=\n"
+ + " </value>\n"
+ + "</signature>\n";
public static byte[] getCertPath1Bytes() {
try {
@@ -199,4 +248,12 @@
String xml = THM_CERT_XML_BEFORE_SERIAL + serial + THM_CERT_XML_AFTER_SERIAL;
return xml.getBytes(StandardCharsets.UTF_8);
}
+
+ public static byte[] getCertXml() {
+ return getCertXmlWithSerial(DEFAULT_SERIAL);
+ }
+
+ public static byte[] getSigXml() {
+ return THM_SIG_XML.getBytes(StandardCharsets.UTF_8);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java
index d08dab4..9279698 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java
@@ -30,8 +30,10 @@
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.cert.CertPath;
+import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
@@ -317,6 +319,42 @@
}
@Test
+ public void validateCertPath_succeeds() throws Exception {
+ X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
+ List<X509Certificate> intermediateCerts =
+ Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+ X509Certificate leafCert = TestData.LEAF_CERT_2;
+ CertPath certPath =
+ CertUtils.buildCertPath(
+ CertUtils.buildPkixParams(
+ TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+ leafCert));
+ CertUtils.validateCertPath(
+ TestData.DATE_ALL_CERTS_VALID, TestData.ROOT_CA_TRUSTED, certPath);
+ }
+
+ @Test
+ public void validateCertPath_throwsIfEmptyCertPath() throws Exception {
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ CertPath emptyCertPath = certFactory.generateCertPath(new ArrayList<X509Certificate>());
+ CertValidationException expected =
+ expectThrows(
+ CertValidationException.class,
+ () -> CertUtils.validateCertPath(TestData.DATE_ALL_CERTS_VALID,
+ TestData.ROOT_CA_TRUSTED, emptyCertPath));
+ assertThat(expected.getMessage()).contains("empty");
+ }
+
+ @Test
+ public void validateCertPath_throwsIfNotValidated() throws Exception {
+ assertThrows(
+ CertValidationException.class,
+ () -> CertUtils.validateCertPath(TestData.DATE_ALL_CERTS_VALID,
+ TestData.ROOT_CA_DIFFERENT_COMMON_NAME,
+ com.android.server.locksettings.recoverablekeystore.TestData.CERT_PATH_1));
+ }
+
+ @Test
public void validateCert_succeeds() throws Exception {
X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
List<X509Certificate> intermediateCerts =
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
index 17a4d34..180345c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
@@ -27,7 +27,6 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +44,6 @@
.getBytes(StandardCharsets.UTF_8);
private static final byte[] KEY_MATERIAL = "app_key_data".getBytes(StandardCharsets.UTF_8);
private static final byte[] PUBLIC_KEY = "public_key_data".getBytes(StandardCharsets.UTF_8);
- private static final byte[] ACCOUNT = "test_account".getBytes(StandardCharsets.UTF_8);
private static final byte[] SALT = "salt".getBytes(StandardCharsets.UTF_8);
private static final int SNAPSHOT_VERSION = 2;
private static final int MAX_ATTEMPTS = 10;
@@ -130,7 +128,6 @@
WrappedApplicationKey entry = new WrappedApplicationKey.Builder()
.setAlias(ALIAS)
.setEncryptedKeyMaterial(KEY_MATERIAL)
- .setAccount(ACCOUNT)
.build();
writer.writeKeyEntry(entry);
@@ -142,7 +139,6 @@
WrappedApplicationKey copy = reader.readKeyEntry();
assertThat(copy.getAlias()).isEqualTo(ALIAS);
assertThat(copy.getEncryptedKeyMaterial()).isEqualTo(KEY_MATERIAL);
- assertThat(copy.getAccount()).isEqualTo(ACCOUNT);
assertThrows(
IOException.class,
@@ -194,7 +190,6 @@
appKeysList.add(new WrappedApplicationKey.Builder()
.setAlias(ALIAS)
.setEncryptedKeyMaterial(KEY_MATERIAL)
- .setAccount(ACCOUNT)
.build());
KeyChainSnapshot snapshot = new KeyChainSnapshot.Builder()
@@ -256,12 +251,10 @@
appKeysList.add(new WrappedApplicationKey.Builder()
.setAlias(ALIAS)
.setEncryptedKeyMaterial(KEY_MATERIAL)
- .setAccount(ACCOUNT)
.build());
appKeysList.add(new WrappedApplicationKey.Builder()
.setAlias(ALIAS2)
.setEncryptedKeyMaterial(KEY_MATERIAL)
- .setAccount(ACCOUNT)
.build());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 609faa4..dfb2dbf 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith;
import android.content.Context;
-import android.security.keystore.RecoveryController;
+import android.security.keystore.recovery.RecoveryController;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
index c016e61..a0cefbf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
@@ -15,73 +15,298 @@
*/
package com.android.server.pm.backup;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser.Package;
import android.content.pm.Signature;
-import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.server.backup.BackupUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Arrays;
@SmallTest
-public class BackupUtilsTest extends AndroidTestCase {
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupUtilsTest {
- private Signature[] genSignatures(String... signatures) {
- final Signature[] sigs = new Signature[signatures.length];
- for (int i = 0; i < signatures.length; i++){
- sigs[i] = new Signature(signatures[i].getBytes());
- }
- return sigs;
+ private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
+ private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
+ private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
+ private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
+ private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1);
+ private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2);
+ private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3);
+ private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4);
+
+ private PackageManagerInternal mMockPackageManagerInternal;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockPackageManagerInternal = mock(PackageManagerInternal.class);
}
- private PackageInfo genPackage(String... signatures) {
- final PackageInfo pi = new PackageInfo();
- pi.packageName = "package";
- pi.applicationInfo = new ApplicationInfo();
- pi.signatures = genSignatures(signatures);
+ @Test
+ public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, null,
+ mMockPackageManagerInternal);
- return pi;
+ assertThat(result).isFalse();
}
- public void testSignaturesMatch() {
- final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList(
- "abc".getBytes()));
- final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList(
- "abc".getBytes(), "def".getBytes()));
+ @Test
+ public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- PackageInfo pi;
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
- // False for null package.
- assertFalse(BackupUtils.signaturesMatch(stored1, null));
-
- // If it's a system app, signatures don't matter.
- pi = genPackage("xyz");
- pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- assertTrue(BackupUtils.signaturesMatch(stored1, pi));
-
- // Non system apps.
- assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc")));
-
- // Superset is okay.
- assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz")));
- assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc")));
-
- assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz")));
- assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def")));
-
- assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc")));
- assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y")));
-
- // Subset is not okay.
- assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc")));
- assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def")));
+ assertThat(result).isTrue();
}
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ boolean result = BackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+
+ @Test
+ public void
+ signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[0][0];
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void
+ signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = null;
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = null;
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ boolean result = BackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[0][0];
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_equalSignatures_returnsTrue() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ storedSigHashes.add(SIGNATURE_HASH_3);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1, SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ storedSigHashes.add(SIGNATURE_HASH_3);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ storedSigHashes.add(SIGNATURE_HASH_4);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+ packageInfo.packageName);
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know SIGNATURE_1 is in history, and we want to assume it has
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+ packageInfo.packageName);
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void
+ signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know SIGNATURE_1 is in history, but we want to assume it does not have
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+ packageInfo.packageName);
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
public void testHashSignature() {
final byte[] sig1 = "abc".getBytes();
final byte[] sig2 = "def".getBytes();
@@ -115,4 +340,10 @@
MoreAsserts.assertEquals(hash2a, listA.get(1));
MoreAsserts.assertEquals(hash2a, listB.get(1));
}
+
+ private static Signature generateSignature(byte i) {
+ byte[] signatureBytes = new byte[256];
+ signatureBytes[0] = i;
+ return new Signature(signatureBytes);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index a628b7b..5de393c 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -79,11 +79,6 @@
}
@Override
- public Point getShownPositionLw() {
- return new Point(parentFrame.left, parentFrame.top);
- }
-
- @Override
public Rect getDisplayFrameLw() {
return displayFrame;
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index 30ca9ca..1d4348c 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -77,7 +77,9 @@
public void setUpBase() throws Exception {
mContext = new TestContextWrapper(InstrumentationRegistry.getTargetContext());
mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.status_bar_height, STATUS_BAR_HEIGHT);
+ com.android.internal.R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT);
+ mContext.getResourceMocker().addOverride(
+ com.android.internal.R.dimen.status_bar_height_landscape, STATUS_BAR_HEIGHT);
mContext.getResourceMocker().addOverride(
com.android.internal.R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
mContext.getResourceMocker().addOverride(
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index b55c79b..76e4e89 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import android.platform.test.annotations.Presubmit;
@@ -45,6 +46,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 74078662)
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class AppWindowContainerControllerTests extends WindowTestsBase {
@@ -131,7 +133,6 @@
assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
- mDisplayContent.onPendingTransactionApplied();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 64c3037..a120eba 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -23,11 +23,11 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
@@ -39,7 +39,6 @@
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -47,7 +46,6 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -87,7 +85,7 @@
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@@ -97,7 +95,7 @@
final SurfaceControl firstLeash = mAnimatable.mLeash;
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ verify(mTransaction).destroy(eq(firstLeash));
assertFalse(mAnimatable.mFinishedCallbackCalled);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -124,7 +122,7 @@
assertNotAnimating(mAnimatable);
verify(mSpec).onAnimationCancelled(any());
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -145,7 +143,7 @@
verifyZeroInteractions(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -161,11 +159,11 @@
assertNotAnimating(mAnimatable);
assertAnimating(mAnimatable2);
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
- assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction, never()).destroy(eq(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
- assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction).destroy(eq(leash));
}
private void assertAnimating(MyAnimatable animatable) {
@@ -182,7 +180,6 @@
final SurfaceControl mParent;
final SurfaceControl mSurface;
- final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
@@ -198,7 +195,7 @@
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
}
@Override
@@ -219,11 +216,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroySurfaces.add(surface);
- }
-
- @Override
public Builder makeAnimationLeash() {
return new SurfaceControl.Builder(mSession) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 0b99eaa..206ee7a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -644,4 +644,8 @@
public boolean canDismissBootAnimation() {
return true;
}
+
+ @Override
+ public void onScreenMagnificationStateChanged(boolean active) {
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index e78224c..41e446b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -22,6 +22,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayInfo;
@@ -44,6 +45,7 @@
* bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class WindowConfigurationTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
index bab2170..502cb6e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -18,6 +18,7 @@
import android.app.WindowConfiguration;
import android.content.res.Configuration;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import android.platform.test.annotations.Presubmit;
@@ -38,6 +39,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 74078662)
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class WindowContainerControllerTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 1bd9a93..8446d25 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,6 +56,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 74078662)
@RunWith(AndroidJUnit4.class)
public class WindowContainerTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 74c72bf..83868d6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -21,6 +21,7 @@
import org.junit.runner.RunWith;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -52,6 +53,7 @@
* atest FrameworksServicesTests:com.android.server.wm.WindowStateTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowStateTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 7219104..394e636 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -20,6 +20,7 @@
import org.junit.runner.RunWith;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -40,6 +41,7 @@
* bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowTokenTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
index ad9aea7..a3ade1e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
@@ -31,6 +31,7 @@
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.support.test.filters.FlakyTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.proto.ProtoOutputStream;
@@ -56,6 +57,7 @@
* bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowTracingTest extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 5f44fb6..547be55 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -35,6 +35,7 @@
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
+import android.support.test.filters.FlakyTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -53,6 +54,7 @@
* bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ZOrderingTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java
index d3cf978..6bbc7eb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertThat;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
@@ -37,6 +38,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
public class RotationCacheTest {
@@ -100,4 +102,4 @@
assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1)));
assertThat(mComputationCalled, is(true));
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
index fbfa28a..18b8c2d 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
@@ -24,6 +24,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := ConnTestApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/services/tests/uiservicestests/Android.mk b/services/tests/uiservicestests/Android.mk
index d7c3f7f..b98bc89 100644
--- a/services/tests/uiservicestests/Android.mk
+++ b/services/tests/uiservicestests/Android.mk
@@ -31,6 +31,7 @@
LOCAL_DX_FLAGS := --multi-dex
LOCAL_PACKAGE_NAME := FrameworksUiServicesTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 3fbcd81..7f060b3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -47,7 +47,7 @@
class UserUsageStatsService {
private static final String TAG = "UsageStatsService";
private static final boolean DEBUG = UsageStatsService.DEBUG;
- private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss");
private static final int sDateFormatFlags =
DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_TIME
@@ -572,11 +572,13 @@
pw.printPair("endTime", endTime);
}
pw.println(")");
- pw.increaseIndent();
- for (UsageEvents.Event event : events) {
- printEvent(pw, event, prettyDates);
+ if (events != null) {
+ pw.increaseIndent();
+ for (UsageEvents.Event event : events) {
+ printEvent(pw, event, prettyDates);
+ }
+ pw.decreaseIndent();
}
- pw.decreaseIndent();
}
void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index a7fc470..ef0780a 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1359,9 +1359,7 @@
UsbManager.USB_FUNCTION_NONE).equals(
getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE));
}
- // Mask out adb, since it is stored in mAdbEnabled
- mCurrentFunctions = UsbManager.usbFunctionsFromString(mCurrentFunctionsStr)
- & ~UsbManager.FUNCTION_ADB;
+ mCurrentFunctions = UsbManager.FUNCTION_NONE;
mCurrentUsbFunctionsReceived = true;
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index ddb4f04..33da403 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -138,6 +138,7 @@
}
public void systemReady() {
+ mSystemReady = true;
if (mProxy != null) {
try {
mProxy.queryPortStatus();
@@ -146,7 +147,6 @@
"ServiceStart: Failed to query port status", e);
}
}
- mSystemReady = true;
}
public UsbPort[] getPorts() {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 297a6ea..956efc0 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -380,11 +380,10 @@
if (DEBUG) {
Log.d(TAG, " type:0x" + Integer.toHexString(type));
}
- if ((type >= UsbTerminalTypes.TERMINAL_IN_UNDEFINED
- && type <= UsbTerminalTypes.TERMINAL_IN_PROC_MIC_ARRAY)
- || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
- && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)
- || (type == UsbTerminalTypes.TERMINAL_USB_STREAMING)) {
+ int terminalCategory = type & ~0xFF;
+ if (terminalCategory != UsbTerminalTypes.TERMINAL_USB_UNDEFINED
+ && terminalCategory != UsbTerminalTypes.TERMINAL_OUT_UNDEFINED) {
+ // If not explicitly a USB connection or output, it could be an input.
hasInput = true;
break;
}
@@ -419,10 +418,10 @@
if (DEBUG) {
Log.d(TAG, " type:0x" + Integer.toHexString(type));
}
- if ((type >= UsbTerminalTypes.TERMINAL_OUT_UNDEFINED
- && type <= UsbTerminalTypes.TERMINAL_OUT_LFSPEAKER)
- || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
- && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)) {
+ int terminalCategory = type & ~0xFF;
+ if (terminalCategory != UsbTerminalTypes.TERMINAL_USB_UNDEFINED
+ && terminalCategory != UsbTerminalTypes.TERMINAL_IN_UNDEFINED) {
+ // If not explicitly a USB connection or input, it could be an output.
hasOutput = true;
break;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
index 9bd6cb9..cbb899e 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
@@ -24,6 +24,7 @@
private static final String TAG = "UsbTerminalTypes";
// USB
+ public static final int TERMINAL_USB_UNDEFINED = 0x0100;
public static final int TERMINAL_USB_STREAMING = 0x0101;
// Inputs
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index e7f0cc2..cb87d1f 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -1103,10 +1103,15 @@
"android.provider.Telephony.MMS_DOWNLOADED";
/**
- * Broadcast Action: A debug code has been entered in the dialer. These "secret codes"
- * are used to activate developer menus by dialing certain codes. And they are of the
- * form {@code *#*#<code>#*#*}. The intent will have the data URI:
- * {@code android_secret_code://<code>}.
+ * Broadcast Action: A debug code has been entered in the dialer. This intent is
+ * broadcast by the system and OEM telephony apps may need to receive these broadcasts.
+ * These "secret codes" are used to activate developer menus by dialing certain codes.
+ * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
+ * URI: {@code android_secret_code://<code>}. It is possible that a manifest
+ * receiver would be woken up even if it is not currently running.
+ *
+ * <p>Requires {@code android.Manifest.permission#CONTROL_INCALL_EXPERIENCE} to
+ * send and receive.</p>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SECRET_CODE_ACTION =
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6798a83..96eb23d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1815,7 +1815,14 @@
"check_pricing_with_carrier_data_roaming_bool";
/**
- * List of thresholds of RSRP for determining the display level of LTE signal bar.
+ * A list of 4 LTE RSRP thresholds above which a signal level is considered POOR,
+ * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
+ *
+ * Note that the min and max thresholds are fixed at -140 and -44, as explained in
+ * TS 136.133 9.1.4 - RSRP Measurement Report Mapping.
+ * <p>
+ * See SignalStrength#MAX_LTE_RSRP and SignalStrength#MIN_LTE_RSRP. Any signal level outside
+ * these boundaries is considered invalid.
* @hide
*/
public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY =
@@ -2136,12 +2143,10 @@
sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
new int[] {
- -140, /* SIGNAL_STRENGTH_NONE_OR_UNKNOWN */
-128, /* SIGNAL_STRENGTH_POOR */
-118, /* SIGNAL_STRENGTH_MODERATE */
-108, /* SIGNAL_STRENGTH_GOOD */
-98, /* SIGNAL_STRENGTH_GREAT */
- -44
});
}
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index b362df9..26ffe32 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -82,8 +82,7 @@
.noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
return false;
}
- if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
- && !isLegacyForeground(context, pkgName, uid)) {
+ if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) {
return false;
}
// If the user or profile is current, permission is granted.
@@ -101,35 +100,6 @@
&& locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
}
- private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
- int uid) {
- long token = Binder.clearCallingIdentity();
- try {
- return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
- try {
- if (context.getPackageManager().getApplicationInfo(pkgName, 0)
- .targetSdkVersion <= Build.VERSION_CODES.O) {
- return true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- // In case of exception, assume known app (more strict checking)
- // Note: This case will never happen since checkPackage is
- // called to verify validity before checking app's version.
- }
- return false;
- }
-
- private static boolean isForegroundApp(@NonNull Context context, int uid) {
- final ActivityManager am = context.getSystemService(ActivityManager.class);
- return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
- }
-
private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
return context.checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 0ee870a..0446925 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -372,7 +372,7 @@
break;
case LISTEN_PHYSICAL_CHANNEL_CONFIGURATION:
PhoneStateListener.this.onPhysicalChannelConfigurationChanged(
- (List<PhysicalChannelConfig>)msg.obj);
+ (List<PhysicalChannelConfig>)msg.obj);
break;
}
}
@@ -700,6 +700,10 @@
public void onCarrierNetworkChange(boolean active) {
send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
}
+
+ public void onPhysicalChannelConfigurationChanged(List<PhysicalChannelConfig> configs) {
+ send(LISTEN_PHYSICAL_CHANNEL_CONFIGURATION, 0, 0, configs);
+ }
}
IPhoneStateListener callback = new IPhoneStateListenerStub(this);
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 651d68d..ce444dd 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -27,8 +27,9 @@
*/
public final class PhysicalChannelConfig implements Parcelable {
+ // TODO(b/72993578) consolidate these enums in a central location.
@Retention(RetentionPolicy.SOURCE)
- @IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING})
+ @IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING, CONNECTION_UNKNOWN})
public @interface ConnectionStatus {}
/**
@@ -41,6 +42,9 @@
*/
public static final int CONNECTION_SECONDARY_SERVING = 2;
+ /** Connection status is unknown. */
+ public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE;
+
/**
* Connection status of the cell.
*
@@ -86,6 +90,7 @@
*
* @see #CONNECTION_PRIMARY_SERVING
* @see #CONNECTION_SECONDARY_SERVING
+ * @see #CONNECTION_UNKNOWN
*
* @return Connection status of the cell
*/
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 778ca77..47a7d5f 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -62,7 +62,9 @@
*/
public static final int INVALID = Integer.MAX_VALUE;
- private static final int LTE_RSRP_THRESHOLDS_NUM = 6;
+ private static final int LTE_RSRP_THRESHOLDS_NUM = 4;
+ private static final int MAX_LTE_RSRP = -44;
+ private static final int MIN_LTE_RSRP = -140;
/** Parameters reported by the Radio */
private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
@@ -86,7 +88,8 @@
// onSignalStrengthResult.
private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar.
- // The threshold of LTE RSRP for determining the display level of LTE signal bar.
+ // The threshold of LTE RSRP for determining the display level of LTE signal bar. Note that the
+ // min and max are fixed at MIN_LTE_RSRP (-140) and MAX_LTE_RSRP (-44).
private int mLteRsrpThresholds[] = new int[LTE_RSRP_THRESHOLDS_NUM];
/**
@@ -324,7 +327,8 @@
// TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC
mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
- mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID;
+ mLteRsrp = ((-mLteRsrp >= MIN_LTE_RSRP) && (-mLteRsrp <= MAX_LTE_RSRP)) ? -mLteRsrp
+ : SignalStrength.INVALID;
mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
: SignalStrength.INVALID;
@@ -740,24 +744,29 @@
*/
public int getLteLevel() {
/*
- * TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received
- * signal + noise RSRP = reference signal dBm RSRQ = quality of signal
- * dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio
- * = -10log P1/P2 dB
+ * TS 36.214 Physical Layer Section 5.1.3
+ * TS 36.331 RRC
+ *
+ * RSSI = received signal + noise
+ * RSRP = reference signal dBm
+ * RSRQ = quality of signal dB = Number of Resource blocks*RSRP/RSSI
+ * SNR = gain = signal/noise ratio = -10log P1/P2 dB
*/
int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
- if (mLteRsrp > mLteRsrpThresholds[5]) {
- rsrpIconLevel = -1;
- } else if (mLteRsrp >= (mLteRsrpThresholds[4] - mLteRsrpBoost)) {
- rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
+ if (mLteRsrp > MAX_LTE_RSRP || mLteRsrp < MIN_LTE_RSRP) {
+ if (mLteRsrp != INVALID) {
+ Log.wtf(LOG_TAG, "getLteLevel - invalid lte rsrp: mLteRsrp=" + mLteRsrp);
+ }
} else if (mLteRsrp >= (mLteRsrpThresholds[3] - mLteRsrpBoost)) {
- rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
+ rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
} else if (mLteRsrp >= (mLteRsrpThresholds[2] - mLteRsrpBoost)) {
- rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+ rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
} else if (mLteRsrp >= (mLteRsrpThresholds[1] - mLteRsrpBoost)) {
+ rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+ } else if (mLteRsrp >= (mLteRsrpThresholds[0] - mLteRsrpBoost)) {
rsrpIconLevel = SIGNAL_STRENGTH_POOR;
- } else if (mLteRsrp >= mLteRsrpThresholds[0]) {
+ } else {
rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 0874b86..8a3f138 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -395,6 +395,112 @@
}
/**
+ * Send a text based SMS with messaging options.
+ *
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is successfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending messages through same link or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ *
+ * @throws IllegalArgumentException if destinationAddress or text are empty
+ * {@hide}
+ */
+ public void sendTextMessage(
+ String destinationAddress, String scAddress, String text,
+ PendingIntent sentIntent, PendingIntent deliveryIntent,
+ int priority, boolean expectMore, int validityPeriod) {
+ sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
+ true /* persistMessage*/, priority, expectMore, validityPeriod);
+ }
+
+ private void sendTextMessageInternal(
+ String destinationAddress, String scAddress, String text,
+ PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
+ int priority, boolean expectMore, int validityPeriod) {
+ if (TextUtils.isEmpty(destinationAddress)) {
+ throw new IllegalArgumentException("Invalid destinationAddress");
+ }
+
+ if (TextUtils.isEmpty(text)) {
+ throw new IllegalArgumentException("Invalid message body");
+ }
+
+ if (priority < 0x00 || priority > 0x03) {
+ throw new IllegalArgumentException("Invalid priority");
+ }
+
+ if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
+ throw new IllegalArgumentException("Invalid validity period");
+ }
+
+ try {
+ ISms iccISms = getISmsServiceOrThrow();
+ if (iccISms != null) {
+ iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(),
+ ActivityThread.currentPackageName(), destinationAddress, scAddress, text,
+ sentIntent, deliveryIntent, persistMessage, priority, expectMore,
+ validityPeriod);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ /**
+ * Send a text based SMS without writing it into the SMS Provider.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
+ * privileges.
+ * </p>
+ *
+ * @see #sendTextMessage(String, String, String, PendingIntent,
+ * PendingIntent, int, boolean, int)
+ * @hide
+ */
+ public void sendTextMessageWithoutPersisting(
+ String destinationAddress, String scAddress, String text,
+ PendingIntent sentIntent, PendingIntent deliveryIntent, int priority,
+ boolean expectMore, int validityPeriod) {
+ sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
+ false /* persistMessage */, priority, expectMore, validityPeriod);
+ }
+
+ /**
+ *
* Inject an SMS PDU into the android application framework.
*
* <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
@@ -552,6 +658,140 @@
}
/**
+ * Send a multi-part text based SMS with messaging options. The callee should have already
+ * divided the message into correctly sized parts by calling
+ * <code>divideMessage</code>.
+ *
+ * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
+ * {@link android.Manifest.permission#SEND_SMS} permission.</p>
+ *
+ * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
+ * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
+ * writes messages sent using this method to the SMS Provider (the default SMS app is always
+ * responsible for writing its sent messages to the SMS Provider). For information about
+ * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
+ *
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending messages through same link or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ *
+ * @throws IllegalArgumentException if destinationAddress or data are empty
+ * {@hide}
+ */
+ public void sendMultipartTextMessage(
+ String destinationAddress, String scAddress, ArrayList<String> parts,
+ ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
+ int priority, boolean expectMore, int validityPeriod) {
+ sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
+ deliveryIntents, true /* persistMessage*/);
+ }
+
+ private void sendMultipartTextMessageInternal(
+ String destinationAddress, String scAddress, List<String> parts,
+ List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
+ boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
+ if (TextUtils.isEmpty(destinationAddress)) {
+ throw new IllegalArgumentException("Invalid destinationAddress");
+ }
+ if (parts == null || parts.size() < 1) {
+ throw new IllegalArgumentException("Invalid message body");
+ }
+
+ if (priority < 0x00 || priority > 0x03) {
+ throw new IllegalArgumentException("Invalid priority");
+ }
+
+ if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
+ throw new IllegalArgumentException("Invalid validity period");
+ }
+
+ if (parts.size() > 1) {
+ try {
+ ISms iccISms = getISmsServiceOrThrow();
+ if (iccISms != null) {
+ iccISms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
+ ActivityThread.currentPackageName(), destinationAddress, scAddress,
+ parts, sentIntents, deliveryIntents, persistMessage, priority,
+ expectMore, validityPeriod);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ } else {
+ PendingIntent sentIntent = null;
+ PendingIntent deliveryIntent = null;
+ if (sentIntents != null && sentIntents.size() > 0) {
+ sentIntent = sentIntents.get(0);
+ }
+ if (deliveryIntents != null && deliveryIntents.size() > 0) {
+ deliveryIntent = deliveryIntents.get(0);
+ }
+ sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
+ sentIntent, deliveryIntent, persistMessage, priority, expectMore,
+ validityPeriod);
+ }
+ }
+
+ /**
+ * Send a multi-part text based SMS without writing it into the SMS Provider.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
+ * privileges.
+ * </p>
+ *
+ * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
+ * ArrayList, int, boolean, int)
+ * @hide
+ **/
+ public void sendMultipartTextMessageWithoutPersisting(
+ String destinationAddress, String scAddress, List<String> parts,
+ List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
+ int priority, boolean expectMore, int validityPeriod) {
+ sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
+ deliveryIntents, false /* persistMessage*/, priority, expectMore,
+ validityPeriod);
+ }
+
+ /**
* Send a data based SMS to a specific application port.
*
* <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -1014,7 +1254,7 @@
* <code>getAllMessagesFromIcc</code>
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
*/
- private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
+ private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
if (records != null) {
int count = records.size();
@@ -1022,7 +1262,8 @@
SmsRawData data = records.get(i);
// List contains all records, including "free" records (null)
if (data != null) {
- SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
+ SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(),
+ getSubscriptionId());
if (sms != null) {
messages.add(sms);
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 577ea7d..9d03b59 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -277,6 +277,31 @@
}
/**
+ * Create an SmsMessage from an SMS EF record.
+ *
+ * @param index Index of SMS record. This should be index in ArrayList
+ * returned by SmsManager.getAllMessagesFromSim + 1.
+ * @param data Record data.
+ * @param subId Subscription Id of the SMS
+ * @return An SmsMessage representing the record.
+ *
+ * @hide
+ */
+ public static SmsMessage createFromEfRecord(int index, byte[] data, int subId) {
+ SmsMessageBase wrappedMessage;
+
+ if (isCdmaVoice(subId)) {
+ wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
+ index, data);
+ } else {
+ wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
+ index, data);
+ }
+
+ return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null;
+ }
+
+ /**
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
* length in bytes (not hex chars) less the SMSC header
*
@@ -836,6 +861,7 @@
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(subId);
return (PHONE_TYPE_CDMA == activePhone);
}
+
/**
* Decide if the carrier supports long SMS.
* {@hide}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index cdc1ba9..af3a0bb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5281,6 +5281,24 @@
}
/**
+ * Determines if emergency calling is allowed for the MMTEL feature on the slot provided.
+ * @param slotIndex The SIM slot of the MMTEL feature
+ * @return true if emergency calling is allowed, false otherwise.
+ * @hide
+ */
+ public boolean isEmergencyMmTelAvailable(int slotIndex) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isEmergencyMmTelAvailable(slotIndex);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "isEmergencyMmTelAvailable, RemoteException: " + e.getMessage());
+ }
+ return false;
+ }
+
+ /**
* Set IMS registration state
*
* @param Registration state
@@ -7183,18 +7201,16 @@
*
* @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
* subscription is unavailable or the carrier cannot be identified.
- * @throws IllegalStateException if telephony service is unavailable.
*/
public int getAndroidCarrierIdForSubscription() {
try {
ITelephony service = getITelephony();
- return service.getSubscriptionCarrierId(getSubId());
+ if (service != null) {
+ return service.getSubscriptionCarrierId(getSubId());
+ }
} catch (RemoteException ex) {
// This could happen if binder process crashes.
ex.rethrowAsRuntimeException();
- } catch (NullPointerException ex) {
- // This could happen before phone restarts due to crashing.
- throw new IllegalStateException("Telephony service unavailable");
}
return UNKNOWN_CARRIER_ID;
}
@@ -7210,18 +7226,16 @@
*
* @return Carrier name of the current subscription. Return {@code null} if the subscription is
* unavailable or the carrier cannot be identified.
- * @throws IllegalStateException if telephony service is unavailable.
*/
public CharSequence getAndroidCarrierNameForSubscription() {
try {
ITelephony service = getITelephony();
- return service.getSubscriptionCarrierName(getSubId());
+ if (service != null) {
+ return service.getSubscriptionCarrierName(getSubId());
+ }
} catch (RemoteException ex) {
// This could happen if binder process crashes.
ex.rethrowAsRuntimeException();
- } catch (NullPointerException ex) {
- // This could happen before phone restarts due to crashing.
- throw new IllegalStateException("Telephony service unavailable");
}
return null;
}
@@ -7669,4 +7683,83 @@
Log.e(TAG, "Error calling ITelephony#setUserDataEnabled", e);
}
}
+
+ /**
+ * In this mode, modem will not send specified indications when screen is off.
+ * @hide
+ */
+ public static final int INDICATION_UPDATE_MODE_NORMAL = 1;
+
+ /**
+ * In this mode, modem will still send specified indications when screen is off.
+ * @hide
+ */
+ public static final int INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "INDICATION_UPDATE_MODE_" }, value = {
+ INDICATION_UPDATE_MODE_NORMAL,
+ INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IndicationUpdateMode{}
+
+ /**
+ * The indication for signal strength update.
+ * @hide
+ */
+ public static final int INDICATION_FILTER_SIGNAL_STRENGTH = 0x1;
+
+ /**
+ * The indication for full network state update.
+ * @hide
+ */
+ public static final int INDICATION_FILTER_FULL_NETWORK_STATE = 0x2;
+
+ /**
+ * The indication for data call dormancy changed update.
+ * @hide
+ */
+ public static final int INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED = 0x4;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "INDICATION_FILTER_" }, value = {
+ INDICATION_FILTER_SIGNAL_STRENGTH,
+ INDICATION_FILTER_FULL_NETWORK_STATE,
+ INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IndicationFilters{}
+
+ /**
+ * Sets radio indication update mode. This can be used to control the behavior of indication
+ * update from modem to Android frameworks. For example, by default several indication updates
+ * are turned off when screen is off, but in some special cases (e.g. carkit is connected but
+ * screen is off) we want to turn on those indications even when the screen is off.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @param filters Indication filters. Should be a bitmask of INDICATION_FILTER_XXX.
+ * @see #INDICATION_FILTER_SIGNAL_STRENGTH
+ * @see #INDICATION_FILTER_FULL_NETWORK_STATE
+ * @see #INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED
+ * @param updateMode The voice activation state
+ * @see #INDICATION_UPDATE_MODE_NORMAL
+ * @see #INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setRadioIndicationUpdateMode(@IndicationFilters int filters,
+ @IndicationUpdateMode int updateMode) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setRadioIndicationUpdateMode(getSubId(), filters, updateMode);
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ ex.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 41c1430..e8597b2 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -17,6 +17,7 @@
package android.telephony.data;
import android.annotation.SystemApi;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -230,8 +231,10 @@
@Override
public String toString() {
- return "DataProfile=" + mProfileId + "/" + mApn + "/" + mProtocol + "/" + mAuthType
- + "/" + mUserName + "/" + mPassword + "/" + mType + "/" + mMaxConnsTime
+ return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType
+ + "/" + (Build.IS_USER ? "***/***/***" :
+ (mApn + "/" + mUserName + "/" + mPassword))
+ + "/" + mType + "/" + mMaxConnsTime
+ "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
+ mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
+ mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index c3f4007..38f9745 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -116,6 +116,9 @@
/** Result code of an unknown error. */
public static final int RESULT_UNKNOWN_ERROR = -1;
+ /** Result code when the eUICC card with the given card Id is not found. */
+ public static final int RESULT_EUICC_NOT_FOUND = -2;
+
/**
* Callback to receive the result of an eUICC card API.
*
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 1fdbae9..d537699 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -87,7 +87,9 @@
// ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
// defined values in ImsServiceClass for compatibility purposes.
/**
- * This feature supports emergency calling over MMTEL.
+ * This feature supports emergency calling over MMTEL. If defined, the framework will try to
+ * place an emergency call over IMS first. If it is not defined, the framework will only use
+ * CSFB for emergency calling.
*/
public static final int FEATURE_EMERGENCY_MMTEL = 0;
/**
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 09267fc..2fffd36 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -332,20 +332,14 @@
public static final int PROCESS_CALL_IMS = 0;
/**
* To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
- * not process the outgoing NON_EMERGENCY call as IMS and should instead use circuit switch.
+ * not process the outgoing call as IMS and should instead use circuit switch.
*/
public static final int PROCESS_CALL_CSFB = 1;
- /**
- * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
- * not process the outgoing EMERGENCY call as IMS and should instead use circuit switch.
- */
- public static final int PROCESS_CALL_EMERGENCY_CSFB = 2;
@IntDef(flag = true,
value = {
PROCESS_CALL_IMS,
- PROCESS_CALL_CSFB,
- PROCESS_CALL_EMERGENCY_CSFB
+ PROCESS_CALL_CSFB
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessCallResult {}
@@ -536,12 +530,15 @@
/**
* Called by the framework to determine if the outgoing call, designated by the outgoing
- * {@link Uri}s, should be processed as an IMS call or CSFB call.
+ * {@link String}s, should be processed as an IMS call or CSFB call. If this method's
+ * functionality is not overridden, the platform will process every call as IMS as long as the
+ * MmTelFeature reports that the {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE} capability is
+ * available.
* @param numbers An array of {@link String}s that will be used for placing the call. There can
* be multiple {@link String}s listed in the case when we want to place an outgoing
* call as a conference.
* @return a {@link ProcessCallResult} to the framework, which will be used to determine if the
- * call wil lbe placed over IMS or via CSFB.
+ * call will be placed over IMS or via CSFB.
*/
public @ProcessCallResult int shouldProcessCall(String[] numbers) {
return PROCESS_CALL_IMS;
diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
index 0673a38..0664a7e 100644
--- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
@@ -74,7 +74,9 @@
/** @hide */
@IntDef({
DELIVER_STATUS_OK,
- DELIVER_STATUS_ERROR
+ DELIVER_STATUS_ERROR_GENERIC,
+ DELIVER_STATUS_ERROR_NO_MEMORY,
+ DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeliverStatusResult {}
@@ -86,7 +88,17 @@
/**
* Message was not delivered.
*/
- public static final int DELIVER_STATUS_ERROR = 2;
+ public static final int DELIVER_STATUS_ERROR_GENERIC = 2;
+
+ /**
+ * Message was not delivered due to lack of memory.
+ */
+ public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3;
+
+ /**
+ * Message was not delivered as the request is not supported.
+ */
+ public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4;
/** @hide */
@IntDef({
@@ -106,7 +118,6 @@
*/
public static final int STATUS_REPORT_STATUS_ERROR = 2;
-
// Lock for feature synchronization
private final Object mLock = new Object();
private IImsSmsListener mListener;
@@ -157,7 +168,9 @@
* @param token token provided in {@link #onSmsReceived(int, String, byte[])}
* @param result result of delivering the message. Valid values are:
* {@link #DELIVER_STATUS_OK},
- * {@link #DELIVER_STATUS_ERROR}
+ * {@link #DELIVER_STATUS_ERROR_GENERIC},
+ * {@link #DELIVER_STATUS_ERROR_NO_MEMORY},
+ * {@link #DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED}
* @param messageRef the message reference
*/
public void acknowledgeSms(int token, @DeliverStatusResult int messageRef, int result) {
@@ -200,7 +213,7 @@
mListener.onSmsReceived(token, format, pdu);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
- acknowledgeSms(token, 0, DELIVER_STATUS_ERROR);
+ acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC);
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 8e3f4c0..1cfe8c2 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -21,6 +21,7 @@
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.VoLteServiceState;
@@ -37,6 +38,7 @@
void onDataConnectionStateChanged(int state, int networkType);
void onDataActivity(int direction);
void onSignalStrengthsChanged(in SignalStrength signalStrength);
+ void onPhysicalChannelConfigurationChanged(in List<PhysicalChannelConfig> configs);
void onOtaspChanged(in int otaspMode);
void onCellInfoChanged(in List<CellInfo> cellInfo);
void onPreciseCallStateChanged(in PreciseCallState callState);
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index fe37531..a4eb424 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -187,6 +187,57 @@
in PendingIntent deliveryIntent, in boolean persistMessage);
/**
+ * Send an SMS with options using Subscription Id.
+ *
+ * @param subId the subId on which the SMS has to be sent.
+ * @param destAddr the address to send the message to
+ * @param scAddr the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param persistMessageForNonDefaultSmsApp whether the sent message should
+ * be automatically persisted in the SMS db. It only affects messages sent
+ * by a non-default SMS app. Currently only the carrier app can set this
+ * parameter to false to skip auto message persistence.
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending message is multi segmented or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ */
+ void sendTextForSubscriberWithOptions(in int subId, String callingPkg, in String destAddr,
+ in String scAddr, in String text, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent, in boolean persistMessageForNonDefaultSmsApp,
+ in int priority, in boolean expectMore, in int validityPeriod);
+
+ /**
* Inject an SMS PDU into the android platform.
*
* @param subId the subId on which the SMS has to be injected.
@@ -234,6 +285,56 @@
in List<PendingIntent> deliveryIntents, in boolean persistMessageForNonDefaultSmsApp);
/**
+ * Send a multi-part text based SMS with options using Subscription Id.
+ *
+ * @param subId the subId on which the SMS has to be sent.
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code>
+ * <code>RESULT_ERROR_RADIO_OFF</code>
+ * <code>RESULT_ERROR_NULL_PDU</code>.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param persistMessageForNonDefaultSmsApp whether the sent message should
+ * be automatically persisted in the SMS db. It only affects messages sent
+ * by a non-default SMS app. Currently only the carrier app can set this
+ * parameter to false to skip auto message persistence.
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending message is multi segmented or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ */
+ void sendMultipartTextForSubscriberWithOptions(in int subId, String callingPkg,
+ in String destinationAddress, in String scAddress, in List<String> parts,
+ in List<PendingIntent> sentIntents, in List<PendingIntent> deliveryIntents,
+ in boolean persistMessageForNonDefaultSmsApp, in int priority, in boolean expectMore,
+ in int validityPeriod);
+
+ /**
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier and RAN type. The RAN type specify this message ID
* belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9e2b519..a941a56 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -823,6 +823,12 @@
IImsConfig getImsConfig(int slotId, int feature);
/**
+ * Returns true if emergency calling is available for the MMTEL feature associated with the
+ * slot specified.
+ */
+ boolean isEmergencyMmTelAvailable(int slotId);
+
+ /**
* Set the network selection mode to automatic.
*
* @param subId the id of the subscription to update.
@@ -1473,4 +1479,12 @@
* @return boolean Return true if the switch succeeds, false if the switch fails.
*/
boolean switchSlots(in int[] physicalSlots);
+
+ /**
+ * Sets radio indication update mode. This can be used to control the behavior of indication
+ * update from modem to Android frameworks. For example, by default several indication updates
+ * are turned off when screen is off, but in some special cases (e.g. carkit is connected but
+ * screen is off) we want to turn on those indications even when the screen is off.
+ */
+ void setRadioIndicationUpdateMode(int subId, int filters, int mode);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 188167c..06dc13e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -21,9 +21,9 @@
import android.net.NetworkCapabilities;
import android.os.Bundle;
import android.telephony.CellInfo;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
-import android.telephony.CellInfo;
import android.telephony.VoLteServiceState;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -58,6 +58,9 @@
void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
void notifyCellInfo(in List<CellInfo> cellInfo);
+ void notifyPhysicalChannelConfiguration(in List<PhysicalChannelConfig> configs);
+ void notifyPhysicalChannelConfigurationForSubscriber(in int subId,
+ in List<PhysicalChannelConfig> configs);
void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
int backgroundCallState);
void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 7a53ef6..14c5f4b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -99,6 +99,15 @@
private static final int RETURN_NO_ACK = 0;
private static final int RETURN_ACK = 1;
+ /**
+ * Supported priority modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
+ */
+ private static final int PRIORITY_NORMAL = 0x0;
+ private static final int PRIORITY_INTERACTIVE = 0x1;
+ private static final int PRIORITY_URGENT = 0x2;
+ private static final int PRIORITY_EMERGENCY = 0x3;
+
private SmsEnvelope mEnvelope;
private BearerData mBearerData;
@@ -211,6 +220,26 @@
*/
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
boolean statusReportRequested, SmsHeader smsHeader) {
+ return getSubmitPdu(scAddr, destAddr, message, statusReportRequested, smsHeader, -1);
+ }
+
+ /**
+ * Get an SMS-SUBMIT PDU for a destination address and a message
+ *
+ * @param scAddr Service Centre address. Null means use default.
+ * @param destAddr Address of the recipient.
+ * @param message String representation of the message payload.
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @param smsHeader Array containing the data for the User Data Header, preceded
+ * by the Element Identifiers.
+ * @param priority Priority level of the message
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
+ boolean statusReportRequested, SmsHeader smsHeader, int priority) {
/**
* TODO(cleanup): Do we really want silent failure like this?
@@ -224,7 +253,7 @@
UserData uData = new UserData();
uData.payloadStr = message;
uData.userDataHeader = smsHeader;
- return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
+ return privateGetSubmitPdu(destAddr, statusReportRequested, uData, priority);
}
/**
@@ -282,6 +311,22 @@
}
/**
+ * Get an SMS-SUBMIT PDU for a data message to a destination address & port
+ *
+ * @param destAddr the address of the destination for the message
+ * @param userData the data for the message
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @param priority Priority level of the message
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
+ boolean statusReportRequested, int priority) {
+ return privateGetSubmitPdu(destAddr, statusReportRequested, userData, priority);
+ }
+
+ /**
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
*/
@Override
@@ -764,6 +809,15 @@
*/
private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
UserData userData) {
+ return privateGetSubmitPdu(destAddrStr, statusReportRequested, userData, -1);
+ }
+
+ /**
+ * Creates BearerData and Envelope from parameters for a Submit SMS.
+ * @return byte stream for SubmitPdu.
+ */
+ private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
+ UserData userData, int priority) {
/**
* TODO(cleanup): give this function a more meaningful name.
@@ -792,6 +846,10 @@
bearerData.userAckReq = false;
bearerData.readAckReq = false;
bearerData.reportReq = false;
+ if (priority >= PRIORITY_NORMAL && priority <= PRIORITY_EMERGENCY) {
+ bearerData.priorityIndicatorSet = true;
+ bearerData.priority = priority;
+ }
bearerData.userData = userData;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 1ca19e0..4f5bfa9 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -89,6 +89,18 @@
private int mVoiceMailCount = 0;
+ private static final int VALIDITY_PERIOD_FORMAT_NONE = 0x00;
+ private static final int VALIDITY_PERIOD_FORMAT_ENHANCED = 0x01;
+ private static final int VALIDITY_PERIOD_FORMAT_RELATIVE = 0x02;
+ private static final int VALIDITY_PERIOD_FORMAT_ABSOLUTE = 0x03;
+
+ //Validity Period min - 5 mins
+ private static final int VALIDITY_PERIOD_MIN = 5;
+ //Validity Period max - 63 weeks
+ private static final int VALIDITY_PERIOD_MAX = 635040;
+
+ private static final int INVALID_VALIDITY_PERIOD = -1;
+
public static class SubmitPdu extends SubmitPduBase {
}
@@ -202,6 +214,45 @@
}
/**
+ * Get Encoded Relative Validty Period Value from Validity period in mins.
+ *
+ * @param validityPeriod Validity period in mins.
+ *
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * ||relValidityPeriod (TP-VP) || || validityPeriod ||
+ *
+ * 0 to 143 ---> (TP-VP + 1) x 5 minutes
+ *
+ * 144 to 167 ---> 12 hours + ((TP-VP -143) x 30 minutes)
+ *
+ * 168 to 196 ---> (TP-VP - 166) x 1 day
+ *
+ * 197 to 255 ---> (TP-VP - 192) x 1 week
+ *
+ * @return relValidityPeriod Encoded Relative Validity Period Value.
+ * @hide
+ */
+ public static int getRelativeValidityPeriod(int validityPeriod) {
+ int relValidityPeriod = INVALID_VALIDITY_PERIOD;
+
+ if (validityPeriod < VALIDITY_PERIOD_MIN || validityPeriod > VALIDITY_PERIOD_MAX) {
+ Rlog.e(LOG_TAG,"Invalid Validity Period" + validityPeriod);
+ return relValidityPeriod;
+ }
+
+ if (validityPeriod <= 720) {
+ relValidityPeriod = (validityPeriod / 5) - 1;
+ } else if (validityPeriod <= 1440) {
+ relValidityPeriod = ((validityPeriod - 720) / 30) + 143;
+ } else if (validityPeriod <= 43200) {
+ relValidityPeriod = (validityPeriod / 1440) + 166;
+ } else if (validityPeriod <= 635040) {
+ relValidityPeriod = (validityPeriod / 10080) + 192;
+ }
+ return relValidityPeriod;
+ }
+
+ /**
* Get an SMS-SUBMIT PDU for a destination address and a message
*
* @param scAddress Service Centre address. Null means use default.
@@ -236,6 +287,29 @@
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
+ header, encoding, languageTable, languageShiftTable, -1);
+ }
+
+ /**
+ * Get an SMS-SUBMIT PDU for a destination address and a message using the
+ * specified encoding.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param encoding Encoding defined by constants in
+ * com.android.internal.telephony.SmsConstants.ENCODING_*
+ * @param languageTable
+ * @param languageShiftTable
+ * @param validityPeriod Validity Period of the message in Minutes.
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested, byte[] header, int encoding,
+ int languageTable, int languageShiftTable, int validityPeriod) {
// Perform null parameter checks.
if (message == null || destinationAddress == null) {
@@ -272,8 +346,19 @@
}
SubmitPdu ret = new SubmitPdu();
- // MTI = SMS-SUBMIT, UDHI = header != null
- byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
+
+ int validityPeriodFormat = VALIDITY_PERIOD_FORMAT_NONE;
+ int relativeValidityPeriod = INVALID_VALIDITY_PERIOD;
+
+ // TP-Validity-Period-Format (TP-VPF) in 3GPP TS 23.040 V6.8.1 section 9.2.3.3
+ //bit 4:3 = 10 - TP-VP field present - relative format
+ if((relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod)) >= 0) {
+ validityPeriodFormat = VALIDITY_PERIOD_FORMAT_RELATIVE;
+ }
+
+ byte mtiByte = (byte)(0x01 | (validityPeriodFormat << 0x03) |
+ (header != null ? 0x40 : 0x00));
+
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
statusReportRequested, ret);
@@ -338,7 +423,11 @@
bo.write(0x08);
}
- // (no TP-Validity-Period)
+ if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) {
+ // ( TP-Validity-Period - relative format)
+ bo.write(relativeValidityPeriod);
+ }
+
bo.write(userData, 0, userData.length);
ret.encodedMessage = bo.toByteArray();
return ret;
@@ -388,6 +477,24 @@
}
/**
+ * Get an SMS-SUBMIT PDU for a destination address and a message
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message
+ * @param statusReportRequested staus report of the message Requested
+ * @param validityPeriod Validity Period of the message in Minutes.
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested, int validityPeriod) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
+ null, ENCODING_UNKNOWN, 0, 0, validityPeriod);
+ }
+
+ /**
* Get an SMS-SUBMIT PDU for a data message to a destination address & port
*
* @param scAddress Service Centre address. null == use default
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 54e07a16..bb07363 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -19,7 +19,6 @@
java_library {
name: "android.test.mock",
- // Needs to be consistent with the repackaged version of this make target.
java_version: "1.8",
srcs: ["src/**/*.java"],
@@ -28,15 +27,3 @@
"framework",
],
}
-
-// Build the repackaged.android.test.mock library
-// ==============================================
-java_library_static {
- name: "repackaged.android.test.mock",
-
- static_libs: ["android.test.mock"],
-
- jarjar_rules: "jarjar-rules.txt",
- // Pin java_version until jarjar is certified to support later versions. http://b/72703434
- java_version: "1.8",
-}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index c69279b..1cce2c3 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -24,7 +24,7 @@
srcs: ["src/**/*.java"],
errorprone: {
- javacflags: ["-Xep:DepAnn:ERROR"],
+ javacflags: ["-Xep:DepAnn:ERROR"],
},
sdk_version: "current",
@@ -56,8 +56,21 @@
java_library_static {
name: "repackaged.android.test.runner",
+ srcs: ["src/**/*.java"],
+ exclude_srcs: [
+ "src/android/test/ActivityUnitTestCase.java",
+ "src/android/test/ApplicationTestCase.java",
+ "src/android/test/IsolatedContext.java",
+ "src/android/test/ProviderTestCase.java",
+ "src/android/test/ProviderTestCase2.java",
+ "src/android/test/RenamingDelegatingContext.java",
+ "src/android/test/ServiceTestCase.java",
+ ],
+
sdk_version: "current",
- static_libs: ["android.test.runner"],
+ libs: [
+ "android.test.base",
+ ],
jarjar_rules: "jarjar-rules.txt",
// Pin java_version until jarjar is certified to support later versions. http://b/72703434
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
index 1a4f6d5..f97d1c9 100644
--- a/test-runner/tests/Android.mk
+++ b/test-runner/tests/Android.mk
@@ -32,6 +32,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests
+# Because of android.test.mock.
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/AccessibilityEventsLogger/Android.mk b/tests/AccessibilityEventsLogger/Android.mk
index 52bc579..4224017 100644
--- a/tests/AccessibilityEventsLogger/Android.mk
+++ b/tests/AccessibilityEventsLogger/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := AccessibilityEventsLogger
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/ActivityManagerPerfTests/README.txt b/tests/ActivityManagerPerfTests/README.txt
index 2686290..1560262 100644
--- a/tests/ActivityManagerPerfTests/README.txt
+++ b/tests/ActivityManagerPerfTests/README.txt
@@ -49,5 +49,7 @@
can be reported in an iteration
* If the target package should be running before your test logic starts, add startTargetPackage();
at the beginning of the iteration
+
* Reporting
- * Look at go/am-perf for how to add new tests to dashboards and receive notification on regression
+ * Look at internal documentation for how to add new tests to dashboards and receive notification
+ on regressions
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk
index 767e899..33d15d2 100644
--- a/tests/ActivityManagerPerfTests/test-app/Android.mk
+++ b/tests/ActivityManagerPerfTests/test-app/Android.mk
@@ -26,5 +26,6 @@
LOCAL_MIN_SDK_VERSION := 25
LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp
+LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk
index 7597e69..f23a665 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.mk
+++ b/tests/ActivityManagerPerfTests/tests/Android.mk
@@ -26,6 +26,7 @@
ActivityManagerPerfTestsUtils
LOCAL_PACKAGE_NAME := ActivityManagerPerfTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MIN_SDK_VERSION := 25
diff --git a/tests/ActivityManagerPerfTests/utils/Android.mk b/tests/ActivityManagerPerfTests/utils/Android.mk
index 7276e37..60c9423 100644
--- a/tests/ActivityManagerPerfTests/utils/Android.mk
+++ b/tests/ActivityManagerPerfTests/utils/Android.mk
@@ -16,6 +16,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index f3c6b5a..274fc5f 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := ActivityTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk
index 917293f..1fb548b 100644
--- a/tests/AppLaunch/Android.mk
+++ b/tests/AppLaunch/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := AppLaunch
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
diff --git a/tests/Assist/Android.mk b/tests/Assist/Android.mk
index f31c4dd..d0d3eca 100644
--- a/tests/Assist/Android.mk
+++ b/tests/Assist/Android.mk
@@ -6,5 +6,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Assist
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
index da1a08b..b10305d 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
@@ -27,6 +27,7 @@
android-support-test \
LOCAL_PACKAGE_NAME := BackgroundDexOptServiceIntegrationTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/tests/BandwidthTests/Android.mk b/tests/BandwidthTests/Android.mk
index 7bc5f857..d00fdc6 100644
--- a/tests/BandwidthTests/Android.mk
+++ b/tests/BandwidthTests/Android.mk
@@ -19,6 +19,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := BandwidthEnforcementTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
include $(BUILD_PACKAGE)
diff --git a/tests/BatteryWaster/Android.mk b/tests/BatteryWaster/Android.mk
index 6db34a7..fb244a8 100644
--- a/tests/BatteryWaster/Android.mk
+++ b/tests/BatteryWaster/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := BatteryWaster
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/BiDiTests/Android.mk b/tests/BiDiTests/Android.mk
index ae29fc2..78cf4be 100644
--- a/tests/BiDiTests/Android.mk
+++ b/tests/BiDiTests/Android.mk
@@ -21,6 +21,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := BiDiTests
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk
index 5765575..0934889 100644
--- a/tests/BrowserPowerTest/Android.mk
+++ b/tests/BrowserPowerTest/Android.mk
@@ -25,6 +25,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := BrowserPowerTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
#LOCAL_INSTRUMENTATION_FOR := browserpowertest
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
index 9e7f618..a900077 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
@@ -19,6 +19,7 @@
LOCAL_MODULE_TAGS := tests
# LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PACKAGE_NAME := SmartCamera-tests
diff --git a/tests/CameraPrewarmTest/Android.mk b/tests/CameraPrewarmTest/Android.mk
index b6316f0..e128504 100644
--- a/tests/CameraPrewarmTest/Android.mk
+++ b/tests/CameraPrewarmTest/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := CameraPrewarmTest
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk
index b071ec4..6a0a93e 100644
--- a/tests/CanvasCompare/Android.mk
+++ b/tests/CanvasCompare/Android.mk
@@ -20,6 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
LOCAL_PACKAGE_NAME := CanvasCompare
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
index 82e2126..9c47a26 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -24,6 +24,7 @@
LOCAL_PACKAGE_NAME := AppCompatibilityTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk
index 85f7edf..bcf3599 100644
--- a/tests/DataIdleTest/Android.mk
+++ b/tests/DataIdleTest/Android.mk
@@ -20,6 +20,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := DataIdleTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
index 7187a37..ee2ec0a 100644
--- a/tests/DexLoggerIntegrationTests/Android.mk
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -35,6 +35,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := DexLoggerIntegrationTests
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm)
diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk
index 01f10e5..ec250ff 100644
--- a/tests/DozeTest/Android.mk
+++ b/tests/DozeTest/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := DozeTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/DpiTest/Android.mk b/tests/DpiTest/Android.mk
index f55ce6e..e69d082 100644
--- a/tests/DpiTest/Android.mk
+++ b/tests/DpiTest/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := DensityTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk
index 6da1b38..8646460 100644
--- a/tests/FeatureSplit/base/Android.mk
+++ b/tests/FeatureSplit/base/Android.mk
@@ -20,6 +20,7 @@
LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := FeatureSplitBase
+LOCAL_SDK_VERSION := current
LOCAL_EXPORT_PACKAGE_RESOURCES := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk
index e6ba5c2..d4d2589 100644
--- a/tests/FeatureSplit/feature1/Android.mk
+++ b/tests/FeatureSplit/feature1/Android.mk
@@ -20,6 +20,7 @@
LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := FeatureSplit1
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
LOCAL_APK_LIBRARIES := FeatureSplitBase
diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk
index c8e8609..5e5e78b 100644
--- a/tests/FeatureSplit/feature2/Android.mk
+++ b/tests/FeatureSplit/feature2/Android.mk
@@ -20,6 +20,7 @@
LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := FeatureSplit2
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
LOCAL_APK_LIBRARIES := FeatureSplitBase
diff --git a/tests/FixVibrateSetting/Android.mk b/tests/FixVibrateSetting/Android.mk
index 2a88e5a..86db09e 100644
--- a/tests/FixVibrateSetting/Android.mk
+++ b/tests/FixVibrateSetting/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := FixVibrateSetting
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk
index 1873cc1..0664d4d 100644
--- a/tests/FrameworkPerf/Android.mk
+++ b/tests/FrameworkPerf/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := FrameworkPerf
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/tests/GridLayoutTest/Android.mk b/tests/GridLayoutTest/Android.mk
index a02918b..e7e3ccd 100644
--- a/tests/GridLayoutTest/Android.mk
+++ b/tests/GridLayoutTest/Android.mk
@@ -20,6 +20,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := GridLayoutTest
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk
index 8550d70..cf1a512 100644
--- a/tests/HierarchyViewerTest/Android.mk
+++ b/tests/HierarchyViewerTest/Android.mk
@@ -6,8 +6,9 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := HierarchyViewerTest
+LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
LOCAL_STATIC_JAVA_LIBRARIES := junit
include $(BUILD_PACKAGE)
diff --git a/tests/HwAccelerationTest/Android.mk b/tests/HwAccelerationTest/Android.mk
index d4743f9..11ea954 100644
--- a/tests/HwAccelerationTest/Android.mk
+++ b/tests/HwAccelerationTest/Android.mk
@@ -20,6 +20,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := HwAccelerationTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk
index eb5327b..a8f5b08 100644
--- a/tests/ImfTest/Android.mk
+++ b/tests/ImfTest/Android.mk
@@ -8,6 +8,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ImfTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
index a0df959..14186d7 100644
--- a/tests/ImfTest/tests/Android.mk
+++ b/tests/ImfTest/tests/Android.mk
@@ -11,6 +11,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := ImfTestTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_INSTRUMENTATION_FOR := ImfTest
diff --git a/tests/Internal/Android.mk b/tests/Internal/Android.mk
index b69e3e4..da56696 100644
--- a/tests/Internal/Android.mk
+++ b/tests/Internal/Android.mk
@@ -18,6 +18,7 @@
LOCAL_CERTIFICATE := platform
LOCAL_PACKAGE_NAME := InternalTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/tests/JobSchedulerTestApp/Android.mk b/tests/JobSchedulerTestApp/Android.mk
index 7336d8c..48ee1f6 100644
--- a/tests/JobSchedulerTestApp/Android.mk
+++ b/tests/JobSchedulerTestApp/Android.mk
@@ -8,6 +8,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := JobSchedulerTestApp
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/LargeAssetTest/Android.mk b/tests/LargeAssetTest/Android.mk
index cb7f01b..f6d98bf 100644
--- a/tests/LargeAssetTest/Android.mk
+++ b/tests/LargeAssetTest/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := LargeAssetTest
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/LegacyAssistant/Android.mk b/tests/LegacyAssistant/Android.mk
index 0ad48d1..a583369 100644
--- a/tests/LegacyAssistant/Android.mk
+++ b/tests/LegacyAssistant/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := LegacyAssistant
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
diff --git a/tests/LocationTracker/Android.mk b/tests/LocationTracker/Android.mk
index b142d22..0d51b3b 100644
--- a/tests/LocationTracker/Android.mk
+++ b/tests/LocationTracker/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := LocationTracker
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
diff --git a/tests/LockTaskTests/Android.mk b/tests/LockTaskTests/Android.mk
index ed58643..a693eaa 100644
--- a/tests/LockTaskTests/Android.mk
+++ b/tests/LockTaskTests/Android.mk
@@ -5,6 +5,7 @@
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app
LOCAL_PACKAGE_NAME := LockTaskTests
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(call all-Iaidl-files-under, src) $(call all-java-files-under, src)
diff --git a/tests/LotsOfApps/Android.mk b/tests/LotsOfApps/Android.mk
index 0ef9550..bee3bcc 100644
--- a/tests/LotsOfApps/Android.mk
+++ b/tests/LotsOfApps/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := LotsOfApps
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/LowStorageTest/Android.mk b/tests/LowStorageTest/Android.mk
index ab5b9e9..bdde6bd 100644
--- a/tests/LowStorageTest/Android.mk
+++ b/tests/LowStorageTest/Android.mk
@@ -21,5 +21,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := lowstoragetest
+LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk
index e186e9f..5040d5a 100644
--- a/tests/MemoryUsage/Android.mk
+++ b/tests/MemoryUsage/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MemoryUsage
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index 6fb6025..fe65ecc 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -17,5 +17,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := NetworkSecurityConfigTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk
index 9fc6403..41f3f64 100644
--- a/tests/OneMedia/Android.mk
+++ b/tests/OneMedia/Android.mk
@@ -7,6 +7,7 @@
$(call all-Iaidl-files-under, src)
LOCAL_PACKAGE_NAME := OneMedia
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk
index 2f4b343..e827ec2 100644
--- a/tests/RemoteDisplayProvider/Android.mk
+++ b/tests/RemoteDisplayProvider/Android.mk
@@ -21,6 +21,6 @@
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay
+LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay.stubs
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/RenderThreadTest/Android.mk b/tests/RenderThreadTest/Android.mk
index e07e943..4e5f35b 100644
--- a/tests/RenderThreadTest/Android.mk
+++ b/tests/RenderThreadTest/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := RenderThreadTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES += android-common
diff --git a/tests/SerialChat/Android.mk b/tests/SerialChat/Android.mk
index a534e1a..ed6ca999 100644
--- a/tests/SerialChat/Android.mk
+++ b/tests/SerialChat/Android.mk
@@ -22,5 +22,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SerialChat
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk
index f7b3452..d1f6450 100644
--- a/tests/ServiceCrashTest/Android.mk
+++ b/tests/ServiceCrashTest/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ServiceCrashTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := android.test.base
diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk
index a04fb05..9e76c40 100644
--- a/tests/SharedLibrary/client/Android.mk
+++ b/tests/SharedLibrary/client/Android.mk
@@ -7,6 +7,7 @@
LOCAL_RES_LIBRARIES := SharedLibrary
LOCAL_PACKAGE_NAME := SharedLibraryClient
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk
index 78fcb8b..3c1ca87 100644
--- a/tests/SharedLibrary/lib/Android.mk
+++ b/tests/SharedLibrary/lib/Android.mk
@@ -6,6 +6,7 @@
LOCAL_AAPT_FLAGS := --shared-lib
LOCAL_PACKAGE_NAME := SharedLibrary
+LOCAL_SDK_VERSION := current
LOCAL_EXPORT_PACKAGE_RESOURCES := true
LOCAL_PRIVILEGED_MODULE := true
diff --git a/tests/ShowWhenLockedApp/Android.mk b/tests/ShowWhenLockedApp/Android.mk
index 0064167..41e0ac4 100644
--- a/tests/ShowWhenLockedApp/Android.mk
+++ b/tests/ShowWhenLockedApp/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := ShowWhenLocked
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
diff --git a/tests/SmokeTestApps/Android.mk b/tests/SmokeTestApps/Android.mk
index 3f5f011..1f564e0 100644
--- a/tests/SmokeTestApps/Android.mk
+++ b/tests/SmokeTestApps/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := SmokeTestTriggerApps
+LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
diff --git a/tests/SoundTriggerTestApp/Android.mk b/tests/SoundTriggerTestApp/Android.mk
index c327b09..73fb5e8 100644
--- a/tests/SoundTriggerTestApp/Android.mk
+++ b/tests/SoundTriggerTestApp/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SoundTriggerTestApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := optional
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index 030d5f4..204a74e 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -31,5 +31,6 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := SoundTriggerTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk
index b068bef..4d15b2d 100644
--- a/tests/Split/Android.mk
+++ b/tests/Split/Android.mk
@@ -19,6 +19,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Split
+LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4
diff --git a/tests/StatusBar/Android.mk b/tests/StatusBar/Android.mk
index 502657f..e845335 100644
--- a/tests/StatusBar/Android.mk
+++ b/tests/StatusBar/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := StatusBarTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/SystemUIDemoModeController/Android.mk b/tests/SystemUIDemoModeController/Android.mk
index 64ea63c..cc6fa8d 100644
--- a/tests/SystemUIDemoModeController/Android.mk
+++ b/tests/SystemUIDemoModeController/Android.mk
@@ -6,5 +6,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := DemoModeController
+LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
diff --git a/tests/TouchLatency/Android.mk b/tests/TouchLatency/Android.mk
index 969283d..2334bd8 100644
--- a/tests/TouchLatency/Android.mk
+++ b/tests/TouchLatency/Android.mk
@@ -15,6 +15,7 @@
--auto-add-overlay
LOCAL_PACKAGE_NAME := TouchLatency
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/tests/TransformTest/Android.mk b/tests/TransformTest/Android.mk
index 2d3637d..5340cdd 100644
--- a/tests/TransformTest/Android.mk
+++ b/tests/TransformTest/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := TransformTest
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
diff --git a/tests/TransitionTests/Android.mk b/tests/TransitionTests/Android.mk
index 22fa638..a696156 100644
--- a/tests/TransitionTests/Android.mk
+++ b/tests/TransitionTests/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := TransitionTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES += android-common
diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk
index 2fa1950..116cc0a 100644
--- a/tests/TtsTests/Android.mk
+++ b/tests/TtsTests/Android.mk
@@ -24,5 +24,6 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := TtsTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/UsageStatsTest/Android.mk b/tests/UsageStatsTest/Android.mk
index 6b5c999..6735c7c 100644
--- a/tests/UsageStatsTest/Android.mk
+++ b/tests/UsageStatsTest/Android.mk
@@ -11,5 +11,6 @@
LOCAL_CERTIFICATE := platform
LOCAL_PACKAGE_NAME := UsageStatsTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
index 3137a73..cd7aaed 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
@@ -25,6 +25,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AoapTestDeviceApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
index 354e8c9..bd8a51b 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
@@ -25,6 +25,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AoapTestHostApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
index 2d6d6ea8..fed454e 100644
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
@@ -25,6 +25,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := UsbHostExternalManagementTestApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PRIVILEGED_MODULE := true
# TODO remove tests tag
diff --git a/tests/UsbTests/Android.mk b/tests/UsbTests/Android.mk
index a04f32a..4e215cc 100644
--- a/tests/UsbTests/Android.mk
+++ b/tests/UsbTests/Android.mk
@@ -38,6 +38,7 @@
LOCAL_CERTIFICATE := platform
LOCAL_PACKAGE_NAME := UsbTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/tests/UsbTests/res/raw/readme.txt b/tests/UsbTests/res/raw/readme.txt
new file mode 100644
index 0000000..62b673c
--- /dev/null
+++ b/tests/UsbTests/res/raw/readme.txt
@@ -0,0 +1,35 @@
+The usbdescriptors_ files contain raw USB descriptors from the Google
+USB-C to 3.5mm adapter, with different loads connected to the 3.5mm
+jack.
+
+usbdescriptors_nothing.bin:
+ - The descriptors when the jack is disconnected.
+
+usbdescriptors_headphones.bin:
+ - The descriptors when the jack is connected to 32-ohm headphones,
+ no microphone.
+ The relevant output terminal is:
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
+ bTerminalID 15
+ wTerminalType 0x0302 Headphones
+
+usbdescriptors_lineout.bin:
+ - The descriptors when the jack is connected to a PC line-in jack.
+ The relevant output terminal is:
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
+ bTerminalID 15
+ wTerminalType 0x0603 Line Connector
+
+usbdescriptors_headset.bin:
+ - The descriptors when a headset with microphone and low-impedance
+ headphones are connected.
+ The relevant input terminal is:
+ bDescriptorSubtype 2 (INPUT_TERMINAL)
+ bTerminalID 1
+ wTerminalType 0x0201 Microphone
+ The relevant output terminal is:
+ bDescriptorSubtype 3 (OUTPUT_TERMINAL)
+ bTerminalID 15
+ wTerminalType 0x0302 Headphones
+
+
diff --git a/tests/UsbTests/res/raw/usbdescriptors_headphones.bin b/tests/UsbTests/res/raw/usbdescriptors_headphones.bin
new file mode 100644
index 0000000..e8f2932
--- /dev/null
+++ b/tests/UsbTests/res/raw/usbdescriptors_headphones.bin
Binary files differ
diff --git a/tests/UsbTests/res/raw/usbdescriptors_headset.bin b/tests/UsbTests/res/raw/usbdescriptors_headset.bin
new file mode 100644
index 0000000..30eef2a
--- /dev/null
+++ b/tests/UsbTests/res/raw/usbdescriptors_headset.bin
Binary files differ
diff --git a/tests/UsbTests/res/raw/usbdescriptors_lineout.bin b/tests/UsbTests/res/raw/usbdescriptors_lineout.bin
new file mode 100644
index 0000000..d540d33
--- /dev/null
+++ b/tests/UsbTests/res/raw/usbdescriptors_lineout.bin
Binary files differ
diff --git a/tests/UsbTests/res/raw/usbdescriptors_nothing.bin b/tests/UsbTests/res/raw/usbdescriptors_nothing.bin
new file mode 100644
index 0000000..c318abf
--- /dev/null
+++ b/tests/UsbTests/res/raw/usbdescriptors_nothing.bin
Binary files differ
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java
new file mode 100644
index 0000000..f323952
--- /dev/null
+++ b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 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.usb;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.usb.descriptors.UsbDescriptorParser;
+import com.google.common.io.ByteStreams;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.lang.Exception;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link com.android.server.usb.descriptors.UsbDescriptorParser}
+ */
+@RunWith(AndroidJUnit4.class)
+public class UsbDescriptorParserTests {
+
+ public UsbDescriptorParser loadParser(int resource) {
+ Context c = InstrumentationRegistry.getContext();
+ Resources res = c.getResources();
+ InputStream is = null;
+ try {
+ is = res.openRawResource(resource);
+ } catch (NotFoundException e) {
+ fail("Failed to load resource.");
+ }
+
+ byte[] descriptors = null;
+ try {
+ descriptors = ByteStreams.toByteArray(is);
+ } catch (IOException e) {
+ fail("Failed to convert descriptor strema to bytearray.");
+ }
+
+ // Testing same codepath as UsbHostManager.java:usbDeviceAdded
+ UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr");
+ if (!parser.parseDescriptors(descriptors)) {
+ fail("failed to parse descriptors.");
+ }
+ return parser;
+ }
+
+ // A Headset has a microphone and a speaker and is a headset.
+ @Test
+ @SmallTest
+ public void testHeadsetDescriptorParser() {
+ UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_headset);
+ assertTrue(parser.hasInput());
+ assertTrue(parser.hasOutput());
+ assertTrue(parser.isInputHeadset());
+ assertTrue(parser.isOutputHeadset());
+ }
+
+ // Headphones have no microphones but are considered a headset.
+ @Test
+ @SmallTest
+ public void testHeadphoneDescriptorParser() {
+ UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_headphones);
+ assertFalse(parser.hasInput());
+ assertTrue(parser.hasOutput());
+ assertFalse(parser.isInputHeadset());
+ assertTrue(parser.isOutputHeadset());
+ }
+
+ // Line out has no microphones and aren't considered a headset.
+ @Test
+ @SmallTest
+ public void testLineoutDescriptorParser() {
+ UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_lineout);
+ assertFalse(parser.hasInput());
+ assertTrue(parser.hasOutput());
+ assertFalse(parser.isInputHeadset());
+ assertFalse(parser.isOutputHeadset());
+ }
+
+ // An HID-only device shouldn't be considered anything at all.
+ @Test
+ @SmallTest
+ public void testNothingDescriptorParser() {
+ UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_nothing);
+ assertFalse(parser.hasInput());
+ assertFalse(parser.hasOutput());
+ assertFalse(parser.isInputHeadset());
+ assertFalse(parser.isOutputHeadset());
+ }
+
+}
diff --git a/tests/UsesFeature2Test/Android.mk b/tests/UsesFeature2Test/Android.mk
index cc784d7..4cba4ff 100644
--- a/tests/UsesFeature2Test/Android.mk
+++ b/tests/UsesFeature2Test/Android.mk
@@ -19,6 +19,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := UsesFeature2Test
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk
index dd8a4d4..155b2bc 100644
--- a/tests/VectorDrawableTest/Android.mk
+++ b/tests/VectorDrawableTest/Android.mk
@@ -20,6 +20,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := VectorDrawableTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk
index 2ab3d02..725e2bd 100644
--- a/tests/VoiceEnrollment/Android.mk
+++ b/tests/VoiceEnrollment/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := VoiceEnrollment
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := optional
diff --git a/tests/VoiceInteraction/Android.mk b/tests/VoiceInteraction/Android.mk
index 8decca7..aa48b42 100644
--- a/tests/VoiceInteraction/Android.mk
+++ b/tests/VoiceInteraction/Android.mk
@@ -6,5 +6,6 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := VoiceInteraction
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 0401737..db48984 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -57,7 +57,9 @@
Button mCompleteButton;
Button mAbortButton;
+ Bundle mAssistData;
AssistStructure mAssistStructure;
+ AssistContent mAssistContent;
static final int STATE_IDLE = 0;
static final int STATE_LAUNCHING = 1;
@@ -169,19 +171,15 @@
public void onHandleAssist(Bundle assistBundle) {
}
- @Override
- public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
- mAssistStructure = structure;
- if (mAssistVisualizer != null) {
- if (mAssistStructure != null) {
- mAssistVisualizer.setAssistStructure(mAssistStructure);
- } else {
- mAssistVisualizer.clearAssistData();
- }
- }
+ private void logAssistContentAndData(AssistContent content, Bundle data) {
if (content != null) {
Log.i(TAG, "Assist intent: " + content.getIntent());
+ Log.i(TAG, "Assist intent from app: " + content.isAppProvidedIntent());
Log.i(TAG, "Assist clipdata: " + content.getClipData());
+ Log.i(TAG, "Assist structured data: " + content.getStructuredData());
+ Log.i(TAG, "Assist web uri: " + content.getWebUri());
+ Log.i(TAG, "Assist web uri from app: " + content.isAppProvidedWebUri());
+ Log.i(TAG, "Assist extras: " + content.getExtras());
}
if (data != null) {
Uri referrer = data.getParcelable(Intent.EXTRA_REFERRER);
@@ -192,6 +190,21 @@
}
@Override
+ public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
+ mAssistData = data;
+ mAssistStructure = structure;
+ mAssistContent = content;
+ if (mAssistVisualizer != null) {
+ if (mAssistStructure != null) {
+ mAssistVisualizer.setAssistStructure(mAssistStructure);
+ } else {
+ mAssistVisualizer.clearAssistData();
+ }
+ }
+ logAssistContentAndData(content, data);
+ }
+
+ @Override
public void onHandleAssistSecondary(final Bundle data, final AssistStructure structure,
final AssistContent content, int index, int count) {
Log.i(TAG, "Got secondary activity assist data " + index + " of " + count);
@@ -246,6 +259,7 @@
public void onClick(View v) {
if (v == mTreeButton) {
if (mAssistVisualizer != null) {
+ logAssistContentAndData(mAssistContent, mAssistData);
mAssistVisualizer.logTree();
}
} else if (v == mTextButton) {
diff --git a/tests/WallpaperTest/Android.mk b/tests/WallpaperTest/Android.mk
index b4259cd..4815500 100644
--- a/tests/WallpaperTest/Android.mk
+++ b/tests/WallpaperTest/Android.mk
@@ -8,6 +8,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := WallpaperTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/WindowManagerStressTest/Android.mk b/tests/WindowManagerStressTest/Android.mk
index e4cbe93..6f4403f 100644
--- a/tests/WindowManagerStressTest/Android.mk
+++ b/tests/WindowManagerStressTest/Android.mk
@@ -20,6 +20,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := WindowManagerStressTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/appwidgets/AppWidgetHostTest/Android.mk b/tests/appwidgets/AppWidgetHostTest/Android.mk
index 4d0c704..c9e6c6b 100644
--- a/tests/appwidgets/AppWidgetHostTest/Android.mk
+++ b/tests/appwidgets/AppWidgetHostTest/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := AppWidgetHostTest
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.mk b/tests/appwidgets/AppWidgetProviderTest/Android.mk
index 6084fb9..b26c60b 100644
--- a/tests/appwidgets/AppWidgetProviderTest/Android.mk
+++ b/tests/appwidgets/AppWidgetProviderTest/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := AppWidgetProvider
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index 202a699..e9618300 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -40,6 +40,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := BackupTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/java/android/net/IpPrefixTest.java
index b5b2c07..1f1ba2e 100644
--- a/tests/net/java/android/net/IpPrefixTest.java
+++ b/tests/net/java/android/net/IpPrefixTest.java
@@ -223,14 +223,14 @@
}
@Test
- public void testContains() {
+ public void testContainsInetAddress() {
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
assertFalse(p.contains(Address("2001:4868:4860::8888")));
- assertFalse(p.contains(null));
+ assertFalse(p.contains((InetAddress)null));
assertFalse(p.contains(Address("8.8.8.8")));
p = new IpPrefix("192.0.2.0/23");
@@ -251,6 +251,53 @@
}
@Test
+ public void testContainsIpPrefix() {
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23")));
+
+ assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8")));
+ assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8")));
+ assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21")));
+ assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32")));
+
+ assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24")));
+
+ assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32")));
+ assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8")));
+ assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15")));
+ assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8")));
+
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128")));
+
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/64")));
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/120")));
+ assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/32")));
+ assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2006:db8:f00::ace:d00d/96")));
+
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/128")));
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:ccaf/110")));
+
+ assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00e/128")));
+ assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29")));
+ }
+
+ @Test
public void testHashCode() {
IpPrefix p = new IpPrefix(new byte[4], 0);
Random random = new Random();
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 2e1519b..ec6a5ec 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -22,6 +22,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -213,7 +214,9 @@
assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
NetworkCapabilities netCap2 = new NetworkCapabilities();
- assertFalse(netCap2.satisfiedByUids(netCap));
+ // A new netcap object has null UIDs, so anything will satisfy it.
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ // Still not equal though.
assertFalse(netCap2.equalsUids(netCap));
netCap2.setUids(uids);
assertTrue(netCap2.satisfiedByUids(netCap));
@@ -230,7 +233,7 @@
assertTrue(netCap.appliesToUid(650));
assertFalse(netCap.appliesToUid(500));
- assertFalse(new NetworkCapabilities().satisfiedByUids(netCap));
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
netCap.combineCapabilities(new NetworkCapabilities());
assertTrue(netCap.appliesToUid(500));
assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
@@ -252,6 +255,19 @@
assertEqualsThroughMarshalling(netCap);
}
+ @Test
+ public void testOemPaid() {
+ NetworkCapabilities nc = new NetworkCapabilities();
+ nc.maybeMarkCapabilitiesRestricted();
+ assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
+ assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ nc.addCapability(NET_CAPABILITY_OEM_PAID);
+ nc.maybeMarkCapabilitiesRestricted();
+ assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
Parcel p = Parcel.obtain();
netCap.writeToParcel(p, /* flags */ 0);
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 8d51c3b..a5ee8e3 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -19,8 +19,10 @@
import android.net.NetworkUtils;
import android.test.suitebuilder.annotation.SmallTest;
+import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.TreeSet;
import junit.framework.TestCase;
@@ -67,4 +69,101 @@
assertInvalidNetworkMask(IPv4Address("255.255.255.253"));
assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
}
+
+ @SmallTest
+ public void testRoutedIPv4AddressCount() {
+ final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
+ // No routes routes to no addresses.
+ assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("0.0.0.0/0"));
+ assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("20.18.0.0/16"));
+ set.add(new IpPrefix("20.18.0.0/24"));
+ set.add(new IpPrefix("20.18.0.0/8"));
+ // There is a default route, still covers everything
+ assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("20.18.0.0/24"));
+ set.add(new IpPrefix("20.18.0.0/8"));
+ // The 8-length includes the 24-length prefix
+ assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("10.10.10.126/25"));
+ // The 8-length does not include this 25-length prefix
+ assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("1.2.3.4/32"));
+ set.add(new IpPrefix("1.2.3.4/32"));
+ set.add(new IpPrefix("1.2.3.4/32"));
+ set.add(new IpPrefix("1.2.3.4/32"));
+ assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("1.2.3.5/32"));
+ set.add(new IpPrefix("1.2.3.6/32"));
+
+ set.add(new IpPrefix("1.2.3.7/32"));
+ set.add(new IpPrefix("1.2.3.8/32"));
+ set.add(new IpPrefix("1.2.3.9/32"));
+ set.add(new IpPrefix("1.2.3.0/32"));
+ assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));
+
+ // 1.2.3.4/30 eats 1.2.3.{4-7}/32
+ set.add(new IpPrefix("1.2.3.4/30"));
+ set.add(new IpPrefix("6.2.3.4/28"));
+ set.add(new IpPrefix("120.2.3.4/16"));
+ assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
+ }
+
+ @SmallTest
+ public void testRoutedIPv6AddressCount() {
+ final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
+ // No routes routes to no addresses.
+ assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("::/0"));
+ assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("1234:622a::18/64"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
+ // There is a default route, still covers everything
+ assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
+ // The 8-length includes the 96-length prefix
+ assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("10::26/64"));
+ // The 8-length does not include this 64-length prefix
+ assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
+ NetworkUtils.routedIPv6AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
+ assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));
+
+ // add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
+ set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
+ set.add(new IpPrefix("f00b:a33::/112"));
+ assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
+ NetworkUtils.routedIPv6AddressCount(set));
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2aea1d7..207e24a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -387,6 +387,7 @@
mScore = 20;
break;
case TRANSPORT_VPN:
+ mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
break;
default:
@@ -3748,14 +3749,19 @@
final int uid = Process.myUid();
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder().build();
+ final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN).build();
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI).build();
final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
.addTransportType(TRANSPORT_VPN).build();
mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
@@ -3763,6 +3769,7 @@
mWiFiNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
@@ -3777,16 +3784,19 @@
vpnNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
ranges.clear();
vpnNetworkAgent.setUids(ranges);
genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
@@ -3794,18 +3804,21 @@
vpnNetworkAgent.setUids(ranges);
genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 66e0955..3e1ff6d 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -281,6 +281,7 @@
anyInt());
}
+ @Test
public void testCreateTwoTransformsWithSameSpis() throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 1dbf9b2..f59850d 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -57,9 +57,13 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.net.IpPrefix;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
+import android.net.RouteInfo;
import android.net.UidRange;
import android.net.VpnService;
import android.os.Build.VERSION_CODES;
@@ -90,7 +94,8 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Tests for {@link Vpn}.
@@ -563,4 +568,75 @@
return networks.get(network);
}).when(mConnectivityManager).getNetworkCapabilities(any());
}
+
+ // Need multiple copies of this, but Java's Stream objects can't be reused or
+ // duplicated.
+ private Stream<String> publicIpV4Routes() {
+ return Stream.of(
+ "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
+ "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
+ "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
+ "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
+ "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
+ "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
+ "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
+ }
+
+ private Stream<String> publicIpV6Routes() {
+ return Stream.of(
+ "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
+ "fe00::/8", "2605:ef80:e:af1d::/64");
+ }
+
+ @Test
+ public void testProvidesRoutesToMostDestinations() {
+ final LinkProperties lp = new LinkProperties();
+
+ // Default route provides routes to all IPv4 destinations.
+ lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // Empty LP provides routes to no destination
+ lp.clear();
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ // All IPv4 routes except for local networks. This is the case most relevant
+ // to this function. It provides routes to almost the entire space.
+ // (clone the stream so that we can reuse it later)
+ publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
+ // provide routes to "most" destinations.
+ lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // Remove the /2 route, which represent a quarter of the available routing space.
+ // This LP does not provides routes to "most" destinations any more.
+ lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ lp.clear();
+ publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V6 does not provide sufficient coverage but v4 does
+ publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V4 still does
+ lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V4 does not any more
+ lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V4 does not, but V6 has sufficient coverage again
+ lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+ }
}
diff --git a/tests/permission/Android.mk b/tests/permission/Android.mk
index 7f81d9a3..dd2f3ec 100644
--- a/tests/permission/Android.mk
+++ b/tests/permission/Android.mk
@@ -10,6 +10,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := junit
LOCAL_PACKAGE_NAME := FrameworkPermissionTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk
index 3c80ad8..9795188 100644
--- a/tests/privapp-permissions/Android.mk
+++ b/tests/privapp-permissions/Android.mk
@@ -2,6 +2,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := PrivAppPermissionTest
+LOCAL_SDK_VERSION := current
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
LOCAL_REQUIRED_MODULES := privapp-permissions-test.xml
@@ -16,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := VendorPrivAppPermissionTest
+LOCAL_SDK_VERSION := current
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
LOCAL_VENDOR_MODULE := true
@@ -31,6 +33,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := ProductPrivAppPermissionTest
+LOCAL_SDK_VERSION := current
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MANIFEST_FILE := product/AndroidManifest.xml
LOCAL_PRODUCT_MODULE := true
diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk
index f9b3ce4..3b0221c 100644
--- a/tests/testables/tests/Android.mk
+++ b/tests/testables/tests/Android.mk
@@ -19,6 +19,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := TestablesTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src)
diff --git a/tests/utils/DummyIME/Android.mk b/tests/utils/DummyIME/Android.mk
index c8d9f87..0f6c988 100644
--- a/tests/utils/DummyIME/Android.mk
+++ b/tests/utils/DummyIME/Android.mk
@@ -22,5 +22,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := DummyIME
+LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 7cffeea..1b6f882 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -26,11 +26,14 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "text/Utf8Iterator.h"
#include "util/ImmutableMap.h"
#include "util/Maybe.h"
#include "util/Util.h"
#include "xml/XmlPullParser.h"
+using ::aapt::ResourceUtils::StringBuilder;
+using ::aapt::text::Utf8Iterator;
using ::android::StringPiece;
namespace aapt {
@@ -169,114 +172,212 @@
config_(config),
options_(options) {}
-/**
- * Build a string from XML that converts nested elements into Span objects.
- */
+// Base class Node for representing the various Spans and UntranslatableSections of an XML string.
+// This will be used to traverse and flatten the XML string into a single std::string, with all
+// Span and Untranslatable data maintained in parallel, as indices into the string.
+class Node {
+ public:
+ virtual ~Node() = default;
+
+ // Adds the given child node to this parent node's set of child nodes, moving ownership to the
+ // parent node as well.
+ // Returns a pointer to the child node that was added as a convenience.
+ template <typename T>
+ T* AddChild(std::unique_ptr<T> node) {
+ T* raw_ptr = node.get();
+ children.push_back(std::move(node));
+ return raw_ptr;
+ }
+
+ virtual void Build(StringBuilder* builder) const {
+ for (const auto& child : children) {
+ child->Build(builder);
+ }
+ }
+
+ std::vector<std::unique_ptr<Node>> children;
+};
+
+// A chunk of text in the XML string. This lives between other tags, such as XLIFF tags and Spans.
+class SegmentNode : public Node {
+ public:
+ std::string data;
+
+ void Build(StringBuilder* builder) const override {
+ builder->AppendText(data);
+ }
+};
+
+// A tag that will be encoded into the final flattened string. Tags like <b> or <i>.
+class SpanNode : public Node {
+ public:
+ std::string name;
+
+ void Build(StringBuilder* builder) const override {
+ StringBuilder::SpanHandle span_handle = builder->StartSpan(name);
+ Node::Build(builder);
+ builder->EndSpan(span_handle);
+ }
+};
+
+// An XLIFF 'g' tag, which marks a section of the string as untranslatable.
+class UntranslatableNode : public Node {
+ public:
+ void Build(StringBuilder* builder) const override {
+ StringBuilder::UntranslatableHandle handle = builder->StartUntranslatable();
+ Node::Build(builder);
+ builder->EndUntranslatable(handle);
+ }
+};
+
+// Build a string from XML that converts nested elements into Span objects.
bool ResourceParser::FlattenXmlSubtree(
xml::XmlPullParser* parser, std::string* out_raw_string, StyleString* out_style_string,
std::vector<UntranslatableSection>* out_untranslatable_sections) {
- // Keeps track of formatting tags (<b>, <i>) and the range of characters for which they apply.
- // The stack elements refer to the indices in out_style_string->spans.
- // By first adding to the out_style_string->spans vector, and then using the stack to refer
- // to this vector, the original order of tags is preserved in cases such as <b><i>hello</b></i>.
- std::vector<size_t> span_stack;
-
- // Clear the output variables.
- out_raw_string->clear();
- out_style_string->spans.clear();
- out_untranslatable_sections->clear();
-
- // The StringBuilder will concatenate the various segments of text which are initially
- // separated by tags. It also handles unicode escape codes and quotations.
- util::StringBuilder builder;
+ std::string raw_string;
+ std::string current_text;
// The first occurrence of a <xliff:g> tag. Nested <xliff:g> tags are illegal.
Maybe<size_t> untranslatable_start_depth;
+ Node root;
+ std::vector<Node*> node_stack;
+ node_stack.push_back(&root);
+
+ bool saw_span_node = false;
+ SegmentNode* first_segment = nullptr;
+ SegmentNode* last_segment = nullptr;
+
size_t depth = 1;
- while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
+ while (depth > 0 && xml::XmlPullParser::IsGoodEvent(parser->Next())) {
const xml::XmlPullParser::Event event = parser->event();
- if (event == xml::XmlPullParser::Event::kStartElement) {
- if (parser->element_namespace().empty()) {
- // This is an HTML tag which we encode as a span. Add it to the span stack.
- std::string span_name = parser->element_name();
- const auto end_attr_iter = parser->end_attributes();
- for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter; ++attr_iter) {
- span_name += ";";
- span_name += attr_iter->name;
- span_name += "=";
- span_name += attr_iter->value;
+ // First take care of any SegmentNodes that should be created.
+ if (event == xml::XmlPullParser::Event::kStartElement ||
+ event == xml::XmlPullParser::Event::kEndElement) {
+ if (!current_text.empty()) {
+ std::unique_ptr<SegmentNode> segment_node = util::make_unique<SegmentNode>();
+ segment_node->data = std::move(current_text);
+ last_segment = node_stack.back()->AddChild(std::move(segment_node));
+ if (first_segment == nullptr) {
+ first_segment = last_segment;
}
+ current_text = {};
+ }
+ }
- // Make sure the string is representable in our binary format.
- if (builder.Utf16Len() > std::numeric_limits<uint32_t>::max()) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "style string '" << builder.ToString() << "' is too long");
- return false;
- }
+ switch (event) {
+ case xml::XmlPullParser::Event::kText: {
+ current_text += parser->text();
+ raw_string += parser->text();
+ } break;
- out_style_string->spans.push_back(
- Span{std::move(span_name), static_cast<uint32_t>(builder.Utf16Len())});
- span_stack.push_back(out_style_string->spans.size() - 1);
- } else if (parser->element_namespace() == sXliffNamespaceUri) {
- if (parser->element_name() == "g") {
- if (untranslatable_start_depth) {
- // We've already encountered an <xliff:g> tag, and nested <xliff:g> tags are illegal.
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "illegal nested XLIFF 'g' tag");
- return false;
- } else {
- // Mark the start of an untranslatable section. Use UTF8 indices/lengths.
- untranslatable_start_depth = depth;
- const size_t current_idx = builder.ToString().size();
- out_untranslatable_sections->push_back(UntranslatableSection{current_idx, current_idx});
+ case xml::XmlPullParser::Event::kStartElement: {
+ if (parser->element_namespace().empty()) {
+ // This is an HTML tag which we encode as a span. Add it to the span stack.
+ std::unique_ptr<SpanNode> span_node = util::make_unique<SpanNode>();
+ span_node->name = parser->element_name();
+ const auto end_attr_iter = parser->end_attributes();
+ for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter;
+ ++attr_iter) {
+ span_node->name += ";";
+ span_node->name += attr_iter->name;
+ span_node->name += "=";
+ span_node->name += attr_iter->value;
}
+
+ node_stack.push_back(node_stack.back()->AddChild(std::move(span_node)));
+ saw_span_node = true;
+ } else if (parser->element_namespace() == sXliffNamespaceUri) {
+ // This is an XLIFF tag, which is not encoded as a span.
+ if (parser->element_name() == "g") {
+ // Check that an 'untranslatable' tag is not already being processed. Nested
+ // <xliff:g> tags are illegal.
+ if (untranslatable_start_depth) {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ << "illegal nested XLIFF 'g' tag");
+ return false;
+ } else {
+ // Mark the beginning of an 'untranslatable' section.
+ untranslatable_start_depth = depth;
+ node_stack.push_back(
+ node_stack.back()->AddChild(util::make_unique<UntranslatableNode>()));
+ }
+ } else {
+ // Ignore unknown XLIFF tags, but don't warn.
+ node_stack.push_back(node_stack.back()->AddChild(util::make_unique<Node>()));
+ }
+ } else {
+ // Besides XLIFF, any other namespaced tag is unsupported and ignored.
+ diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
+ << "ignoring element '" << parser->element_name()
+ << "' with unknown namespace '" << parser->element_namespace() << "'");
+ node_stack.push_back(node_stack.back()->AddChild(util::make_unique<Node>()));
}
- // Ignore other xliff tags, they get handled by other tools.
- } else {
- // Besides XLIFF, any other namespaced tag is unsupported and ignored.
- diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
- << "ignoring element '" << parser->element_name()
- << "' with unknown namespace '" << parser->element_namespace() << "'");
- }
+ // Enter one level inside the element.
+ depth++;
+ } break;
- // Enter one level inside the element.
- depth++;
- } else if (event == xml::XmlPullParser::Event::kText) {
- // Record both the raw text and append to the builder to deal with escape sequences
- // and quotations.
- out_raw_string->append(parser->text());
- builder.Append(parser->text());
- } else if (event == xml::XmlPullParser::Event::kEndElement) {
- // Return one level from within the element.
- depth--;
- if (depth == 0) {
+ case xml::XmlPullParser::Event::kEndElement: {
+ // Return one level from within the element.
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+
+ node_stack.pop_back();
+ if (untranslatable_start_depth == make_value(depth)) {
+ // This is the end of an untranslatable section.
+ untranslatable_start_depth = {};
+ }
+ } break;
+
+ default:
+ // ignore.
break;
- }
-
- if (parser->element_namespace().empty()) {
- // This is an HTML tag which we encode as a span. Update the span
- // stack and pop the top entry.
- Span& top_span = out_style_string->spans[span_stack.back()];
- top_span.last_char = builder.Utf16Len() - 1;
- span_stack.pop_back();
- } else if (untranslatable_start_depth == make_value(depth)) {
- // This is the end of an untranslatable section. Use UTF8 indices/lengths.
- UntranslatableSection& untranslatable_section = out_untranslatable_sections->back();
- untranslatable_section.end = builder.ToString().size();
- untranslatable_start_depth = {};
- }
- } else if (event == xml::XmlPullParser::Event::kComment) {
- // Ignore.
- } else {
- LOG(FATAL) << "unhandled XML event";
}
}
- CHECK(span_stack.empty()) << "spans haven't been fully processed";
- out_style_string->str = builder.ToString();
+ // Sanity check to make sure we processed all the nodes.
+ CHECK(node_stack.size() == 1u);
+ CHECK(node_stack.back() == &root);
+
+ if (!saw_span_node) {
+ // If there were no spans, we must treat this string a little differently (according to AAPT).
+ // Find and strip the leading whitespace from the first segment, and the trailing whitespace
+ // from the last segment.
+ if (first_segment != nullptr) {
+ // Trim leading whitespace.
+ StringPiece trimmed = util::TrimLeadingWhitespace(first_segment->data);
+ if (trimmed.size() != first_segment->data.size()) {
+ first_segment->data = trimmed.to_string();
+ }
+ }
+
+ if (last_segment != nullptr) {
+ // Trim trailing whitespace.
+ StringPiece trimmed = util::TrimTrailingWhitespace(last_segment->data);
+ if (trimmed.size() != last_segment->data.size()) {
+ last_segment->data = trimmed.to_string();
+ }
+ }
+ }
+
+ // Have the XML structure flatten itself into the StringBuilder. The StringBuilder will take
+ // care of recording the correctly adjusted Spans and UntranslatableSections.
+ StringBuilder builder;
+ root.Build(&builder);
+ if (!builder) {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) << builder.GetError());
+ return false;
+ }
+
+ ResourceUtils::FlattenedXmlString flattened_string = builder.GetFlattenedString();
+ *out_raw_string = std::move(raw_string);
+ *out_untranslatable_sections = std::move(flattened_string.untranslatable_sections);
+ out_style_string->str = std::move(flattened_string.text);
+ out_style_string->spans = std::move(flattened_string.spans);
return true;
}
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 618c8ed..c98c0b9 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -95,6 +95,16 @@
ASSERT_THAT(str, NotNull());
EXPECT_THAT(*str, StrValueEq(" hey there "));
EXPECT_THAT(str->untranslatable_sections, IsEmpty());
+
+ ASSERT_TRUE(TestParse(R"(<string name="bar">Isn\'t it cool?</string>)"));
+ str = test::GetValue<String>(&table_, "string/bar");
+ ASSERT_THAT(str, NotNull());
+ EXPECT_THAT(*str, StrValueEq("Isn't it cool?"));
+
+ ASSERT_TRUE(TestParse(R"(<string name="baz">"Isn't it cool?"</string>)"));
+ str = test::GetValue<String>(&table_, "string/baz");
+ ASSERT_THAT(str, NotNull());
+ EXPECT_THAT(*str, StrValueEq("Isn't it cool?"));
}
TEST_F(ResourceParserTest, ParseEscapedString) {
@@ -126,16 +136,16 @@
StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
ASSERT_THAT(str, NotNull());
- EXPECT_THAT(str->value->value, Eq("This is my aunt\u2019s fickle string"));
+ EXPECT_THAT(str->value->value, StrEq("This is my aunt\u2019s fickle string"));
EXPECT_THAT(str->value->spans, SizeIs(2));
EXPECT_THAT(str->untranslatable_sections, IsEmpty());
- EXPECT_THAT(*str->value->spans[0].name, Eq("b"));
- EXPECT_THAT(str->value->spans[0].first_char, Eq(17u));
+ EXPECT_THAT(*str->value->spans[0].name, StrEq("b"));
+ EXPECT_THAT(str->value->spans[0].first_char, Eq(18u));
EXPECT_THAT(str->value->spans[0].last_char, Eq(30u));
- EXPECT_THAT(*str->value->spans[1].name, Eq("small"));
- EXPECT_THAT(str->value->spans[1].first_char, Eq(24u));
+ EXPECT_THAT(*str->value->spans[1].name, StrEq("small"));
+ EXPECT_THAT(str->value->spans[1].first_char, Eq(25u));
EXPECT_THAT(str->value->spans[1].last_char, Eq(30u));
}
@@ -144,7 +154,7 @@
String* str = test::GetValue<String>(&table_, "string/foo");
ASSERT_THAT(str, NotNull());
- EXPECT_THAT(*str->value, Eq("This is what I think"));
+ EXPECT_THAT(*str->value, StrEq("This is what I think"));
EXPECT_THAT(str->untranslatable_sections, IsEmpty());
ASSERT_TRUE(TestParse(R"(<string name="foo2">" This is what I think "</string>)"));
@@ -154,6 +164,25 @@
EXPECT_THAT(*str, StrValueEq(" This is what I think "));
}
+TEST_F(ResourceParserTest, ParseStyledStringWithWhitespace) {
+ std::string input = R"(<string name="foo"> <b> My <i> favorite</i> string </b> </string>)";
+ ASSERT_TRUE(TestParse(input));
+
+ StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
+ ASSERT_THAT(str, NotNull());
+ EXPECT_THAT(str->value->value, StrEq(" My favorite string "));
+ EXPECT_THAT(str->untranslatable_sections, IsEmpty());
+
+ ASSERT_THAT(str->value->spans, SizeIs(2u));
+ EXPECT_THAT(*str->value->spans[0].name, StrEq("b"));
+ EXPECT_THAT(str->value->spans[0].first_char, Eq(1u));
+ EXPECT_THAT(str->value->spans[0].last_char, Eq(21u));
+
+ EXPECT_THAT(*str->value->spans[1].name, StrEq("i"));
+ EXPECT_THAT(str->value->spans[1].first_char, Eq(5u));
+ EXPECT_THAT(str->value->spans[1].last_char, Eq(13u));
+}
+
TEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
std::string input = R"(
<string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
@@ -182,12 +211,9 @@
String* str = test::GetValue<String>(&table_, "string/foo");
ASSERT_THAT(str, NotNull());
EXPECT_THAT(*str, StrValueEq("There are %1$d apples"));
- ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
- // We expect indices and lengths that span to include the whitespace
- // before %1$d. This is due to how the StringBuilder withholds whitespace unless
- // needed (to deal with line breaks, etc.).
- EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
+ ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
+ EXPECT_THAT(str->untranslatable_sections[0].start, Eq(10u));
EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
}
@@ -199,14 +225,16 @@
StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
ASSERT_THAT(str, NotNull());
- EXPECT_THAT(str->value->value, Eq("There are %1$d apples"));
- ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
+ EXPECT_THAT(str->value->value, Eq(" There are %1$d apples"));
- // We expect indices and lengths that span to include the whitespace
- // before %1$d. This is due to how the StringBuilder withholds whitespace unless
- // needed (to deal with line breaks, etc.).
- EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
- EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
+ ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
+ EXPECT_THAT(str->untranslatable_sections[0].start, Eq(11u));
+ EXPECT_THAT(str->untranslatable_sections[0].end, Eq(15u));
+
+ ASSERT_THAT(str->value->spans, SizeIs(1u));
+ EXPECT_THAT(*str->value->spans[0].name, StrEq("b"));
+ EXPECT_THAT(str->value->spans[0].first_char, Eq(11u));
+ EXPECT_THAT(str->value->spans[0].last_char, Eq(14u));
}
TEST_F(ResourceParserTest, ParseNull) {
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 628466d..8fc3d65 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -18,17 +18,23 @@
#include <sstream>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/ResourceUtils.h"
#include "NameMangler.h"
#include "SdkConstants.h"
#include "format/binary/ResourceTypeExtensions.h"
+#include "text/Unicode.h"
+#include "text/Utf8Iterator.h"
#include "util/Files.h"
#include "util/Util.h"
+using ::aapt::text::IsWhitespace;
+using ::aapt::text::Utf8Iterator;
using ::android::StringPiece;
using ::android::StringPiece16;
+using ::android::base::StringPrintf;
namespace aapt {
namespace ResourceUtils {
@@ -750,5 +756,195 @@
return util::make_unique<BinaryPrimitive>(res_value);
}
+// Converts the codepoint to UTF-8 and appends it to the string.
+static bool AppendCodepointToUtf8String(char32_t codepoint, std::string* output) {
+ ssize_t len = utf32_to_utf8_length(&codepoint, 1);
+ if (len < 0) {
+ return false;
+ }
+
+ const size_t start_append_pos = output->size();
+
+ // Make room for the next character.
+ output->resize(output->size() + len);
+
+ char* dst = &*(output->begin() + start_append_pos);
+ utf32_to_utf8(&codepoint, 1, dst, len + 1);
+ return true;
+}
+
+// Reads up to 4 UTF-8 characters that represent a Unicode escape sequence, and appends the
+// Unicode codepoint represented by the escape sequence to the string.
+static bool AppendUnicodeEscapeSequence(Utf8Iterator* iter, std::string* output) {
+ char32_t code = 0;
+ for (size_t i = 0; i < 4 && iter->HasNext(); i++) {
+ char32_t codepoint = iter->Next();
+ char32_t a;
+ if (codepoint >= U'0' && codepoint <= U'9') {
+ a = codepoint - U'0';
+ } else if (codepoint >= U'a' && codepoint <= U'f') {
+ a = codepoint - U'a' + 10;
+ } else if (codepoint >= U'A' && codepoint <= U'F') {
+ a = codepoint - U'A' + 10;
+ } else {
+ return {};
+ }
+ code = (code << 4) | a;
+ }
+ return AppendCodepointToUtf8String(code, output);
+}
+
+StringBuilder::StringBuilder(bool preserve_spaces)
+ : preserve_spaces_(preserve_spaces), quote_(preserve_spaces) {
+}
+
+StringBuilder& StringBuilder::AppendText(const std::string& text) {
+ if (!error_.empty()) {
+ return *this;
+ }
+
+ const size_t previous_len = xml_string_.text.size();
+ Utf8Iterator iter(text);
+ while (iter.HasNext()) {
+ char32_t codepoint = iter.Next();
+ if (!quote_ && text::IsWhitespace(codepoint)) {
+ if (!last_codepoint_was_space_) {
+ // Emit a space if it's the first.
+ xml_string_.text += ' ';
+ last_codepoint_was_space_ = true;
+ }
+
+ // Keep eating spaces.
+ continue;
+ }
+
+ // This is not a space.
+ last_codepoint_was_space_ = false;
+
+ if (codepoint == U'\\') {
+ if (iter.HasNext()) {
+ codepoint = iter.Next();
+ switch (codepoint) {
+ case U't':
+ xml_string_.text += '\t';
+ break;
+
+ case U'n':
+ xml_string_.text += '\n';
+ break;
+
+ case U'#':
+ case U'@':
+ case U'?':
+ case U'"':
+ case U'\'':
+ case U'\\':
+ xml_string_.text += static_cast<char>(codepoint);
+ break;
+
+ case U'u':
+ if (!AppendUnicodeEscapeSequence(&iter, &xml_string_.text)) {
+ error_ =
+ StringPrintf("invalid unicode escape sequence in string\n\"%s\"", text.c_str());
+ return *this;
+ }
+ break;
+
+ default:
+ // Ignore the escape character and just include the codepoint.
+ AppendCodepointToUtf8String(codepoint, &xml_string_.text);
+ break;
+ }
+ }
+ } else if (!preserve_spaces_ && codepoint == U'"') {
+ // Only toggle the quote state when we are not preserving spaces.
+ quote_ = !quote_;
+
+ } else if (!quote_ && codepoint == U'\'') {
+ // This should be escaped.
+ error_ = StringPrintf("unescaped apostrophe in string\n\"%s\"", text.c_str());
+ return *this;
+
+ } else {
+ AppendCodepointToUtf8String(codepoint, &xml_string_.text);
+ }
+ }
+
+ // Accumulate the added string's UTF-16 length.
+ const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(xml_string_.text.c_str());
+ const size_t utf8_length = xml_string_.text.size();
+ ssize_t len = utf8_to_utf16_length(utf8_data + previous_len, utf8_length - previous_len);
+ if (len < 0) {
+ error_ = StringPrintf("invalid unicode code point in string\n\"%s\"", utf8_data + previous_len);
+ return *this;
+ }
+
+ utf16_len_ += static_cast<uint32_t>(len);
+ return *this;
+}
+
+StringBuilder::SpanHandle StringBuilder::StartSpan(const std::string& name) {
+ if (!error_.empty()) {
+ return 0u;
+ }
+
+ // When we start a span, all state associated with whitespace truncation and quotation is ended.
+ ResetTextState();
+ Span span;
+ span.name = name;
+ span.first_char = span.last_char = utf16_len_;
+ xml_string_.spans.push_back(std::move(span));
+ return xml_string_.spans.size() - 1;
+}
+
+void StringBuilder::EndSpan(SpanHandle handle) {
+ if (!error_.empty()) {
+ return;
+ }
+
+ // When we end a span, all state associated with whitespace truncation and quotation is ended.
+ ResetTextState();
+ xml_string_.spans[handle].last_char = utf16_len_ - 1u;
+}
+
+StringBuilder::UntranslatableHandle StringBuilder::StartUntranslatable() {
+ if (!error_.empty()) {
+ return 0u;
+ }
+
+ UntranslatableSection section;
+ section.start = section.end = xml_string_.text.size();
+ xml_string_.untranslatable_sections.push_back(section);
+ return xml_string_.untranslatable_sections.size() - 1;
+}
+
+void StringBuilder::EndUntranslatable(UntranslatableHandle handle) {
+ if (!error_.empty()) {
+ return;
+ }
+ xml_string_.untranslatable_sections[handle].end = xml_string_.text.size();
+}
+
+FlattenedXmlString StringBuilder::GetFlattenedString() const {
+ return xml_string_;
+}
+
+std::string StringBuilder::to_string() const {
+ return xml_string_.text;
+}
+
+StringBuilder::operator bool() const {
+ return error_.empty();
+}
+
+std::string StringBuilder::GetError() const {
+ return error_;
+}
+
+void StringBuilder::ResetTextState() {
+ quote_ = preserve_spaces_;
+ last_codepoint_was_space_ = false;
+}
+
} // namespace ResourceUtils
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index f83d49e..7af2fe0 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -224,6 +224,95 @@
const android::Res_value& res_value,
StringPool* dst_pool);
+// A string flattened from an XML hierarchy, which maintains tags and untranslatable sections
+// in parallel data structures.
+struct FlattenedXmlString {
+ std::string text;
+ std::vector<UntranslatableSection> untranslatable_sections;
+ std::vector<Span> spans;
+};
+
+// Flattens an XML hierarchy into a FlattenedXmlString, formatting the text, escaping characters,
+// and removing whitespace, all while keeping the untranslatable sections and spans in sync with the
+// transformations.
+//
+// Specifically, the StringBuilder will handle escaped characters like \t, \n, \\, \', etc.
+// Single quotes *must* be escaped, unless within a pair of double-quotes.
+// Pairs of double-quotes disable whitespace stripping of the enclosed text.
+// Unicode escape codes (\u0049) are interpreted and the represented Unicode character is inserted.
+//
+// A NOTE ON WHITESPACE:
+//
+// When preserve_spaces is false, and when text is not enclosed within double-quotes,
+// StringBuilder replaces a series of whitespace with a single space character. This happens at the
+// start and end of the string as well, so leading and trailing whitespace is possible.
+//
+// When a Span is started or stopped, the whitespace counter is reset, meaning if whitespace
+// is encountered directly after the span, it will be emitted. This leads to situations like the
+// following: "This <b> is </b> spaced" -> "This is spaced". Without spans, this would be properly
+// compressed: "This is spaced" -> "This is spaced".
+//
+// Untranslatable sections do not have the same problem:
+// "This <xliff:g> is </xliff:g> not spaced" -> "This is not spaced".
+//
+// NOTE: This is all the way it is because AAPT1 did it this way. Maintaining backwards
+// compatibility is important.
+//
+class StringBuilder {
+ public:
+ using SpanHandle = size_t;
+ using UntranslatableHandle = size_t;
+
+ // Creates a StringBuilder. If preserve_spaces is true, whitespace removal is not performed, and
+ // single quotations can be used without escaping them.
+ explicit StringBuilder(bool preserve_spaces = false);
+
+ // Appends a chunk of text.
+ StringBuilder& AppendText(const std::string& text);
+
+ // Starts a Span (tag) with the given name. The name is expected to be of the form:
+ // "tag_name;attr1=value;attr2=value;"
+ // Which is how Spans are encoded in the ResStringPool.
+ // To end the span, pass back the SpanHandle received from this method to the EndSpan() method.
+ SpanHandle StartSpan(const std::string& name);
+
+ // Ends a Span (tag). Pass in the matching SpanHandle previously obtained from StartSpan().
+ void EndSpan(SpanHandle handle);
+
+ // Starts an Untranslatable section.
+ // To end the section, pass back the UntranslatableHandle received from this method to
+ // the EndUntranslatable() method.
+ UntranslatableHandle StartUntranslatable();
+
+ // Ends an Untranslatable section. Pass in the matching UntranslatableHandle previously obtained
+ // from StartUntranslatable().
+ void EndUntranslatable(UntranslatableHandle handle);
+
+ // Returns the flattened XML string, with all spans and untranslatable sections encoded as
+ // parallel data structures.
+ FlattenedXmlString GetFlattenedString() const;
+
+ // Returns just the flattened XML text, with no spans or untranslatable sections.
+ std::string to_string() const;
+
+ // Returns true if there was no error.
+ explicit operator bool() const;
+
+ std::string GetError() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StringBuilder);
+
+ void ResetTextState();
+
+ std::string error_;
+ FlattenedXmlString xml_string_;
+ uint32_t utf16_len_ = 0u;
+ bool preserve_spaces_;
+ bool quote_;
+ bool last_codepoint_was_space_ = false;
+};
+
} // namespace ResourceUtils
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index cb786d3..11f3fa3 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -212,4 +212,48 @@
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
}
+TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) {
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText(" hey guys ")
+ .AppendText(" this is so cool ")
+ .to_string(),
+ Eq(" hey guys this is so cool "));
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText(" \" wow, so many \t ")
+ .AppendText("spaces. \"what? ")
+ .to_string(),
+ Eq(" wow, so many \t spaces. what? "));
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText(" where \t ")
+ .AppendText(" \nis the pie?")
+ .to_string(),
+ Eq(" where is the pie?"));
+}
+
+TEST(ResourceUtilsTest, StringBuilderEscaping) {
+ EXPECT_THAT(ResourceUtils::StringBuilder()
+ .AppendText("hey guys\\n ")
+ .AppendText(" this \\t is so\\\\ cool")
+ .to_string(),
+ Eq("hey guys\n this \t is so\\ cool"));
+ EXPECT_THAT(ResourceUtils::StringBuilder().AppendText("\\@\\?\\#\\\\\\'").to_string(),
+ Eq("@?#\\\'"));
+}
+
+TEST(ResourceUtilsTest, StringBuilderMisplacedQuote) {
+ ResourceUtils::StringBuilder builder;
+ EXPECT_FALSE(builder.AppendText("they're coming!"));
+}
+
+TEST(ResourceUtilsTest, StringBuilderUnicodeCodes) {
+ EXPECT_THAT(ResourceUtils::StringBuilder().AppendText("\\u00AF\\u0AF0 woah").to_string(),
+ Eq("\u00AF\u0AF0 woah"));
+ EXPECT_FALSE(ResourceUtils::StringBuilder().AppendText("\\u00 yo"));
+}
+
+TEST(ResourceUtilsTest, StringBuilderPreserveSpaces) {
+ EXPECT_THAT(ResourceUtils::StringBuilder(true /*preserve_spaces*/).AppendText("\"").to_string(),
+ Eq("\""));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index 345cc95..781b9fe 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -25,13 +25,17 @@
#include "androidfw/ResourceTypes.h"
#include "utils/misc.h"
+#include "ResourceUtils.h"
#include "SdkConstants.h"
+#include "ValueVisitor.h"
#include "format/binary/ChunkWriter.h"
#include "format/binary/ResourceTypeExtensions.h"
#include "xml/XmlDom.h"
using namespace android;
+using ::aapt::ResourceUtils::StringBuilder;
+
namespace aapt {
namespace {
@@ -88,9 +92,9 @@
ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>();
// Process plain strings to make sure they get properly escaped.
- util::StringBuilder builder;
- builder.Append(node->text);
- AddString(builder.ToString(), kLowPriority, &flat_text->data);
+ StringBuilder builder;
+ builder.AppendText(node->text);
+ AddString(builder.to_string(), kLowPriority, &flat_text->data);
writer.Finish();
}
@@ -153,6 +157,9 @@
private:
DISALLOW_COPY_AND_ASSIGN(XmlFlattenerVisitor);
+ // We are adding strings to a StringPool whose strings will be sorted and merged with other
+ // string pools. That means we can't encode the ID of a string directly. Instead, we defer the
+ // writing of the ID here, until after the StringPool is merged and sorted.
void AddString(const StringPiece& str, uint32_t priority, android::ResStringPool_ref* dest,
bool treat_empty_string_as_null = false) {
if (str.empty() && treat_empty_string_as_null) {
@@ -164,6 +171,9 @@
}
}
+ // We are adding strings to a StringPool whose strings will be sorted and merged with other
+ // string pools. That means we can't encode the ID of a string directly. Instead, we defer the
+ // writing of the ID here, until after the StringPool is merged and sorted.
void AddString(const StringPool::Ref& ref, android::ResStringPool_ref* dest) {
string_refs.push_back(StringFlattenDest{ref, dest});
}
@@ -248,30 +258,39 @@
AddString(name_ref, &flat_attr->name);
}
- // Process plain strings to make sure they get properly escaped.
- StringPiece raw_value = xml_attr->value;
-
- util::StringBuilder str_builder(true /*preserve_spaces*/);
- str_builder.Append(xml_attr->value);
-
- if (!options_.keep_raw_values) {
- raw_value = str_builder.ToString();
- }
-
- if (options_.keep_raw_values || !xml_attr->compiled_value) {
- // Keep raw values if the value is not compiled or
- // if we're building a static library (need symbols).
- AddString(raw_value, kLowPriority, &flat_attr->rawValue);
- }
-
- if (xml_attr->compiled_value) {
- CHECK(xml_attr->compiled_value->Flatten(&flat_attr->typedValue));
+ std::string processed_str;
+ Maybe<StringPiece> compiled_text;
+ if (xml_attr->compiled_value != nullptr) {
+ // Make sure we're not flattening a String. A String can be referencing a string from
+ // a different StringPool than we're using here to build the binary XML.
+ String* string_value = ValueCast<String>(xml_attr->compiled_value.get());
+ if (string_value != nullptr) {
+ // Mark the String's text as needing to be serialized.
+ compiled_text = StringPiece(*string_value->value);
+ } else {
+ // Serialize this compiled value safely.
+ CHECK(xml_attr->compiled_value->Flatten(&flat_attr->typedValue));
+ }
} else {
- // Flatten as a regular string type.
- flat_attr->typedValue.dataType = android::Res_value::TYPE_STRING;
+ // There is no compiled value, so treat the raw string as compiled, once it is processed to
+ // make sure escape sequences are properly interpreted.
+ processed_str =
+ StringBuilder(true /*preserve_spaces*/).AppendText(xml_attr->value).to_string();
+ compiled_text = StringPiece(processed_str);
+ }
- AddString(str_builder.ToString(), kLowPriority,
- (ResStringPool_ref*)&flat_attr->typedValue.data);
+ if (compiled_text) {
+ // Write out the compiled text and raw_text.
+ flat_attr->typedValue.dataType = android::Res_value::TYPE_STRING;
+ AddString(compiled_text.value(), kLowPriority,
+ reinterpret_cast<ResStringPool_ref*>(&flat_attr->typedValue.data));
+ if (options_.keep_raw_values) {
+ AddString(xml_attr->value, kLowPriority, &flat_attr->rawValue);
+ } else {
+ AddString(compiled_text.value(), kLowPriority, &flat_attr->rawValue);
+ }
+ } else if (options_.keep_raw_values && !xml_attr->value.empty()) {
+ AddString(xml_attr->value, kLowPriority, &flat_attr->rawValue);
}
flat_attr->typedValue.size = util::HostToDevice16(sizeof(flat_attr->typedValue));
diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp
index 0450f6c..08243fe 100644
--- a/tools/aapt2/format/binary/XmlFlattener_test.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp
@@ -286,4 +286,92 @@
EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}"));
}
+TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)");
+
+ // Raw values are kept when encoding an attribute with no compiled value, regardless of option.
+ XmlFlattenerOptions options;
+ options.keep_raw_values = false;
+
+ android::ResXMLTree tree;
+ ASSERT_TRUE(Flatten(doc.get(), &tree, options));
+
+ while (tree.next() != android::ResXMLTree::START_TAG) {
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
+ }
+
+ ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0));
+ EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING));
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0)));
+}
+
+TEST_F(XmlFlattenerTest, FlattenCompiledStringValuePreservesRawValue) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)");
+ doc->root->attributes[0].compiled_value =
+ util::make_unique<String>(doc->string_pool.MakeRef("bar"));
+
+ // Raw values are kept when encoding a string anyways.
+ XmlFlattenerOptions options;
+ options.keep_raw_values = false;
+
+ android::ResXMLTree tree;
+ ASSERT_TRUE(Flatten(doc.get(), &tree, options));
+
+ while (tree.next() != android::ResXMLTree::START_TAG) {
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
+ }
+
+ ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0));
+ EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING));
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0)));
+}
+
+TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionFalse) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="true" />)");
+ doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true);
+
+ XmlFlattenerOptions options;
+ options.keep_raw_values = false;
+
+ android::ResXMLTree tree;
+ ASSERT_TRUE(Flatten(doc.get(), &tree, options));
+
+ while (tree.next() != android::ResXMLTree::START_TAG) {
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
+ }
+
+ ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
+ EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN));
+}
+
+TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionTrue) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="true" />)");
+ doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true);
+
+ XmlFlattenerOptions options;
+ options.keep_raw_values = true;
+
+ android::ResXMLTree tree;
+ ASSERT_TRUE(Flatten(doc.get(), &tree, options));
+
+ while (tree.next() != android::ResXMLTree::START_TAG) {
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
+ ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
+ }
+
+ ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0));
+
+ size_t len;
+ EXPECT_THAT(tree.getAttributeStringValue(0, &len), StrEq(u"true"));
+
+ EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index b8f8804..9aaaa69 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -30,6 +30,7 @@
#include "util/Util.h"
#include "xml/XmlUtil.h"
+using ::aapt::ResourceUtils::StringBuilder;
using ::android::StringPiece;
namespace aapt {
@@ -133,10 +134,11 @@
// If we could not parse as any specific type, try a basic STRING.
if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) {
- util::StringBuilder string_builder;
- string_builder.Append(*raw_string->value);
+ StringBuilder string_builder;
+ string_builder.AppendText(*raw_string->value);
if (string_builder) {
- transformed = util::make_unique<String>(string_pool_->MakeRef(string_builder.ToString()));
+ transformed =
+ util::make_unique<String>(string_pool_->MakeRef(string_builder.to_string()));
}
}
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index e42145d..d1c9ca1 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -76,6 +76,34 @@
return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
}
+StringPiece TrimLeadingWhitespace(const StringPiece& str) {
+ if (str.size() == 0 || str.data() == nullptr) {
+ return str;
+ }
+
+ const char* start = str.data();
+ const char* end = start + str.length();
+
+ while (start != end && isspace(*start)) {
+ start++;
+ }
+ return StringPiece(start, end - start);
+}
+
+StringPiece TrimTrailingWhitespace(const StringPiece& str) {
+ if (str.size() == 0 || str.data() == nullptr) {
+ return str;
+ }
+
+ const char* start = str.data();
+ const char* end = start + str.length();
+
+ while (end != start && isspace(*(end - 1))) {
+ end--;
+ }
+ return StringPiece(start, end - start);
+}
+
StringPiece TrimWhitespace(const StringPiece& str) {
if (str.size() == 0 || str.data() == nullptr) {
return str;
@@ -269,162 +297,6 @@
return true;
}
-static bool AppendCodepointToUtf8String(char32_t codepoint, std::string* output) {
- ssize_t len = utf32_to_utf8_length(&codepoint, 1);
- if (len < 0) {
- return false;
- }
-
- const size_t start_append_pos = output->size();
-
- // Make room for the next character.
- output->resize(output->size() + len);
-
- char* dst = &*(output->begin() + start_append_pos);
- utf32_to_utf8(&codepoint, 1, dst, len + 1);
- return true;
-}
-
-static bool AppendUnicodeCodepoint(Utf8Iterator* iter, std::string* output) {
- char32_t code = 0;
- for (size_t i = 0; i < 4 && iter->HasNext(); i++) {
- char32_t codepoint = iter->Next();
- char32_t a;
- if (codepoint >= U'0' && codepoint <= U'9') {
- a = codepoint - U'0';
- } else if (codepoint >= U'a' && codepoint <= U'f') {
- a = codepoint - U'a' + 10;
- } else if (codepoint >= U'A' && codepoint <= U'F') {
- a = codepoint - U'A' + 10;
- } else {
- return {};
- }
- code = (code << 4) | a;
- }
- return AppendCodepointToUtf8String(code, output);
-}
-
-static bool IsCodepointSpace(char32_t codepoint) {
- if (static_cast<uint32_t>(codepoint) & 0xffffff00u) {
- return false;
- }
- return isspace(static_cast<char>(codepoint));
-}
-
-StringBuilder::StringBuilder(bool preserve_spaces) : preserve_spaces_(preserve_spaces) {
-}
-
-StringBuilder& StringBuilder::Append(const StringPiece& str) {
- if (!error_.empty()) {
- return *this;
- }
-
- // Where the new data will be appended to.
- const size_t new_data_index = str_.size();
-
- Utf8Iterator iter(str);
- while (iter.HasNext()) {
- const char32_t codepoint = iter.Next();
-
- if (last_char_was_escape_) {
- switch (codepoint) {
- case U't':
- str_ += '\t';
- break;
-
- case U'n':
- str_ += '\n';
- break;
-
- case U'#':
- case U'@':
- case U'?':
- case U'"':
- case U'\'':
- case U'\\':
- str_ += static_cast<char>(codepoint);
- break;
-
- case U'u':
- if (!AppendUnicodeCodepoint(&iter, &str_)) {
- error_ = "invalid unicode escape sequence";
- return *this;
- }
- break;
-
- default:
- // Ignore the escape character and just include the codepoint.
- AppendCodepointToUtf8String(codepoint, &str_);
- break;
- }
- last_char_was_escape_ = false;
-
- } else if (!preserve_spaces_ && codepoint == U'"') {
- if (!quote_ && trailing_space_) {
- // We found an opening quote, and we have trailing space, so we should append that
- // space now.
- if (trailing_space_) {
- // We had trailing whitespace, so replace with a single space.
- if (!str_.empty()) {
- str_ += ' ';
- }
- trailing_space_ = false;
- }
- }
- quote_ = !quote_;
-
- } else if (!preserve_spaces_ && codepoint == U'\'' && !quote_) {
- // This should be escaped.
- error_ = "unescaped apostrophe";
- return *this;
-
- } else if (codepoint == U'\\') {
- // This is an escape sequence, convert to the real value.
- if (!quote_ && trailing_space_) {
- // We had trailing whitespace, so
- // replace with a single space.
- if (!str_.empty()) {
- str_ += ' ';
- }
- trailing_space_ = false;
- }
- last_char_was_escape_ = true;
- } else {
- if (preserve_spaces_ || quote_) {
- // Quotes mean everything is taken, including whitespace.
- AppendCodepointToUtf8String(codepoint, &str_);
- } else {
- // This is not quoted text, so we will accumulate whitespace and only emit a single
- // character of whitespace if it is followed by a non-whitespace character.
- if (IsCodepointSpace(codepoint)) {
- // We found whitespace.
- trailing_space_ = true;
- } else {
- if (trailing_space_) {
- // We saw trailing space before, so replace all
- // that trailing space with one space.
- if (!str_.empty()) {
- str_ += ' ';
- }
- trailing_space_ = false;
- }
- AppendCodepointToUtf8String(codepoint, &str_);
- }
- }
- }
- }
-
- // Accumulate the added string's UTF-16 length.
- ssize_t len = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str_.data()) + new_data_index,
- str_.size() - new_data_index);
- if (len < 0) {
- error_ = "invalid unicode code point";
- return *this;
- }
- utf16_len_ += len;
- return *this;
-}
-
std::u16string Utf8ToUtf16(const StringPiece& utf8) {
ssize_t utf16_length = utf8_to_utf16_length(
reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 7c949b90..0eb35d1 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -59,7 +59,15 @@
// Returns true if the string ends with suffix.
bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
-// Creates a new StringPiece16 that points to a substring of the original string without leading or
+// Creates a new StringPiece that points to a substring of the original string without leading
+// whitespace.
+android::StringPiece TrimLeadingWhitespace(const android::StringPiece& str);
+
+// Creates a new StringPiece that points to a substring of the original string without trailing
+// whitespace.
+android::StringPiece TrimTrailingWhitespace(const android::StringPiece& str);
+
+// Creates a new StringPiece that points to a substring of the original string without leading or
// trailing whitespace.
android::StringPiece TrimWhitespace(const android::StringPiece& str);
@@ -141,9 +149,12 @@
// break the string interpolation.
bool VerifyJavaStringFormat(const android::StringPiece& str);
+bool AppendStyledString(const android::StringPiece& input, bool preserve_spaces,
+ std::string* out_str, std::string* out_error);
+
class StringBuilder {
public:
- explicit StringBuilder(bool preserve_spaces = false);
+ StringBuilder() = default;
StringBuilder& Append(const android::StringPiece& str);
const std::string& ToString() const;
@@ -158,7 +169,6 @@
explicit operator bool() const;
private:
- bool preserve_spaces_;
std::string str_;
size_t utf16_len_ = 0;
bool quote_ = false;
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index 2d1242a..d4e3bec 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -41,45 +41,6 @@
EXPECT_TRUE(util::StartsWith("hello.xml", "he"));
}
-TEST(UtilTest, StringBuilderSplitEscapeSequence) {
- EXPECT_THAT(util::StringBuilder().Append("this is a new\\").Append("nline.").ToString(),
- Eq("this is a new\nline."));
-}
-
-TEST(UtilTest, StringBuilderWhitespaceRemoval) {
- EXPECT_THAT(util::StringBuilder().Append(" hey guys ").Append(" this is so cool ").ToString(),
- Eq("hey guys this is so cool"));
- EXPECT_THAT(
- util::StringBuilder().Append(" \" wow, so many \t ").Append("spaces. \"what? ").ToString(),
- Eq(" wow, so many \t spaces. what?"));
- EXPECT_THAT(util::StringBuilder().Append(" where \t ").Append(" \nis the pie?").ToString(),
- Eq("where is the pie?"));
-}
-
-TEST(UtilTest, StringBuilderEscaping) {
- EXPECT_THAT(util::StringBuilder()
- .Append(" hey guys\\n ")
- .Append(" this \\t is so\\\\ cool ")
- .ToString(),
- Eq("hey guys\n this \t is so\\ cool"));
- EXPECT_THAT(util::StringBuilder().Append("\\@\\?\\#\\\\\\'").ToString(), Eq("@?#\\\'"));
-}
-
-TEST(UtilTest, StringBuilderMisplacedQuote) {
- util::StringBuilder builder;
- EXPECT_FALSE(builder.Append("they're coming!"));
-}
-
-TEST(UtilTest, StringBuilderUnicodeCodes) {
- EXPECT_THAT(util::StringBuilder().Append("\\u00AF\\u0AF0 woah").ToString(),
- Eq("\u00AF\u0AF0 woah"));
- EXPECT_FALSE(util::StringBuilder().Append("\\u00 yo"));
-}
-
-TEST(UtilTest, StringBuilderPreserveSpaces) {
- EXPECT_THAT(util::StringBuilder(true /*preserve_spaces*/).Append("\"").ToString(), Eq("\""));
-}
-
TEST(UtilTest, TokenizeInput) {
auto tokenizer = util::Tokenize(StringPiece("this| is|the|end"), '|');
auto iter = tokenizer.begin();
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 7b748ce..b6cd086 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -248,8 +248,14 @@
android::Res_value res_value;
if (parser->getAttributeValue(i, &res_value) > 0) {
- attr.compiled_value = ResourceUtils::ParseBinaryResValue(
- ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
+ // Only compile the value if it is not a string, or it is a string that differs from
+ // the raw attribute value.
+ int32_t raw_value_idx = parser->getAttributeValueStringID(i);
+ if (res_value.dataType != android::Res_value::TYPE_STRING || raw_value_idx < 0 ||
+ static_cast<uint32_t>(raw_value_idx) != res_value.data) {
+ attr.compiled_value = ResourceUtils::ParseBinaryResValue(
+ ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
+ }
}
el->attributes.push_back(std::move(attr));
@@ -262,8 +268,8 @@
// an enum, which causes errors when qualifying it with android::
using namespace android;
- StringPool string_pool;
- std::unique_ptr<Element> root;
+ std::unique_ptr<XmlResource> xml_resource = util::make_unique<XmlResource>();
+
std::stack<Element*> node_stack;
std::unique_ptr<Element> pending_element;
@@ -322,12 +328,12 @@
}
Element* this_el = el.get();
- CopyAttributes(el.get(), &tree, &string_pool);
+ CopyAttributes(el.get(), &tree, &xml_resource->string_pool);
if (!node_stack.empty()) {
node_stack.top()->AppendChild(std::move(el));
} else {
- root = std::move(el);
+ xml_resource->root = std::move(el);
}
node_stack.push(this_el);
break;
@@ -359,7 +365,7 @@
break;
}
}
- return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
+ return xml_resource;
}
std::unique_ptr<XmlResource> XmlResource::Clone() const {
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index e7b269a..9183918 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -411,6 +411,11 @@
case SECTION_LOG:
printf(" new LogSection(%d, %s),\n", field->number(), s.args().c_str());
break;
+ case SECTION_GZIP:
+ printf(" new GZipSection(%d,", field->number());
+ splitAndPrint(s.args());
+ printf(" NULL),\n");
+ break;
}
}
printf(" NULL };\n");
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index b5273dd..50c4b5e 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -999,6 +999,7 @@
// just in case legacy API needed some relatively real timestamp
legacyResults[i].ts = SystemClock.elapsedRealtime() * 1000;
}
+ i++;
}
listener.onSuccess(legacyResults);
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 06a5c2e..8529a89 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -27,6 +27,7 @@
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -420,9 +421,12 @@
"createNetworkSpecifier: Invalid 'role' argument when creating a network "
+ "specifier");
}
- if (peerHandle == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer handle - cannot be null");
+ if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR || !WifiAwareUtils.isLegacyVersion(mContext,
+ Build.VERSION_CODES.P)) {
+ if (peerHandle == null) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid peer handle - cannot be null");
+ }
}
return new WifiAwareNetworkSpecifier(
@@ -453,9 +457,12 @@
"createNetworkSpecifier: Invalid 'role' argument when creating a network "
+ "specifier");
}
- if (peer == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC - cannot be null");
+ if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR || !WifiAwareUtils.isLegacyVersion(mContext,
+ Build.VERSION_CODES.P)) {
+ if (peer == null) {
+ throw new IllegalArgumentException(
+ "createNetworkSpecifier: Invalid peer MAC - cannot be null");
+ }
}
if (peer != null && peer.length != 6) {
throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareUtils.java b/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
index fda7a9a..3ece93d 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
@@ -16,6 +16,8 @@
package android.net.wifi.aware;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.wifi.V1_0.Constants;
/**
@@ -84,4 +86,21 @@
return true;
}
+
+ /**
+ * Returns true if the App version is older than minVersion.
+ */
+ public static boolean isLegacyVersion(Context context, int minVersion) {
+ try {
+ if (context.getPackageManager().getApplicationInfo(context.getOpPackageName(), 0)
+ .targetSdkVersion < minVersion) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // In case of exception, assume known app (more strict checking)
+ // Note: This case will never happen since checkPackage is
+ // called to verify valididity before checking App's version.
+ }
+ return false;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 84e3ed9..272f727 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -19,14 +19,20 @@
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.net.wifi.RttManager;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
@@ -79,12 +85,32 @@
@Mock
public RttManager.RttListener mockRttListener;
+ @Mock
+ public PackageManager mockPackageManager;
+
+ @Mock
+ public ApplicationInfo mockApplicationInfo;
+
private static final int AWARE_STATUS_ERROR = -1;
+ private static final byte[] PMK_VALID = "01234567890123456789012345678901".getBytes();
+ private static final byte[] PMK_INVALID = "012".getBytes();
+
+ private static final String PASSPHRASE_VALID = "SomeLongEnoughPassphrase";
+ private static final String PASSPHRASE_TOO_SHORT = "012";
+ private static final String PASSPHRASE_TOO_LONG =
+ "0123456789012345678901234567890123456789012345678901234567890123456789";
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mockApplicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
+ when(mockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(
+ mockApplicationInfo);
+ when(mockContext.getOpPackageName()).thenReturn("XXX");
+ when(mockContext.getPackageManager()).thenReturn(mockPackageManager);
+
mDut = new WifiAwareManager(mockContext, mockAwareService);
mMockLooper = new TestLooper();
mMockLooperHandler = new Handler(mMockLooper.getLooper());
@@ -884,8 +910,8 @@
final int sessionId = 123;
final PeerHandle peerHandle = new PeerHandle(123412);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- final byte[] pmk = "01234567890123456789012345678901".getBytes();
- final String passphrase = "A really bad password";
+ final byte[] pmk = PMK_VALID;
+ final String passphrase = PASSPHRASE_VALID;
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
@@ -965,8 +991,8 @@
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
- final byte[] pmk = "01234567890123456789012345678901".getBytes();
- final String passphrase = "A really bad password";
+ final byte[] pmk = PMK_VALID;
+ final String passphrase = PASSPHRASE_VALID;
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1030,7 +1056,7 @@
*/
@Test(expected = IllegalArgumentException.class)
public void testNetworkSpecifierWithClientIncorrectLengthPmk() throws Exception {
- executeNetworkSpecifierWithClient(new PeerHandle(123412), true, "012".getBytes(), null);
+ executeNetworkSpecifierWithClient(new PeerHandle(123412), true, PMK_INVALID, null);
}
/**
@@ -1045,17 +1071,17 @@
* Validate that a too short Passphrase triggers an exception.
*/
@Test(expected = IllegalArgumentException.class)
- public void testNetworkSpecifierWithClientShortPassphrase() throws Exception {
- executeNetworkSpecifierWithClient(new PeerHandle(123412), false, null, "012");
+ public void testNetworkSpecifierWithClientTooShortPassphrase() throws Exception {
+ executeNetworkSpecifierWithClient(new PeerHandle(123412), false, null,
+ PASSPHRASE_TOO_SHORT);
}
/**
* Validate that a too long Passphrase triggers an exception.
*/
@Test(expected = IllegalArgumentException.class)
- public void testNetworkSpecifierWithClientLongPassphrase() throws Exception {
- executeNetworkSpecifierWithClient(new PeerHandle(123412), false, null,
- "0123456789012345678901234567890123456789012345678901234567890123456789");
+ public void testNetworkSpecifierWithClientTooLongPassphrase() throws Exception {
+ executeNetworkSpecifierWithClient(new PeerHandle(123412), false, null, PASSPHRASE_TOO_LONG);
}
/**
@@ -1063,8 +1089,16 @@
*/
@Test(expected = IllegalArgumentException.class)
public void testNetworkSpecifierWithClientNullPeer() throws Exception {
- executeNetworkSpecifierWithClient(null, false, null,
- "0123456789012345678901234567890123456789012345678901234567890123456789");
+ executeNetworkSpecifierWithClient(null, false, null, PASSPHRASE_VALID);
+ }
+
+ /**
+ * Validate that a null PeerHandle does not trigger an exception for legacy API.
+ */
+ @Test
+ public void testNetworkSpecifierWithClientNullPeerLegacyApi() throws Exception {
+ mockApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ executeNetworkSpecifierWithClient(null, false, null, PASSPHRASE_VALID);
}
private void executeNetworkSpecifierWithClient(PeerHandle peerHandle, boolean doPmk, byte[] pmk,
@@ -1117,7 +1151,7 @@
@Test(expected = IllegalArgumentException.class)
public void testNetworkSpecifierDirectNullPmk() throws Exception {
executeNetworkSpecifierDirect(HexEncoding.decode("000102030405".toCharArray(), false), true,
- null, null);
+ null, null, true);
}
/**
@@ -1126,7 +1160,7 @@
@Test(expected = IllegalArgumentException.class)
public void testNetworkSpecifierDirectIncorrectLengthPmk() throws Exception {
executeNetworkSpecifierDirect(HexEncoding.decode("000102030405".toCharArray(), false), true,
- "012".getBytes(), null);
+ PMK_INVALID, null, true);
}
/**
@@ -1135,40 +1169,57 @@
@Test(expected = IllegalArgumentException.class)
public void testNetworkSpecifierDirectNullPassphrase() throws Exception {
executeNetworkSpecifierDirect(HexEncoding.decode("000102030405".toCharArray(), false),
- false, null, null);
+ false, null, null, true);
}
/**
* Validate that a too short Passphrase triggers an exception.
*/
@Test(expected = IllegalArgumentException.class)
- public void testNetworkSpecifierDirectShortPassphrase() throws Exception {
+ public void testNetworkSpecifierDirectTooShortPassphrase() throws Exception {
executeNetworkSpecifierDirect(HexEncoding.decode("000102030405".toCharArray(), false),
- false, null, "012");
+ false, null, PASSPHRASE_TOO_SHORT, true);
}
/**
* Validate that a too long Passphrase triggers an exception.
*/
@Test(expected = IllegalArgumentException.class)
- public void testNetworkSpecifierDirectLongPassphrase() throws Exception {
+ public void testNetworkSpecifierDirectTooLongPassphrase() throws Exception {
executeNetworkSpecifierDirect(HexEncoding.decode("000102030405".toCharArray(), false),
- false, null,
- "0123456789012345678901234567890123456789012345678901234567890123456789");
+ false, null, PASSPHRASE_TOO_LONG, true);
}
/**
- * Validate that a null peer MAC triggers an exception.
+ * Validate that a null peer MAC triggers an exception for an Initiator.
*/
@Test(expected = IllegalArgumentException.class)
- public void testNetworkSpecifierDirectNullPeer() throws Exception {
- executeNetworkSpecifierDirect(null, false, null, null);
+ public void testNetworkSpecifierDirectNullPeerInitiator() throws Exception {
+ executeNetworkSpecifierDirect(null, false, null, PASSPHRASE_VALID, true);
+ }
+
+ /**
+ * Validate that a null peer MAC triggers an exception for a Resonder.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testNetworkSpecifierDirectNullPeerResponder() throws Exception {
+ executeNetworkSpecifierDirect(null, false, null, PASSPHRASE_VALID, false);
+ }
+
+ /**
+ * Validate that a null peer MAC does not trigger an exception for a Resonder on legacy API.
+ */
+ @Test
+ public void testNetworkSpecifierDirectNullPeerResponderLegacyApi() throws Exception {
+ mockApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ executeNetworkSpecifierDirect(null, false, null, PASSPHRASE_VALID, false);
}
private void executeNetworkSpecifierDirect(byte[] someMac, boolean doPmk, byte[] pmk,
- String passphrase) throws Exception {
+ String passphrase, boolean doInitiator) throws Exception {
final int clientId = 134;
- final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+ final int role = doInitiator ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index b573adf..c5ad7de 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -263,6 +263,7 @@
*
* @throws Exception
*/
+ @Test
public void validateCertCredentialWithoutCaCert() throws Exception {
Credential cred = createCredentialWithCertificateCredential();
cred.setCaCertificate(null);