Merge "Adding proto for QuotaTracker dumps."
diff --git a/Android.bp b/Android.bp
index 21552695..15188ec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1660,6 +1660,8 @@
         "core/java/android/util/LocalLog.java",
         "core/java/android/util/TimeUtils.java",
         "core/java/com/android/internal/os/SomeArgs.java",
+        "core/java/com/android/internal/util/AsyncChannel.java",
+        "core/java/com/android/internal/util/BitwiseInputStream.java",
         "core/java/com/android/internal/util/FastXmlSerializer.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IState.java",
diff --git a/api/current.txt b/api/current.txt
index 6ddd847..52dd1a1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22653,6 +22653,7 @@
     method public void onConfigureWindow(android.view.Window, boolean, boolean);
     method public android.view.View onCreateCandidatesView();
     method public android.view.View onCreateExtractTextView();
+    method @Nullable public android.view.inputmethod.InlineSuggestionsRequest onCreateInlineSuggestionsRequest();
     method public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
     method public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
     method public android.view.View onCreateInputView();
@@ -22669,6 +22670,7 @@
     method public void onFinishInput();
     method public void onFinishInputView(boolean);
     method public void onInitializeInterface();
+    method public boolean onInlineSuggestionsResponse(@NonNull android.view.inputmethod.InlineSuggestionsResponse);
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
@@ -36025,7 +36027,8 @@
     method @WorkerThread public long getCacheSizeBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method public String getMountedObbPath(String);
     method @NonNull public android.os.storage.StorageVolume getPrimaryStorageVolume();
-    method @Nullable public android.os.storage.StorageVolume getStorageVolume(java.io.File);
+    method @NonNull public java.util.List<android.os.storage.StorageVolume> getRecentStorageVolumes();
+    method @Nullable public android.os.storage.StorageVolume getStorageVolume(@NonNull java.io.File);
     method @NonNull public android.os.storage.StorageVolume getStorageVolume(@NonNull android.net.Uri);
     method @NonNull public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
     method @NonNull public java.util.UUID getUuidForPath(@NonNull java.io.File) throws java.io.IOException;
@@ -36051,6 +36054,8 @@
     method @NonNull public android.content.Intent createOpenDocumentTreeIntent();
     method public int describeContents();
     method public String getDescription(android.content.Context);
+    method @Nullable public java.io.File getDirectory();
+    method @Nullable public String getMediaStoreVolumeName();
     method public String getState();
     method @Nullable public String getUuid();
     method public boolean isEmulated();
@@ -38721,6 +38726,7 @@
     method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
     method public static android.net.Uri getMediaScannerUri();
     method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @NonNull public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
     method public static boolean getRequireOriginal(@NonNull android.net.Uri);
     method @NonNull public static String getVersion(@NonNull android.content.Context);
     method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String);
@@ -38986,6 +38992,7 @@
     method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long);
     method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long, long);
     method @Deprecated public static android.net.Uri getContentUri(String);
+    method @Deprecated @NonNull public static android.util.Size getKindSize(int);
     method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
     method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
     method @Deprecated public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, String[]);
@@ -39068,6 +39075,7 @@
     method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long);
     method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long, long);
     method @Deprecated public static android.net.Uri getContentUri(String);
+    method @Deprecated @NonNull public static android.util.Size getKindSize(int);
     method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
     method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
     field @Deprecated public static final String DATA = "_data";
@@ -41574,7 +41582,8 @@
     method @NonNull public java.util.List<android.service.autofill.FillContext> getFillContexts();
     method public int getFlags();
     method public int getId();
-    method public void writeToParcel(android.os.Parcel, int);
+    method @Nullable public android.view.inputmethod.InlineSuggestionsRequest getInlineSuggestionsRequest();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
     field public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 2; // 0x2
     field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
@@ -41591,6 +41600,7 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset);
+    method @NonNull public android.service.autofill.FillResponse.Builder addInlineSuggestionSlice(@NonNull android.app.slice.Slice);
     method @NonNull public android.service.autofill.FillResponse build();
     method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
     method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
@@ -52801,6 +52811,7 @@
 
   public static final class WindowInsetsAnimationCallback.InsetsAnimation {
     ctor public WindowInsetsAnimationCallback.InsetsAnimation(int, @Nullable android.view.animation.Interpolator, long);
+    method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
     method public long getDurationMillis();
     method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
     method public float getInterpolatedFraction();
@@ -52817,6 +52828,7 @@
 
   public interface WindowInsetsAnimationController {
     method public void finish(boolean);
+    method public float getCurrentAlpha();
     method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
     method @NonNull public android.graphics.Insets getCurrentInsets();
     method @NonNull public android.graphics.Insets getHiddenStateInsets();
diff --git a/api/removed.txt b/api/removed.txt
index 4e8e325..8b30d0a 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -436,10 +436,8 @@
   }
 
   public final class MediaStore {
-    method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
     method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
     method @Deprecated public static boolean getIncludePending(@NonNull android.net.Uri);
-    method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
     method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
@@ -473,22 +471,6 @@
     field @Deprecated public static final String GROUP_ID = "group_id";
   }
 
-  @Deprecated public static class MediaStore.PendingParams {
-    ctor public MediaStore.PendingParams(@NonNull android.net.Uri, @NonNull String, @NonNull String);
-    method public void setDownloadUri(@Nullable android.net.Uri);
-    method public void setRefererUri(@Nullable android.net.Uri);
-    method public void setRelativePath(@Nullable String);
-  }
-
-  @Deprecated public static class MediaStore.PendingSession implements java.lang.AutoCloseable {
-    method public void abandon();
-    method public void close();
-    method public void notifyProgress(@IntRange(from=0, to=100) int);
-    method @NonNull public android.os.ParcelFileDescriptor open() throws java.io.FileNotFoundException;
-    method @NonNull public java.io.OutputStream openOutputStream() throws java.io.FileNotFoundException;
-    method @NonNull public android.net.Uri publish();
-  }
-
   public static interface MediaStore.Video.VideoColumns extends android.provider.MediaStore.MediaColumns {
     field public static final String ALBUM = "album";
     field public static final String ARTIST = "artist";
diff --git a/api/system-current.txt b/api/system-current.txt
index 8d55a33..1108927 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6365,6 +6365,7 @@
   }
 
   public class Environment {
+    method @NonNull public static java.util.Collection<java.io.File> getInternalMediaDirectories();
     method @NonNull public static java.io.File getOdmDirectory();
     method @NonNull public static java.io.File getOemDirectory();
     method @NonNull public static java.io.File getProductDirectory();
@@ -7253,8 +7254,8 @@
   }
 
   public final class MediaStore {
-    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
-    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
+    method @NonNull public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
+    method public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
   }
 
   public abstract class SearchIndexableData {
@@ -9608,6 +9609,7 @@
   public final class SmsManager {
     method public boolean disableCellBroadcastRange(int, int, int);
     method public boolean enableCellBroadcastRange(int, int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSmsCapacityOnIcc();
     method public void sendMultipartTextMessage(@NonNull String, @NonNull String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 1c6bce0..219258e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -697,6 +697,7 @@
   public abstract class Context {
     method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
     method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public java.io.File getCrateDir(@NonNull String);
     method public abstract android.view.Display getDisplay();
     method public abstract int getDisplayId();
     method public android.os.UserHandle getUser();
@@ -2467,14 +2468,9 @@
   }
 
   public final class MediaStore {
-    method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
-    method @NonNull public static java.io.File getVolumePath(@NonNull String) throws java.io.FileNotFoundException;
-    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
-    method public static android.net.Uri scanFile(android.content.Context, java.io.File);
-    method public static android.net.Uri scanFileFromShell(android.content.Context, java.io.File);
-    method public static void scanVolume(android.content.Context, java.io.File);
-    method public static void waitForIdle(android.content.Context);
+    method @NonNull public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
+    method public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
+    method public static void waitForIdle(@NonNull android.content.ContentResolver);
   }
 
   public final class Settings {
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 484f823..afff614 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -146,6 +146,7 @@
         "libprotoutil",
         "libservices",
         "libstatslog",
+        "libstatsmetadata",
         "libstatssocket",
         "libsysutils",
         "libtimestats_proto",
@@ -153,6 +154,63 @@
     ],
 }
 
+// ================
+// libstatsmetadata
+// ================
+
+genrule {
+    name: "atoms_info.h",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --atomsInfoHeader $(genDir)/atoms_info.h",
+    out: [
+        "atoms_info.h",
+    ],
+}
+
+genrule {
+    name: "atoms_info.cpp",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --atomsInfoCpp $(genDir)/atoms_info.cpp",
+    out: [
+        "atoms_info.cpp",
+    ],
+}
+
+cc_library_shared {
+    name: "libstatsmetadata",
+    host_supported: true,
+    generated_sources: [
+        "atoms_info.cpp",
+    ],
+    generated_headers: [
+        "atoms_info.h",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_generated_headers: [
+        "atoms_info.h",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libstatslog",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libutils",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libutils",
+            ],
+        },
+    },
+}
+
+
 // =========
 // statsd
 // =========
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 84a0607..a545fc5 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -18,8 +18,8 @@
 #include "Log.h"
 #include "FieldValue.h"
 #include "HashableDimensionKey.h"
+#include "atoms_info.h"
 #include "math.h"
-#include "statslog.h"
 
 namespace android {
 namespace os {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 98d41c2..3481814 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -27,6 +27,7 @@
 #include <utils/SystemClock.h>
 
 #include "android-base/stringprintf.h"
+#include "atoms_info.h"
 #include "external/StatsPullerManager.h"
 #include "guardrail/StatsdStats.h"
 #include "metrics/CountMetricProducer.h"
diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp
index b142cac..dc69b78 100644
--- a/cmds/statsd/src/external/PowerStatsPuller.cpp
+++ b/cmds/statsd/src/external/PowerStatsPuller.cpp
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "PowerStatsPuller.h"
+#include "statslog.h"
 #include "stats_log_util.h"
 
 using android::hardware::hidl_vec;
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
index 53fa630..031c437 100644
--- a/cmds/statsd/src/external/puller_util.cpp
+++ b/cmds/statsd/src/external/puller_util.cpp
@@ -18,8 +18,8 @@
 #include "Log.h"
 
 #include "StatsPullerManager.h"
+#include "atoms_info.h"
 #include "puller_util.h"
-#include "statslog.h"
 
 namespace android {
 namespace os {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 23d2ace..564b9ee 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -16,7 +16,7 @@
 #pragma once
 
 #include "config/ConfigKey.h"
-#include "statslog.h"
+#include "atoms_info.h"
 
 #include <gtest/gtest_prod.h>
 #include <log/log_time.h>
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 464cec3..088f607 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -23,6 +23,7 @@
 #include <utils/SystemClock.h>
 
 #include "CountMetricProducer.h"
+#include "atoms_info.h"
 #include "condition/CombinationConditionTracker.h"
 #include "condition/SimpleConditionTracker.h"
 #include "guardrail/StatsdStats.h"
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 9131802..2ad8217 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -22,6 +22,7 @@
 
 #include <inttypes.h>
 
+#include "atoms_info.h"
 #include "condition/CombinationConditionTracker.h"
 #include "condition/SimpleConditionTracker.h"
 #include "condition/StateConditionTracker.h"
@@ -36,7 +37,6 @@
 #include "metrics/ValueMetricProducer.h"
 #include "state/StateManager.h"
 #include "stats_util.h"
-#include "statslog.h"
 
 using std::set;
 using std::string;
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index e65325a..7453370 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -15,7 +15,7 @@
  */
 #pragma once
 
-#include <statslog.h>
+#include <atoms_info.h>
 #include <utils/RefBase.h>
 #include "HashableDimensionKey.h"
 #include "logd/LogEvent.h"
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index 0a86363..f3e9433 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -19,9 +19,9 @@
 #include <android/util/ProtoOutputStream.h>
 #include "FieldValue.h"
 #include "HashableDimensionKey.h"
+#include "atoms_info.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "guardrail/StatsdStats.h"
-#include "statslog.h"
 
 namespace android {
 namespace os {
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
index e91fb0d..6abdfa3 100644
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -24,6 +24,7 @@
 #include <log/log.h>
 
 #include "src/external/GpuStatsPuller.h"
+#include "statslog.h"
 
 #ifdef __ANDROID__
 
diff --git a/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
index 5c9636f..5b7a30d 100644
--- a/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "SurfaceflingerStatsPuller_test"
 
 #include "src/external/SurfaceflingerStatsPuller.h"
+#include "statslog.h"
 
 #include <gtest/gtest.h>
 #include <log/log.h>
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
index 266ea35..6730828 100644
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 #include <stdio.h>
 #include <vector>
+#include "statslog.h"
 #include "../metrics/metrics_test_helper.h"
 
 #ifdef __ANDROID__
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 46f88d5..155e93f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -99,6 +99,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteOrder;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -251,6 +252,8 @@
     @GuardedBy("mSync")
     private File mFilesDir;
     @GuardedBy("mSync")
+    private File mCratesDir;
+    @GuardedBy("mSync")
     private File mNoBackupFilesDir;
     @GuardedBy("mSync")
     private File mCacheDir;
@@ -702,6 +705,24 @@
     }
 
     @Override
+    public File getCrateDir(@NonNull String crateId) {
+        Preconditions.checkArgument(FileUtils.isValidExtFilename(crateId), "invalidated crateId");
+        final Path cratesRootPath = getDataDir().toPath().resolve("crates");
+        final Path absoluteNormalizedCratePath = cratesRootPath.resolve(crateId)
+                .toAbsolutePath().normalize();
+
+        synchronized (mSync) {
+            if (mCratesDir == null) {
+                mCratesDir = cratesRootPath.toFile();
+            }
+            ensurePrivateDirExists(mCratesDir);
+        }
+
+        File cratedDir = absoluteNormalizedCratePath.toFile();
+        return ensurePrivateDirExists(cratedDir);
+    }
+
+    @Override
     public File getNoBackupFilesDir() {
         synchronized (mSync) {
             if (mNoBackupFilesDir == null) {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 80c9ba2..eb50581 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1314,8 +1314,8 @@
 
         // TODO: DownloadProvider.update() should take care of updating corresponding
         // MediaProvider entries.
-        MediaStore.scanFile(context, before);
-        MediaStore.scanFile(context, after);
+        MediaStore.scanFile(mResolver, before);
+        MediaStore.scanFile(mResolver, after);
 
         final ContentValues values = new ContentValues();
         values.put(Downloads.Impl.COLUMN_TITLE, displayName);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index a1305da..ce21db3 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -152,6 +152,8 @@
 import android.os.health.SystemHealthManager;
 import android.os.image.DynamicSystemManager;
 import android.os.image.IDynamicSystemService;
+import android.os.incremental.IIncrementalManagerNative;
+import android.os.incremental.IncrementalManager;
 import android.os.storage.StorageManager;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
@@ -1225,6 +1227,20 @@
                                 Context.DATA_LOADER_MANAGER_SERVICE);
                         return new DataLoaderManager(IDataLoaderManager.Stub.asInterface(b));
                     }});
+        //TODO(b/136132412): refactor this: 1) merge IIncrementalManager.aidl and
+        //IIncrementalManagerNative.aidl, 2) implement the binder interface in
+        //IncrementalManagerService.java, 3) use JNI to call native functions
+        registerService(Context.INCREMENTAL_SERVICE, IncrementalManager.class,
+                new CachedServiceFetcher<IncrementalManager>() {
+                    @Override
+                    public IncrementalManager createService(ContextImpl ctx) {
+                        IBinder b = ServiceManager.getService(Context.INCREMENTAL_SERVICE);
+                        if (b == null) {
+                            return null;
+                        }
+                        return new IncrementalManager(
+                                IIncrementalManagerNative.Stub.asInterface(b));
+                    }});
         //CHECKSTYLE:ON IndentationCheck
 
         sInitializing = true;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d084449..24b5061 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1060,6 +1060,31 @@
     public abstract File getFilesDir();
 
     /**
+     * Returns the absolute path to the directory that is related to the crate on the filesystem.
+     * <p>
+     *     The crateId require a validated file name. It can't contain any "..", ".",
+     *     {@link File#separatorChar} etc..
+     * </p>
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
+     * </p>
+     * <p>
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path.
+     *</p>
+     *
+     * @param crateId the relative validated file name under {@link Context#getDataDir()}/crates
+     * @return the crate directory file.
+     * @hide
+     */
+    @NonNull
+    @TestApi
+    public File getCrateDir(@NonNull String crateId) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Returns the absolute path to the directory on the filesystem similar to
      * {@link #getFilesDir()}. The difference is that files placed under this
      * directory will be excluded from automatic backup to remote storage. See
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index d6442e2..d1b5135 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -252,6 +252,16 @@
         return mBase.getFilesDir();
     }
 
+    /**
+     * {@inheritDoc Context#getCrateDir()}
+     * @hide
+     */
+    @NonNull
+    @Override
+    public File getCrateDir(@NonNull String cratedId) {
+        return mBase.getCrateDir(cratedId);
+    }
+
     @Override
     public File getNoBackupFilesDir() {
         return mBase.getNoBackupFilesDir();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 94af541..0d1f404 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1513,16 +1513,6 @@
     public static final int DELETE_DONT_KILL_APP = 0x00000008;
 
     /**
-     * Flag parameter for {@link #deletePackage} to indicate that any
-     * contributed media should also be deleted during this uninstall. The
-     * meaning of "contributed" means it won't automatically be deleted when the
-     * app is uninstalled.
-     *
-     * @hide
-     */
-    public static final int DELETE_CONTRIBUTED_MEDIA = 0x00000010;
-
-    /**
      * Flag parameter for {@link #deletePackage} to indicate that package deletion
      * should be chatty.
      *
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 48d8867..39c1dac 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -823,6 +823,7 @@
         switch (token.toUpperCase(Locale.US)) {
             case "COLLATE": case "ASC": case "DESC":
             case "BINARY": case "RTRIM": case "NOCASE":
+            case "LOCALIZED": case "UNICODE":
                 return;
         }
         throw new IllegalArgumentException("Invalid token " + token);
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index a47f601..62f0196 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -19,6 +19,7 @@
 import android.annotation.BinderThread;
 import android.annotation.MainThread;
 import android.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -28,6 +29,7 @@
 import android.os.ResultReceiver;
 import android.util.Log;
 import android.view.InputChannel;
+import android.view.autofill.AutofillId;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
@@ -39,6 +41,7 @@
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
 import com.android.internal.view.IInputMethodSession;
@@ -72,6 +75,7 @@
     private static final int DO_SHOW_SOFT_INPUT = 60;
     private static final int DO_HIDE_SOFT_INPUT = 70;
     private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80;
+    private static final int DO_CREATE_INLINE_SUGGESTIONS_REQUEST = 90;
 
     final WeakReference<AbstractInputMethodService> mTarget;
     final Context mContext;
@@ -225,6 +229,11 @@
             case DO_CHANGE_INPUTMETHOD_SUBTYPE:
                 inputMethod.changeInputMethodSubtype((InputMethodSubtype)msg.obj);
                 return;
+            case DO_CREATE_INLINE_SUGGESTIONS_REQUEST:
+                SomeArgs args = (SomeArgs) msg.obj;
+                inputMethod.onCreateInlineSuggestionsRequest((ComponentName) args.arg1,
+                        (AutofillId) args.arg2, (IInlineSuggestionsRequestCallback) args.arg3);
+                return;
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -267,6 +276,15 @@
 
     @BinderThread
     @Override
+    public void onCreateInlineSuggestionsRequest(ComponentName componentName, AutofillId autofillId,
+            IInlineSuggestionsRequestCallback cb) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageOOO(DO_CREATE_INLINE_SUGGESTIONS_REQUEST, componentName,
+                        autofillId, cb));
+    }
+
+    @BinderThread
+    @Override
     public void bindInput(InputBinding binding) {
         if (mIsUnbindIssued != null) {
             Log.e(TAG, "bindInput must be paired with unbindInput.");
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 156bcfe..7da7dc1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -23,6 +23,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
 
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.AnyThread;
@@ -35,6 +37,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.Dialog;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -47,6 +50,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -70,11 +75,14 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
+import android.view.autofill.AutofillId;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputContentInfo;
@@ -91,11 +99,14 @@
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.IInlineSuggestionsResponseCallback;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.Collections;
 
 /**
@@ -436,6 +447,14 @@
     final Insets mTmpInsets = new Insets();
     final int[] mTmpLocation = new int[2];
 
+    @Nullable
+    private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null;
+
+    @Nullable
+    private InlineSuggestionsResponseCallbackImpl mInlineSuggestionsResponseCallback = null;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
+
     final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
         onComputeInsets(mTmpInsets);
         if (isExtractViewShown()) {
@@ -495,6 +514,18 @@
 
         /**
          * {@inheritDoc}
+         * @hide
+         */
+        @MainThread
+        @Override
+        public void onCreateInlineSuggestionsRequest(ComponentName componentName,
+                AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+            Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()");
+            handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb);
+        }
+
+        /**
+         * {@inheritDoc}
          */
         @MainThread
         @Override
@@ -670,6 +701,103 @@
         }
     }
 
+    // TODO(b/137800469): Add detailed docs explaining the inline suggestions process.
+    /**
+     * Returns an {@link InlineSuggestionsRequest} to be sent to Autofill.
+     *
+     * <p>Should be implemented by subclasses.</p>
+     */
+    public @Nullable InlineSuggestionsRequest onCreateInlineSuggestionsRequest() {
+        return null;
+    }
+
+    /**
+     * Called when Autofill responds back with {@link InlineSuggestionsResponse} containing
+     * inline suggestions.
+     *
+     * <p>Should be implemented by subclasses.</p>
+     *
+     * @param response {@link InlineSuggestionsResponse} passed back by Autofill.
+     * @return Whether the IME will use and render  the inline suggestions.
+     */
+    public boolean onInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) {
+        return false;
+    }
+
+    /**
+     * Returns whether inline suggestions are enabled on this service.
+     *
+     * TODO(b/137800469): check XML for value.
+     */
+    private boolean isInlineSuggestionsEnabled() {
+        return true;
+    }
+
+    /**
+     * Sends an {@link InlineSuggestionsRequest} obtained from
+     * {@link #onCreateInlineSuggestionsRequest()} to the current Autofill Session through
+     * {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}.
+     */
+    private void makeInlineSuggestionsRequest() {
+        if (mInlineSuggestionsRequestInfo == null) {
+            Log.w(TAG, "makeInlineSuggestionsRequest() called with null requestInfo cache");
+            return;
+        }
+
+        final IInlineSuggestionsRequestCallback requestCallback =
+                mInlineSuggestionsRequestInfo.mCallback;
+        try {
+            final InlineSuggestionsRequest request = onCreateInlineSuggestionsRequest();
+            if (request == null) {
+                Log.w(TAG, "onCreateInlineSuggestionsRequest() returned null request");
+                requestCallback.onInlineSuggestionsUnsupported();
+            } else {
+                if (mInlineSuggestionsResponseCallback == null) {
+                    mInlineSuggestionsResponseCallback =
+                            new InlineSuggestionsResponseCallbackImpl(this,
+                                    mInlineSuggestionsRequestInfo.mComponentName,
+                                    mInlineSuggestionsRequestInfo.mFocusedId);
+                }
+                requestCallback.onInlineSuggestionsRequest(request,
+                        mInlineSuggestionsResponseCallback);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "makeInlinedSuggestionsRequest() remote exception:" + e);
+        }
+    }
+
+    private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName,
+            @NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) {
+        mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId,
+                callback);
+
+        if (!isInlineSuggestionsEnabled()) {
+            try {
+                callback.onInlineSuggestionsUnsupported();
+            } catch (RemoteException e) {
+                Log.w(TAG, "handleMakeInlineSuggestionsRequest() RemoteException:" + e);
+            }
+            return;
+        }
+
+        if (!mInputStarted) {
+            Log.w(TAG, "onStartInput() not called yet");
+            return;
+        }
+
+        makeInlineSuggestionsRequest();
+    }
+
+    private void handleOnInlineSuggestionsResponse(@NonNull ComponentName componentName,
+            @NonNull AutofillId autofillId, @NonNull InlineSuggestionsResponse response) {
+        if (!mInlineSuggestionsRequestInfo.validate(componentName)) {
+            Log.d(TAG, "Response component=" + componentName + " differs from request component="
+                    + mInlineSuggestionsRequestInfo.mComponentName + ", ignoring response");
+            return;
+        }
+        onInlineSuggestionsResponse(response);
+    }
+
     private void notifyImeHidden() {
         setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
         onPreRenderedWindowVisibilityChanged(false /* setVisible */);
@@ -688,6 +816,63 @@
     }
 
     /**
+     * Internal implementation of {@link IInlineSuggestionsResponseCallback}.
+     */
+    private static final class InlineSuggestionsResponseCallbackImpl
+            extends IInlineSuggestionsResponseCallback.Stub {
+        private final WeakReference<InputMethodService> mInputMethodService;
+
+        private final ComponentName mRequestComponentName;
+        private final AutofillId mRequestAutofillId;
+
+        private InlineSuggestionsResponseCallbackImpl(InputMethodService inputMethodService,
+                ComponentName componentName, AutofillId autofillId) {
+            mInputMethodService = new WeakReference<>(inputMethodService);
+            mRequestComponentName = componentName;
+            mRequestAutofillId = autofillId;
+        }
+
+        @Override
+        public void onInlineSuggestionsResponse(InlineSuggestionsResponse response)
+                throws RemoteException {
+            final InputMethodService service = mInputMethodService.get();
+            if (service != null) {
+                service.mHandler.sendMessage(obtainMessage(
+                        InputMethodService::handleOnInlineSuggestionsResponse, service,
+                        mRequestComponentName, mRequestAutofillId, response));
+            }
+        }
+    }
+
+    /**
+     * Information about incoming requests from Autofill Frameworks for inline suggestions.
+     */
+    private static final class InlineSuggestionsRequestInfo {
+        final ComponentName mComponentName;
+        final AutofillId mFocusedId;
+        final IInlineSuggestionsRequestCallback mCallback;
+
+        InlineSuggestionsRequestInfo(ComponentName componentName, AutofillId focusedId,
+                IInlineSuggestionsRequestCallback callback) {
+            this.mComponentName = componentName;
+            this.mFocusedId = focusedId;
+            this.mCallback = callback;
+        }
+
+        /**
+         * Returns whether the cached {@link ComponentName} matches the passed in activity.
+         */
+        public boolean validate(ComponentName componentName) {
+            final boolean result = componentName.equals(mComponentName);
+            if (!result) {
+                Log.d(TAG, "Cached request info ComponentName=" + mComponentName
+                        + " differs from received ComponentName=" + componentName);
+            }
+            return result;
+        }
+    }
+
+    /**
      * Concrete implementation of
      * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
      * all of the standard behavior for an input method session.
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a92237b..61da5e6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -34,6 +34,8 @@
 import android.util.Log;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.LinkedList;
 
 /**
@@ -528,6 +530,22 @@
     }
 
     /**
+     * Return locations where media files (such as ringtones, notification
+     * sounds, or alarm sounds) may be located on internal storage. These are
+     * typically indexed under {@link MediaStore#VOLUME_INTERNAL}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static @NonNull Collection<File> getInternalMediaDirectories() {
+        final ArrayList<File> res = new ArrayList<>();
+        res.add(new File(Environment.getRootDirectory(), "media"));
+        res.add(new File(Environment.getOemDirectory(), "media"));
+        res.add(new File(Environment.getProductDirectory(), "media"));
+        return res;
+    }
+
+    /**
      * Return the primary shared/external storage directory. This directory may
      * not currently be accessible if it has been mounted by the user on their
      * computer, has been removed from the device, or some other problem has
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 62603fe..2e9f27e 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -264,6 +264,8 @@
     public static final int FLAG_REAL_STATE = 1 << 9;
     /** {@hide} */
     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
+    /** {@hide} */
+    public static final int FLAG_INCLUDE_RECENT = 1 << 11;
 
     /** {@hide} */
     public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
@@ -1125,7 +1127,7 @@
      * Return the {@link StorageVolume} that contains the given file, or
      * {@code null} if none.
      */
-    public @Nullable StorageVolume getStorageVolume(File file) {
+    public @Nullable StorageVolume getStorageVolume(@NonNull File file) {
         return getStorageVolume(getVolumeList(), file);
     }
 
@@ -1140,7 +1142,7 @@
                 return getPrimaryStorageVolume();
             default:
                 for (StorageVolume vol : getStorageVolumes()) {
-                    if (Objects.equals(vol.getNormalizedUuid(), volumeName)) {
+                    if (Objects.equals(vol.getMediaStoreVolumeName(), volumeName)) {
                         return vol;
                     }
                 }
@@ -1201,12 +1203,13 @@
     }
 
     /**
-     * Return the list of shared/external storage volumes available to the
-     * current user. This includes both the primary shared storage device and
-     * any attached external volumes including SD cards and USB drives.
-     *
-     * @see Environment#getExternalStorageDirectory()
-     * @see StorageVolume#createAccessIntent(String)
+     * Return the list of shared/external storage volumes currently available to
+     * the calling user.
+     * <p>
+     * These storage volumes are actively attached to the device, but may be in
+     * any mount state, as returned by {@link StorageVolume#getState()}. Returns
+     * both the primary shared storage device and any attached external volumes,
+     * including SD cards and USB drives.
      */
     public @NonNull List<StorageVolume> getStorageVolumes() {
         final ArrayList<StorageVolume> res = new ArrayList<>();
@@ -1216,6 +1219,22 @@
     }
 
     /**
+     * Return the list of shared/external storage volumes both currently and
+     * recently available to the calling user.
+     * <p>
+     * Recently available storage volumes are likely to reappear in the future,
+     * so apps are encouraged to preserve any indexed metadata related to these
+     * volumes to optimize user experiences.
+     */
+    public @NonNull List<StorageVolume> getRecentStorageVolumes() {
+        final ArrayList<StorageVolume> res = new ArrayList<>();
+        Collections.addAll(res,
+                getVolumeList(mContext.getUserId(),
+                        FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE | FLAG_INCLUDE_RECENT));
+        return res;
+    }
+
+    /**
      * Return the primary shared/external storage volume available to the
      * current user. This volume is the same storage device returned by
      * {@link Environment#getExternalStorageDirectory()} and
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index aefe843..560d617 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -29,6 +29,7 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.provider.DocumentsContract;
+import android.provider.MediaStore;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -173,7 +174,7 @@
      * @return the mount path
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@link StorageVolume#getDirectory()}")
     @TestApi
     public String getPath() {
         return mPath.toString();
@@ -190,12 +191,35 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@link StorageVolume#getDirectory()}")
     public File getPathFile() {
         return mPath;
     }
 
     /**
+     * Returns the directory where this volume is currently mounted.
+     * <p>
+     * Direct filesystem access via this path has significant emulation
+     * overhead, and apps are instead strongly encouraged to interact with media
+     * on storage volumes via the {@link MediaStore} APIs.
+     * <p>
+     * This directory does not give apps any additional access beyond what they
+     * already have via {@link MediaStore}.
+     *
+     * @return directory where this volume is mounted, or {@code null} if the
+     *         volume is not currently mounted.
+     */
+    public @Nullable File getDirectory() {
+        switch (mState) {
+            case Environment.MEDIA_MOUNTED:
+            case Environment.MEDIA_MOUNTED_READ_ONLY:
+                return mPath;
+            default:
+                return null;
+        }
+    }
+
+    /**
      * Returns a user-visible description of the volume.
      *
      * @return the volume description
@@ -265,6 +289,24 @@
         return mFsUuid;
     }
 
+    /**
+     * Return the volume name that can be used to interact with this storage
+     * device through {@link MediaStore}.
+     *
+     * @return opaque volume name, or {@code null} if this volume is not indexed
+     *         by {@link MediaStore}.
+     * @see android.provider.MediaStore.Audio.Media#getContentUri(String)
+     * @see android.provider.MediaStore.Video.Media#getContentUri(String)
+     * @see android.provider.MediaStore.Images.Media#getContentUri(String)
+     */
+    public @Nullable String getMediaStoreVolumeName() {
+        if (isPrimary()) {
+            return MediaStore.VOLUME_EXTERNAL_PRIMARY;
+        } else {
+            return getNormalizedUuid();
+        }
+    }
+
     /** {@hide} */
     public static @Nullable String normalizeUuid(@Nullable String fsUuid) {
         return fsUuid != null ? fsUuid.toLowerCase(Locale.US) : null;
diff --git a/core/java/android/os/storage/VolumeRecord.java b/core/java/android/os/storage/VolumeRecord.java
index 1a794eb..99b45d6 100644
--- a/core/java/android/os/storage/VolumeRecord.java
+++ b/core/java/android/os/storage/VolumeRecord.java
@@ -17,14 +17,18 @@
 package android.os.storage;
 
 import android.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.os.Environment;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.DebugUtils;
 import android.util.TimeUtils;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 
+import java.io.File;
 import java.util.Locale;
 import java.util.Objects;
 
@@ -92,6 +96,27 @@
         return (userFlags & USER_FLAG_SNOOZED) != 0;
     }
 
+    public StorageVolume buildStorageVolume(Context context) {
+        final String id = "unknown:" + fsUuid;
+        final File userPath = new File("/dev/null");
+        final File internalPath = new File("/dev/null");
+        final boolean primary = false;
+        final boolean removable = true;
+        final boolean emulated = false;
+        final boolean allowMassStorage = false;
+        final long maxFileSize = 0;
+        final UserHandle user = new UserHandle(UserHandle.USER_NULL);
+        final String envState = Environment.MEDIA_UNKNOWN;
+
+        String description = nickname;
+        if (description == null) {
+            description = context.getString(android.R.string.unknownName);
+        }
+
+        return new StorageVolume(id, userPath, internalPath, description, primary, removable,
+                emulated, allowMassStorage, maxFileSize, user, fsUuid, envState);
+    }
+
     public void dump(IndentingPrintWriter pw) {
         pw.println("VolumeRecord:");
         pw.increaseIndent();
diff --git a/core/java/android/provider/BaseColumns.java b/core/java/android/provider/BaseColumns.java
index 00c9e72..b216e2b 100644
--- a/core/java/android/provider/BaseColumns.java
+++ b/core/java/android/provider/BaseColumns.java
@@ -16,13 +16,11 @@
 
 package android.provider;
 
-import android.database.Cursor;
-
 public interface BaseColumns {
     /**
      * The unique ID for a row.
      */
-    @Column(Cursor.FIELD_TYPE_INTEGER)
+    // @Column(Cursor.FIELD_TYPE_INTEGER)
     public static final String _ID = "_id";
 
     /**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 701ba91..63204d3 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -21,17 +21,15 @@
 import android.annotation.CurrentTimeSecondsLong;
 import android.annotation.DurationMillisLong;
 import android.annotation.IntDef;
-import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
-import android.app.AppGlobals;
 import android.app.PendingIntent;
 import android.content.ClipData;
 import android.content.ContentProviderClient;
@@ -45,39 +43,28 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.ImageDecoder;
-import android.graphics.Point;
 import android.graphics.PostProcessor;
 import android.media.ExifInterface;
-import android.media.MediaFile;
 import android.media.MediaFormat;
 import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Environment;
-import android.os.FileUtils;
 import android.os.OperationCanceledException;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
-import android.os.storage.VolumeInfo;
-import android.os.storage.VolumeRecord;
-import android.service.media.CameraPrewarmService;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
+import android.util.Size;
 
 import libcore.util.HexEncoding;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -162,9 +149,6 @@
     /** {@hide} */
     public static final String SCAN_VOLUME_CALL = "scan_volume";
     /** {@hide} */
-    public static final String SUICIDE_CALL = "suicide";
-
-    /** {@hide} */
     public static final String CREATE_WRITE_REQUEST_CALL = "create_write_request";
     /** {@hide} */
     public static final String CREATE_TRASH_REQUEST_CALL = "create_trash_request";
@@ -173,42 +157,19 @@
     /** {@hide} */
     public static final String CREATE_DELETE_REQUEST_CALL = "create_delete_request";
 
-    /**
-     * Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that
-     * the file path originated from shell.
-     *
-     * {@hide}
-     */
-    public static final String EXTRA_ORIGINATED_FROM_SHELL =
-            "android.intent.extra.originated_from_shell";
-
-    /**
-     * The method name used by the media scanner and mtp to tell the media provider to
-     * rescan and reclassify that have become unhidden because of renaming folders or
-     * removing nomedia files
-     * @hide
-     */
-    @Deprecated
-    public static final String UNHIDE_CALL = "unhide";
-
-    /**
-     * The method name used by the media scanner service to reload all localized ringtone titles due
-     * to a locale change.
-     * @hide
-     */
-    public static final String RETRANSLATE_CALL = "update_titles";
 
     /** {@hide} */
     public static final String GET_VERSION_CALL = "get_version";
+
     /** {@hide} */
     public static final String GET_DOCUMENT_URI_CALL = "get_document_uri";
     /** {@hide} */
     public static final String GET_MEDIA_URI_CALL = "get_media_uri";
 
     /** {@hide} */
-    public static final String GET_CONTRIBUTED_MEDIA_CALL = "get_contributed_media";
+    public static final String EXTRA_URI = "uri";
     /** {@hide} */
-    public static final String DELETE_CONTRIBUTED_MEDIA_CALL = "delete_contributed_media";
+    public static final String EXTRA_URI_PERMISSIONS = "uriPermissions";
 
     /** {@hide} */
     public static final String EXTRA_CLIP_DATA = "clip_data";
@@ -391,10 +352,10 @@
      * service.
      * <p>
      * This meta-data should reference the fully qualified class name of the prewarm service
-     * extending {@link CameraPrewarmService}.
+     * extending {@code CameraPrewarmService}.
      * <p>
      * The prewarm service will get bound and receive a prewarm signal
-     * {@link CameraPrewarmService#onPrewarm()} when a camera launch intent fire might be imminent.
+     * {@code CameraPrewarmService#onPrewarm()} when a camera launch intent fire might be imminent.
      * An application implementing a prewarm service should do the absolute minimum amount of work
      * to initialize the camera in order to reduce startup time in likely case that shortly after a
      * camera launch intent would be sent.
@@ -775,197 +736,6 @@
     }
 
     /**
-     * Create a new pending media item using the given parameters. Pending items
-     * are expected to have a short lifetime, and owners should either
-     * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a
-     * pending item within a few hours after first creating it.
-     *
-     * @return token which can be passed to {@link #openPending(Context, Uri)}
-     *         to work with this pending item.
-     * @see MediaColumns#IS_PENDING
-     * @see MediaStore#setIncludePending(Uri)
-     * @see MediaStore#createPending(Context, PendingParams)
-     * @removed
-     */
-    @Deprecated
-    public static @NonNull Uri createPending(@NonNull Context context,
-            @NonNull PendingParams params) {
-        return context.getContentResolver().insert(params.insertUri, params.insertValues);
-    }
-
-    /**
-     * Open a pending media item to make progress on it. You can open a pending
-     * item multiple times before finally calling either
-     * {@link PendingSession#publish()} or {@link PendingSession#abandon()}.
-     *
-     * @param uri token which was previously returned from
-     *            {@link #createPending(Context, PendingParams)}.
-     * @removed
-     */
-    @Deprecated
-    public static @NonNull PendingSession openPending(@NonNull Context context, @NonNull Uri uri) {
-        return new PendingSession(context, uri);
-    }
-
-    /**
-     * Parameters that describe a pending media item.
-     *
-     * @removed
-     */
-    @Deprecated
-    public static class PendingParams {
-        /** {@hide} */
-        public final Uri insertUri;
-        /** {@hide} */
-        public final ContentValues insertValues;
-
-        /**
-         * Create parameters that describe a pending media item.
-         *
-         * @param insertUri the {@code content://} Uri where this pending item
-         *            should be inserted when finally published. For example, to
-         *            publish an image, use
-         *            {@link MediaStore.Images.Media#getContentUri(String)}.
-         */
-        public PendingParams(@NonNull Uri insertUri, @NonNull String displayName,
-                @NonNull String mimeType) {
-            this.insertUri = Objects.requireNonNull(insertUri);
-            final long now = System.currentTimeMillis() / 1000;
-            this.insertValues = new ContentValues();
-            this.insertValues.put(MediaColumns.DISPLAY_NAME, Objects.requireNonNull(displayName));
-            this.insertValues.put(MediaColumns.MIME_TYPE, Objects.requireNonNull(mimeType));
-            this.insertValues.put(MediaColumns.DATE_ADDED, now);
-            this.insertValues.put(MediaColumns.DATE_MODIFIED, now);
-            this.insertValues.put(MediaColumns.IS_PENDING, 1);
-            this.insertValues.put(MediaColumns.DATE_EXPIRES,
-                    (System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS) / 1000);
-        }
-
-        public void setRelativePath(@Nullable String relativePath) {
-            if (relativePath == null) {
-                this.insertValues.remove(MediaColumns.RELATIVE_PATH);
-            } else {
-                this.insertValues.put(MediaColumns.RELATIVE_PATH, relativePath);
-            }
-        }
-
-        /**
-         * Optionally set the Uri from where the file has been downloaded. This is used
-         * for files being added to {@link Downloads} table.
-         *
-         * @see DownloadColumns#DOWNLOAD_URI
-         */
-        public void setDownloadUri(@Nullable Uri downloadUri) {
-            if (downloadUri == null) {
-                this.insertValues.remove(DownloadColumns.DOWNLOAD_URI);
-            } else {
-                this.insertValues.put(DownloadColumns.DOWNLOAD_URI, downloadUri.toString());
-            }
-        }
-
-        /**
-         * Optionally set the Uri indicating HTTP referer of the file. This is used for
-         * files being added to {@link Downloads} table.
-         *
-         * @see DownloadColumns#REFERER_URI
-         */
-        public void setRefererUri(@Nullable Uri refererUri) {
-            if (refererUri == null) {
-                this.insertValues.remove(DownloadColumns.REFERER_URI);
-            } else {
-                this.insertValues.put(DownloadColumns.REFERER_URI, refererUri.toString());
-            }
-        }
-    }
-
-    /**
-     * Session actively working on a pending media item. Pending items are
-     * expected to have a short lifetime, and owners should either
-     * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a
-     * pending item within a few hours after first creating it.
-     *
-     * @removed
-     */
-    @Deprecated
-    public static class PendingSession implements AutoCloseable {
-        /** {@hide} */
-        private final Context mContext;
-        /** {@hide} */
-        private final Uri mUri;
-
-        /** {@hide} */
-        public PendingSession(Context context, Uri uri) {
-            mContext = Objects.requireNonNull(context);
-            mUri = Objects.requireNonNull(uri);
-        }
-
-        /**
-         * Open the underlying file representing this media item. When a media
-         * item is successfully completed, you should
-         * {@link ParcelFileDescriptor#close()} and then {@link #publish()} it.
-         *
-         * @see #notifyProgress(int)
-         */
-        public @NonNull ParcelFileDescriptor open() throws FileNotFoundException {
-            return mContext.getContentResolver().openFileDescriptor(mUri, "rw");
-        }
-
-        /**
-         * Open the underlying file representing this media item. When a media
-         * item is successfully completed, you should
-         * {@link OutputStream#close()} and then {@link #publish()} it.
-         *
-         * @see #notifyProgress(int)
-         */
-        public @NonNull OutputStream openOutputStream() throws FileNotFoundException {
-            return mContext.getContentResolver().openOutputStream(mUri);
-        }
-
-        /**
-         * Notify of current progress on this pending media item. Gallery
-         * applications may choose to surface progress information of this
-         * pending item.
-         *
-         * @param progress a percentage between 0 and 100.
-         */
-        public void notifyProgress(@IntRange(from = 0, to = 100) int progress) {
-            final Uri withProgress = mUri.buildUpon()
-                    .appendQueryParameter(PARAM_PROGRESS, Integer.toString(progress)).build();
-            mContext.getContentResolver().notifyChange(withProgress, null, 0);
-        }
-
-        /**
-         * When this media item is successfully completed, call this method to
-         * publish and make the final item visible to the user.
-         *
-         * @return the final {@code content://} Uri representing the newly
-         *         published media.
-         */
-        public @NonNull Uri publish() {
-            final ContentValues values = new ContentValues();
-            values.put(MediaColumns.IS_PENDING, 0);
-            values.putNull(MediaColumns.DATE_EXPIRES);
-            mContext.getContentResolver().update(mUri, values, null, null);
-            return mUri;
-        }
-
-        /**
-         * When this media item has failed to be completed, call this method to
-         * destroy the pending item record and any data related to it.
-         */
-        public void abandon() {
-            mContext.getContentResolver().delete(mUri, null, null);
-        }
-
-        @Override
-        public void close() {
-            // No resources to close, but at least we can inform people that no
-            // progress is being actively made.
-            notifyProgress(-1);
-        }
-    }
-
-    /**
      * Mark the given item as being "trashed", meaning it should be deleted at
      * some point in the future. This is a more gentle operation than simply
      * calling {@link ContentResolver#delete(Uri, String, String[])}, which
@@ -1701,34 +1471,22 @@
             return ContentUris.withAppendedId(getContentUri(volumeName), rowId);
         }
 
-        /**
-         * For use only by the MTP implementation.
-         * @hide
-         */
+        /** {@hide} */
         @UnsupportedAppUsage
-        public static Uri getMtpObjectsUri(String volumeName) {
-            return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("object").build();
+        public static Uri getMtpObjectsUri(@NonNull String volumeName) {
+            return MediaStore.Files.getContentUri(volumeName);
         }
 
-        /**
-         * For use only by the MTP implementation.
-         * @hide
-         */
+        /** {@hide} */
         @UnsupportedAppUsage
-        public static final Uri getMtpObjectsUri(String volumeName,
-                long fileId) {
-            return ContentUris.withAppendedId(getMtpObjectsUri(volumeName), fileId);
+        public static final Uri getMtpObjectsUri(@NonNull String volumeName, long fileId) {
+            return MediaStore.Files.getContentUri(volumeName, fileId);
         }
 
-        /**
-         * Used to implement the MTP GetObjectReferences and SetObjectReferences commands.
-         * @hide
-         */
+        /** {@hide} */
         @UnsupportedAppUsage
-        public static final Uri getMtpReferencesUri(String volumeName,
-                long fileId) {
-            return getMtpObjectsUri(volumeName, fileId).buildUpon().appendPath("references")
-                    .build();
+        public static final Uri getMtpReferencesUri(@NonNull String volumeName, long fileId) {
+            return MediaStore.Files.getContentUri(volumeName, fileId);
         }
 
         /**
@@ -1851,9 +1609,21 @@
         public static final int FULL_SCREEN_KIND = 2;
         public static final int MICRO_KIND = 3;
 
-        public static final Point MINI_SIZE = new Point(512, 384);
-        public static final Point FULL_SCREEN_SIZE = new Point(1024, 786);
-        public static final Point MICRO_SIZE = new Point(96, 96);
+        public static final Size MINI_SIZE = new Size(512, 384);
+        public static final Size FULL_SCREEN_SIZE = new Size(1024, 786);
+        public static final Size MICRO_SIZE = new Size(96, 96);
+
+        public static @NonNull Size getKindSize(int kind) {
+            if (kind == ThumbnailConstants.MICRO_KIND) {
+                return ThumbnailConstants.MICRO_SIZE;
+            } else if (kind == ThumbnailConstants.FULL_SCREEN_KIND) {
+                return ThumbnailConstants.FULL_SCREEN_SIZE;
+            } else if (kind == ThumbnailConstants.MINI_KIND) {
+                return ThumbnailConstants.MINI_SIZE;
+            } else {
+                throw new IllegalArgumentException("Unsupported kind: " + kind);
+            }
+        }
     }
 
     /**
@@ -1957,22 +1727,22 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * @deprecated since this method doesn't have a {@link Context}, we can't
+     *             find the actual {@link StorageVolume} for the given path, so
+     *             only a vague guess is returned. Callers should use
+     *             {@link StorageManager#getStorageVolume(File)} instead.
+     * @hide
+     */
+    @Deprecated
     public static @NonNull String getVolumeName(@NonNull File path) {
-        if (FileUtils.contains(Environment.getStorageDirectory(), path)) {
-            final StorageManager sm = AppGlobals.getInitialApplication()
-                    .getSystemService(StorageManager.class);
-            final StorageVolume sv = sm.getStorageVolume(path);
-            if (sv != null) {
-                if (sv.isPrimary()) {
-                    return VOLUME_EXTERNAL_PRIMARY;
-                } else {
-                    return checkArgumentVolumeName(sv.getNormalizedUuid());
-                }
-            }
-            throw new IllegalStateException("Unknown volume at " + path);
+        // Ideally we'd find the relevant StorageVolume, but we don't have a
+        // Context to obtain it from, so the best we can do is assume
+        if (path.getAbsolutePath()
+                .startsWith(Environment.getStorageDirectory().getAbsolutePath())) {
+            return MediaStore.VOLUME_EXTERNAL;
         } else {
-            return VOLUME_INTERNAL;
+            return MediaStore.VOLUME_INTERNAL;
         }
     }
 
@@ -1985,7 +1755,7 @@
         /**
          * Currently outstanding thumbnail requests that can be cancelled.
          */
-        @GuardedBy("sPending")
+        // @GuardedBy("sPending")
         private static ArrayMap<Uri, CancellationSignal> sPending = new ArrayMap<>();
 
         /**
@@ -1997,16 +1767,7 @@
         @Deprecated
         static @Nullable Bitmap getThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri,
                 int kind, @Nullable BitmapFactory.Options opts) {
-            final Point size;
-            if (kind == ThumbnailConstants.MICRO_KIND) {
-                size = ThumbnailConstants.MICRO_SIZE;
-            } else if (kind == ThumbnailConstants.FULL_SCREEN_KIND) {
-                size = ThumbnailConstants.FULL_SCREEN_SIZE;
-            } else if (kind == ThumbnailConstants.MINI_KIND) {
-                size = ThumbnailConstants.MINI_SIZE;
-            } else {
-                throw new IllegalArgumentException("Unsupported kind: " + kind);
-            }
+            final Size size = ThumbnailConstants.getKindSize(kind);
 
             CancellationSignal signal = null;
             synchronized (sPending) {
@@ -2018,7 +1779,7 @@
             }
 
             try {
-                return cr.loadThumbnail(uri, Point.convert(size), signal);
+                return cr.loadThumbnail(uri, size, signal);
             } catch (IOException e) {
                 Log.w(TAG, "Failed to obtain thumbnail for " + uri, e);
                 return null;
@@ -2215,26 +1976,14 @@
             @Deprecated
             public static final String insertImage(ContentResolver cr, String imagePath,
                     String name, String description) throws FileNotFoundException {
-                final File file = new File(imagePath);
-                final String mimeType = MediaFile.getMimeTypeForFile(imagePath);
-
-                if (TextUtils.isEmpty(name)) name = "Image";
-                final PendingParams params = new PendingParams(
-                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, name, mimeType);
-
-                final Context context = AppGlobals.getInitialApplication();
-                final Uri pendingUri = createPending(context, params);
-                try (PendingSession session = openPending(context, pendingUri)) {
-                    try (InputStream in = new FileInputStream(file);
-                         OutputStream out = session.openOutputStream()) {
-                        FileUtils.copy(in, out);
-                    }
-                    return session.publish().toString();
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to insert image", e);
-                    context.getContentResolver().delete(pendingUri, null, null);
-                    return null;
+                final Bitmap source;
+                try {
+                    source = ImageDecoder
+                            .decodeBitmap(ImageDecoder.createSource(new File(imagePath)));
+                } catch (IOException e) {
+                    throw new FileNotFoundException(e.getMessage());
                 }
+                return insertImage(cr, source, name, description);
             }
 
             /**
@@ -2251,22 +2000,34 @@
              *             control over lifecycle.
              */
             @Deprecated
-            public static final String insertImage(ContentResolver cr, Bitmap source,
-                                                   String title, String description) {
+            public static final String insertImage(ContentResolver cr, Bitmap source, String title,
+                    String description) {
                 if (TextUtils.isEmpty(title)) title = "Image";
-                final PendingParams params = new PendingParams(
-                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, title, "image/jpeg");
 
-                final Context context = AppGlobals.getInitialApplication();
-                final Uri pendingUri = createPending(context, params);
-                try (PendingSession session = openPending(context, pendingUri)) {
-                    try (OutputStream out = session.openOutputStream()) {
+                final long now = System.currentTimeMillis();
+                final ContentValues values = new ContentValues();
+                values.put(MediaColumns.DISPLAY_NAME, title);
+                values.put(MediaColumns.MIME_TYPE, "image/jpeg");
+                values.put(MediaColumns.DATE_ADDED, now / 1000);
+                values.put(MediaColumns.DATE_MODIFIED, now / 1000);
+                values.put(MediaColumns.DATE_EXPIRES, (now + DateUtils.DAY_IN_MILLIS) / 1000);
+                values.put(MediaColumns.IS_PENDING, 1);
+
+                final Uri uri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+                try {
+                    try (OutputStream out = cr.openOutputStream(uri)) {
                         source.compress(Bitmap.CompressFormat.JPEG, 90, out);
                     }
-                    return session.publish().toString();
+
+                    // Everything went well above, publish it!
+                    values.clear();
+                    values.put(MediaColumns.IS_PENDING, 0);
+                    values.putNull(MediaColumns.DATE_EXPIRES);
+                    cr.update(uri, values, null, null);
+                    return uri.toString();
                 } catch (Exception e) {
                     Log.w(TAG, "Failed to insert image", e);
-                    context.getContentResolver().delete(pendingUri, null, null);
+                    cr.delete(uri, null, null);
                     return null;
                 }
             }
@@ -2526,6 +2287,14 @@
             public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND;
 
             /**
+             * Return the typical {@link Size} (in pixels) used internally when
+             * the given thumbnail kind is requested.
+             */
+            public static @NonNull Size getKindSize(int kind) {
+                return ThumbnailConstants.getKindSize(kind);
+            }
+
+            /**
              * The blob raw data of thumbnail
              *
              * @deprecated this column never existed internally, and could never
@@ -3780,6 +3549,14 @@
             public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND;
 
             /**
+             * Return the typical {@link Size} (in pixels) used internally when
+             * the given thumbnail kind is requested.
+             */
+            public static @NonNull Size getKindSize(int kind) {
+                return ThumbnailConstants.getKindSize(kind);
+            }
+
+            /**
              * The width of the thumbnal
              */
             @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
@@ -3811,54 +3588,44 @@
      */
     public static @NonNull Set<String> getExternalVolumeNames(@NonNull Context context) {
         final StorageManager sm = context.getSystemService(StorageManager.class);
-        final Set<String> volumeNames = new ArraySet<>();
-        for (VolumeInfo vi : sm.getVolumes()) {
-            if (vi.isVisibleForUser(UserHandle.myUserId()) && vi.isMountedReadable()) {
-                if (vi.isPrimary()) {
-                    volumeNames.add(VOLUME_EXTERNAL_PRIMARY);
-                } else {
-                    volumeNames.add(vi.getNormalizedFsUuid());
+        final Set<String> res = new ArraySet<>();
+        for (StorageVolume sv : sm.getStorageVolumes()) {
+            switch (sv.getState()) {
+                case Environment.MEDIA_MOUNTED:
+                case Environment.MEDIA_MOUNTED_READ_ONLY: {
+                    final String volumeName = sv.getMediaStoreVolumeName();
+                    if (volumeName != null) {
+                        res.add(volumeName);
+                    }
+                    break;
                 }
             }
         }
-        return volumeNames;
+        return res;
     }
 
     /**
-     * Return list of all specific volume names that have recently been part of
+     * Return list of all recent volume names that have been part of
      * {@link #VOLUME_EXTERNAL}.
      * <p>
-     * This includes both currently mounted volumes <em>and</em> recently
-     * mounted (but currently unmounted) volumes. Any indexed metadata for these
-     * volumes is preserved to optimize the speed of remounting at a later time.
-     *
-     * @hide
+     * These volume names are not currently mounted, but they're likely to
+     * reappear in the future, so apps are encouraged to preserve any indexed
+     * metadata related to these volumes to optimize user experiences.
+     * <p>
+     * Each specific volume name can be passed to APIs like
+     * {@link MediaStore.Images.Media#getContentUri(String)} to interact with
+     * media on that storage device.
      */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
     public static @NonNull Set<String> getRecentExternalVolumeNames(@NonNull Context context) {
         final StorageManager sm = context.getSystemService(StorageManager.class);
-
-        // We always have primary storage
-        final Set<String> volumeNames = new ArraySet<>();
-        volumeNames.add(VOLUME_EXTERNAL_PRIMARY);
-
-        final long lastWeek = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
-        for (VolumeRecord rec : sm.getVolumeRecords()) {
-            // Skip volumes without valid UUIDs
-            if (TextUtils.isEmpty(rec.fsUuid)) continue;
-
-            final VolumeInfo vi = sm.findVolumeByUuid(rec.fsUuid);
-            if (vi != null && vi.isVisibleForUser(UserHandle.myUserId())
-                    && vi.isMountedReadable()) {
-                // We're mounted right now
-                volumeNames.add(rec.getNormalizedFsUuid());
-            } else if (rec.lastSeenMillis > 0 && rec.lastSeenMillis < lastWeek) {
-                // We're not mounted right now, but we've been seen recently
-                volumeNames.add(rec.getNormalizedFsUuid());
+        final Set<String> res = new ArraySet<>();
+        for (StorageVolume sv : sm.getRecentStorageVolumes()) {
+            final String volumeName = sv.getMediaStoreVolumeName();
+            if (volumeName != null) {
+                res.add(volumeName);
             }
         }
-        return volumeNames;
+        return res;
     }
 
     /**
@@ -3911,97 +3678,6 @@
     }
 
     /**
-     * Return path where the given specific volume is mounted. Not valid for
-     * {@link #VOLUME_INTERNAL} or {@link #VOLUME_EXTERNAL}, since those are
-     * broad collections that cover many paths.
-     *
-     * @hide
-     */
-    @TestApi
-    public static @NonNull File getVolumePath(@NonNull String volumeName)
-            throws FileNotFoundException {
-        final StorageManager sm = AppGlobals.getInitialApplication()
-                .getSystemService(StorageManager.class);
-        return getVolumePath(sm.getVolumes(), volumeName);
-    }
-
-    /** {@hide} */
-    public static @NonNull File getVolumePath(@NonNull List<VolumeInfo> volumes,
-            @NonNull String volumeName) throws FileNotFoundException {
-        if (TextUtils.isEmpty(volumeName)) {
-            throw new IllegalArgumentException();
-        }
-
-        switch (volumeName) {
-            case VOLUME_INTERNAL:
-            case VOLUME_EXTERNAL:
-                throw new FileNotFoundException(volumeName + " has no associated path");
-        }
-
-        final boolean wantPrimary = VOLUME_EXTERNAL_PRIMARY.equals(volumeName);
-        for (VolumeInfo volume : volumes) {
-            final boolean matchPrimary = wantPrimary
-                    && volume.isPrimary();
-            final boolean matchSecondary = !wantPrimary
-                    && Objects.equals(volume.getNormalizedFsUuid(), volumeName);
-            if (matchPrimary || matchSecondary) {
-                final File path = volume.getPathForUser(UserHandle.myUserId());
-                if (path != null) {
-                    return path;
-                }
-            }
-        }
-        throw new FileNotFoundException("Failed to find path for " + volumeName);
-    }
-
-    /**
-     * Return paths that should be scanned for the given volume.
-     *
-     * @hide
-     */
-    @TestApi
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
-    public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName)
-            throws FileNotFoundException {
-        if (TextUtils.isEmpty(volumeName)) {
-            throw new IllegalArgumentException();
-        }
-
-        final Context context = AppGlobals.getInitialApplication();
-        final UserManager um = context.getSystemService(UserManager.class);
-
-        final ArrayList<File> res = new ArrayList<>();
-        if (VOLUME_INTERNAL.equals(volumeName)) {
-            addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
-            addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
-            addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
-        } else if (VOLUME_EXTERNAL.equals(volumeName)) {
-            for (String exactVolume : getExternalVolumeNames(context)) {
-                addCanonicalFile(res, getVolumePath(exactVolume));
-            }
-            if (um.isDemoUser()) {
-                addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
-            }
-        } else {
-            addCanonicalFile(res, getVolumePath(volumeName));
-            if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName) && um.isDemoUser()) {
-                addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
-            }
-        }
-        return res;
-    }
-
-    private static void addCanonicalFile(List<File> list, File file) {
-        try {
-            list.add(file.getCanonicalFile());
-        } catch (IOException e) {
-            Log.w(TAG, "Failed to resolve " + file + ": " + e);
-            list.add(file);
-        }
-    }
-
-    /**
      * Uri for querying the state of the media scanner.
      */
     public static Uri getMediaScannerUri() {
@@ -4084,10 +3760,10 @@
 
         try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
             final Bundle in = new Bundle();
-            in.putParcelable(DocumentsContract.EXTRA_URI, mediaUri);
-            in.putParcelableList(DocumentsContract.EXTRA_URI_PERMISSIONS, uriPermissions);
+            in.putParcelable(EXTRA_URI, mediaUri);
+            in.putParcelableArrayList(EXTRA_URI_PERMISSIONS, new ArrayList<>(uriPermissions));
             final Bundle out = client.call(GET_DOCUMENT_URI_CALL, null, in);
-            return out.getParcelable(DocumentsContract.EXTRA_URI);
+            return out.getParcelable(EXTRA_URI);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -4114,134 +3790,43 @@
 
         try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
             final Bundle in = new Bundle();
-            in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
-            in.putParcelableList(DocumentsContract.EXTRA_URI_PERMISSIONS, uriPermissions);
+            in.putParcelable(EXTRA_URI, documentUri);
+            in.putParcelableArrayList(EXTRA_URI_PERMISSIONS, new ArrayList<>(uriPermissions));
             final Bundle out = client.call(GET_MEDIA_URI_CALL, null, in);
-            return out.getParcelable(DocumentsContract.EXTRA_URI);
+            return out.getParcelable(EXTRA_URI);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
+    /** @hide */
+    @TestApi
+    public static void waitForIdle(@NonNull ContentResolver resolver) {
+        resolver.call(AUTHORITY, WAIT_FOR_IDLE_CALL, null, null);
+    }
+
     /**
-     * Calculate size of media contributed by given package under the calling
-     * user. The meaning of "contributed" means it won't automatically be
-     * deleted when the app is uninstalled.
+     * Perform a blocking scan of the given {@link File}, returning the
+     * {@link Uri} of the scanned file.
      *
      * @hide
      */
+    @SystemApi
     @TestApi
-    @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
-    public static @BytesLong long getContributedMediaSize(Context context, String packageName,
-            UserHandle user) throws IOException {
-        final UserManager um = context.getSystemService(UserManager.class);
-        if (um.isUserUnlocked(user) && um.isUserRunning(user)) {
-            try {
-                final ContentResolver resolver = context
-                        .createPackageContextAsUser(packageName, 0, user).getContentResolver();
-                final Bundle in = new Bundle();
-                in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
-                final Bundle out = resolver.call(AUTHORITY, GET_CONTRIBUTED_MEDIA_CALL, null, in);
-                return out.getLong(Intent.EXTRA_INDEX);
-            } catch (Exception e) {
-                throw new IOException(e);
-            }
-        } else {
-            throw new IOException("User " + user + " must be unlocked and running");
-        }
+    @SuppressLint("StreamFiles")
+    public static @NonNull Uri scanFile(@NonNull ContentResolver resolver, @NonNull File file) {
+        final Bundle out = resolver.call(AUTHORITY, SCAN_FILE_CALL, file.getAbsolutePath(), null);
+        return out.getParcelable(Intent.EXTRA_STREAM);
     }
 
     /**
-     * Delete all media contributed by given package under the calling user. The
-     * meaning of "contributed" means it won't automatically be deleted when the
-     * app is uninstalled.
+     * Perform a blocking scan of the given storage volume.
      *
      * @hide
      */
+    @SystemApi
     @TestApi
-    @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
-    public static void deleteContributedMedia(Context context, String packageName,
-            UserHandle user) throws IOException {
-        final UserManager um = context.getSystemService(UserManager.class);
-        if (um.isUserUnlocked(user) && um.isUserRunning(user)) {
-            try {
-                final ContentResolver resolver = context
-                        .createPackageContextAsUser(packageName, 0, user).getContentResolver();
-                final Bundle in = new Bundle();
-                in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
-                resolver.call(AUTHORITY, DELETE_CONTRIBUTED_MEDIA_CALL, null, in);
-            } catch (Exception e) {
-                throw new IOException(e);
-            }
-        } else {
-            throw new IOException("User " + user + " must be unlocked and running");
-        }
-    }
-
-    /** @hide */
-    @TestApi
-    public static void waitForIdle(Context context) {
-        final ContentResolver resolver = context.getContentResolver();
-        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
-            client.call(WAIT_FOR_IDLE_CALL, null, null);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    /** @hide */
-    public static void suicide(Context context) {
-        final ContentResolver resolver = context.getContentResolver();
-        try (ContentProviderClient client = resolver
-                .acquireUnstableContentProviderClient(AUTHORITY)) {
-            client.call(SUICIDE_CALL, null, null);
-        } catch (Exception ignored) {
-        }
-    }
-
-    /** @hide */
-    @TestApi
-    public static Uri scanFile(Context context, File file) {
-        return scan(context, SCAN_FILE_CALL, file, false);
-    }
-
-    /** @hide */
-    @TestApi
-    public static Uri scanFileFromShell(Context context, File file) {
-        return scan(context, SCAN_FILE_CALL, file, true);
-    }
-
-    /** @hide */
-    @TestApi
-    public static void scanVolume(Context context, File file) {
-        scan(context, SCAN_VOLUME_CALL, file, false);
-    }
-
-    /** @hide */
-    public static Uri scanFile(ContentProviderClient client, File file) {
-        return scan(client, SCAN_FILE_CALL, file, false);
-    }
-
-    /** @hide */
-    private static Uri scan(Context context, String method, File file,
-            boolean originatedFromShell) {
-        final ContentResolver resolver = context.getContentResolver();
-        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
-            return scan(client, method, file, originatedFromShell);
-        }
-    }
-
-    /** @hide */
-    private static Uri scan(ContentProviderClient client, String method, File file,
-            boolean originatedFromShell) {
-        try {
-            final Bundle in = new Bundle();
-            in.putParcelable(Intent.EXTRA_STREAM, Uri.fromFile(file));
-            in.putBoolean(EXTRA_ORIGINATED_FROM_SHELL, originatedFromShell);
-            final Bundle out = client.call(method, null, in);
-            return out.getParcelable(Intent.EXTRA_STREAM);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
+    public static void scanVolume(@NonNull ContentResolver resolver, @NonNull String volumeName) {
+        resolver.call(AUTHORITY, SCAN_VOLUME_CALL, volumeName, null);
     }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e73a74f..f4e2329 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13653,13 +13653,6 @@
         public static final String KERNEL_CPU_THREAD_READER = "kernel_cpu_thread_reader";
 
         /**
-         * Default user id to boot into. They map to user ids, for example, 10, 11, 12.
-         *
-         * @hide
-         */
-        public static final String DEFAULT_USER_ID_TO_BOOT_INTO = "default_boot_into_user_id";
-
-        /**
          * Persistent user id that is last logged in to.
          *
          * They map to user ids, for example, 10, 11, 12.
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index e53ebad..72e9ad0 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -23,6 +23,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.View;
+import android.view.inputmethod.InlineSuggestionsRequest;
 
 import com.android.internal.util.DataClass;
 import com.android.internal.util.Preconditions;
@@ -116,20 +117,34 @@
      */
     private final @RequestFlags int mFlags;
 
+    /**
+     * Gets the {@link android.view.inputmethod.InlineSuggestionsRequest} associated
+     * with this request.
+     *
+     * TODO(b/137800469): Add more doc describing how to handle the inline suggestions request.
+     *
+     * @return the suggestionspec
+     */
+    private final @Nullable InlineSuggestionsRequest mInlineSuggestionsRequest;
+
     private void onConstructed() {
         Preconditions.checkCollectionElementsNotNull(mFillContexts, "contexts");
     }
 
 
 
-    // Code below generated by codegen v1.0.0.
+    // Code below generated by codegen v1.0.14.
     //
     // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/FillRequest.java
     //
-    // CHECKSTYLE:OFF Generated code
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
 
     /** @hide */
     @IntDef(flag = true, prefix = "FLAG_", value = {
@@ -184,6 +199,11 @@
      *
      *   @return any combination of {@link #FLAG_MANUAL_REQUEST} and
      *           {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+     * @param inlineSuggestionsRequest
+     *   Gets the {@link android.view.inputmethod.InlineSuggestionsRequest} associated
+     *   with this request.
+     *
+     *   TODO(b/137800469): Add more doc describing how to handle the inline suggestions request.
      * @hide
      */
     @DataClass.Generated.Member
@@ -191,7 +211,8 @@
             int id,
             @NonNull List<FillContext> fillContexts,
             @Nullable Bundle clientState,
-            @RequestFlags int flags) {
+            @RequestFlags int flags,
+            @Nullable InlineSuggestionsRequest inlineSuggestionsRequest) {
         this.mId = id;
         this.mFillContexts = fillContexts;
         com.android.internal.util.AnnotationValidations.validate(
@@ -203,6 +224,7 @@
                 mFlags,
                 FLAG_MANUAL_REQUEST
                         | FLAG_COMPATIBILITY_MODE_REQUEST);
+        this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
 
         onConstructed();
     }
@@ -256,6 +278,19 @@
         return mFlags;
     }
 
+    /**
+     * Gets the {@link android.view.inputmethod.InlineSuggestionsRequest} associated
+     * with this request.
+     *
+     * TODO(b/137800469): Add more doc describing how to handle the inline suggestions request.
+     *
+     * @return the suggestionspec
+     */
+    @DataClass.Generated.Member
+    public @Nullable InlineSuggestionsRequest getInlineSuggestionsRequest() {
+        return mInlineSuggestionsRequest;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -266,29 +301,63 @@
                 "id = " + mId + ", " +
                 "fillContexts = " + mFillContexts + ", " +
                 "clientState = " + mClientState + ", " +
-                "flags = " + requestFlagsToString(mFlags) +
+                "flags = " + requestFlagsToString(mFlags) + ", " +
+                "inlineSuggestionsRequest = " + mInlineSuggestionsRequest +
         " }";
     }
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
         if (mClientState != null) flg |= 0x4;
+        if (mInlineSuggestionsRequest != null) flg |= 0x10;
         dest.writeByte(flg);
         dest.writeInt(mId);
         dest.writeParcelableList(mFillContexts, flags);
         if (mClientState != null) dest.writeBundle(mClientState);
         dest.writeInt(mFlags);
+        if (mInlineSuggestionsRequest != null) dest.writeTypedObject(mInlineSuggestionsRequest, flags);
     }
 
     @Override
     @DataClass.Generated.Member
     public int describeContents() { return 0; }
 
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ FillRequest(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int id = in.readInt();
+        List<FillContext> fillContexts = new ArrayList<>();
+        in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
+        Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
+        int flags = in.readInt();
+        InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x10) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
+
+        this.mId = id;
+        this.mFillContexts = fillContexts;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFillContexts);
+        this.mClientState = clientState;
+        this.mFlags = flags;
+
+        Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST);
+        this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
+
+        onConstructed();
+    }
+
     @DataClass.Generated.Member
     public static final @NonNull Parcelable.Creator<FillRequest> CREATOR
             = new Parcelable.Creator<FillRequest>() {
@@ -298,31 +367,21 @@
         }
 
         @Override
-        @SuppressWarnings({"unchecked", "RedundantCast"})
-        public FillRequest createFromParcel(Parcel in) {
-            // You can override field unparcelling by defining methods like:
-            // static FieldType unparcelFieldName(Parcel in) { ... }
-
-            byte flg = in.readByte();
-            int id = in.readInt();
-            List<FillContext> fillContexts = new ArrayList<>();
-            in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
-            Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
-            int flags = in.readInt();
-            return new FillRequest(
-                    id,
-                    fillContexts,
-                    clientState,
-                    flags);
+        public FillRequest createFromParcel(@NonNull Parcel in) {
+            return new FillRequest(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1565152134349L,
-            codegenVersion = "1.0.0",
+            time = 1575928271155L,
+            codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
-            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index c99fe61..02a6390 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -25,6 +25,7 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.app.Activity;
+import android.app.slice.Slice;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
@@ -86,6 +87,7 @@
     private int mRequestId;
     private final @Nullable UserData mUserData;
     private final @Nullable int[] mCancelIds;
+    private final @Nullable ParceledListSlice<Slice> mInlineSuggestionSlices;
 
     private FillResponse(@NonNull Builder builder) {
         mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -103,6 +105,8 @@
         mRequestId = INVALID_REQUEST_ID;
         mUserData = builder.mUserData;
         mCancelIds = builder.mCancelIds;
+        mInlineSuggestionSlices = (builder.mInlineSuggestionSlices != null)
+                ? new ParceledListSlice<>(builder.mInlineSuggestionSlices) : null;
     }
 
     /** @hide */
@@ -195,6 +199,11 @@
         return mCancelIds;
     }
 
+    /** @hide */
+    public List<Slice> getInlineSuggestionSlices() {
+        return (mInlineSuggestionSlices != null) ? mInlineSuggestionSlices.getList() : null;
+    }
+
     /**
      * Builder for {@link FillResponse} objects. You must to provide at least
      * one dataset or set an authentication intent with a presentation view.
@@ -215,6 +224,7 @@
         private boolean mDestroyed;
         private UserData mUserData;
         private int[] mCancelIds;
+        private ArrayList<Slice> mInlineSuggestionSlices;
 
         /**
          * Triggers a custom UI before before autofilling the screen with any data set in this
@@ -570,6 +580,20 @@
         }
 
         /**
+         * TODO(b/137800469): add javadoc
+         */
+        @NonNull
+        public Builder addInlineSuggestionSlice(@NonNull Slice inlineSuggestionSlice) {
+            throwIfDestroyed();
+            throwIfAuthenticationCalled();
+            if (mInlineSuggestionSlices == null) {
+                mInlineSuggestionSlices = new ArrayList<>();
+            }
+            mInlineSuggestionSlices.add(inlineSuggestionSlice);
+            return this;
+        }
+
+        /**
          * Builds a new {@link FillResponse} instance.
          *
          * @throws IllegalStateException if any of the following conditions occur:
@@ -670,7 +694,9 @@
         if (mCancelIds != null) {
             builder.append(", mCancelIds=").append(mCancelIds.length);
         }
-
+        if (mInlineSuggestionSlices != null) {
+            builder.append(", inlinedSuggestions=").append(mInlineSuggestionSlices.getList());
+        }
         return builder.append("]").toString();
     }
 
@@ -699,7 +725,7 @@
         parcel.writeParcelableArray(mFieldClassificationIds, flags);
         parcel.writeInt(mFlags);
         parcel.writeIntArray(mCancelIds);
-
+        parcel.writeParcelable(mInlineSuggestionSlices, flags);
         parcel.writeInt(mRequestId);
     }
 
@@ -755,6 +781,16 @@
             final int[] cancelIds = parcel.createIntArray();
             builder.setCancelTargetIds(cancelIds);
 
+            final ParceledListSlice<Slice> parceledInlineSuggestionSlices =
+                    parcel.readParcelable(null);
+            if (parceledInlineSuggestionSlices != null) {
+                final List<Slice> inlineSuggestionSlices = parceledInlineSuggestionSlices.getList();
+                final int size = inlineSuggestionSlices.size();
+                for (int i = 0; i < size; i++) {
+                    builder.addInlineSuggestionSlice(inlineSuggestionSlices.get(i));
+                }
+            }
+
             final FillResponse response = builder.build();
             response.setRequestId(parcel.readInt());
 
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 7ea4f30..cdfd397 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -68,22 +68,26 @@
     private final InsetsController mController;
     private final WindowInsetsAnimationCallback.InsetsAnimation mAnimation;
     private final Rect mFrame;
+    private final boolean mFade;
     private Insets mCurrentInsets;
     private Insets mPendingInsets;
     private float mPendingFraction;
     private boolean mFinished;
     private boolean mCancelled;
     private boolean mShownOnFinish;
+    private float mCurrentAlpha;
+    private float mPendingAlpha;
 
     @VisibleForTesting
     public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
             InsetsState state, WindowInsetsAnimationControlListener listener,
             @InsetsType int types,
             Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier,
-            InsetsController controller, long durationMs) {
+            InsetsController controller, long durationMs, boolean fade) {
         mConsumers = consumers;
         mListener = listener;
         mTypes = types;
+        mFade = fade;
         mTransactionApplierSupplier = transactionApplierSupplier;
         mController = controller;
         mInitialInsetsState = new InsetsState(state, true /* copySources */);
@@ -100,6 +104,7 @@
 
         mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes,
                 InsetsController.INTERPOLATOR, durationMs);
+        mAnimation.setAlpha(getCurrentAlpha());
         mController.dispatchAnimationStarted(mAnimation,
                 new AnimationBounds(mHiddenInsets, mShownInsets));
     }
@@ -120,6 +125,11 @@
     }
 
     @Override
+    public float getCurrentAlpha() {
+        return mCurrentAlpha;
+    }
+
+    @Override
     @InsetsType public int getTypes() {
         return mTypes;
     }
@@ -136,6 +146,7 @@
         }
         mPendingFraction = sanitize(fraction);
         mPendingInsets = sanitize(insets);
+        mPendingAlpha = 1 - sanitize(alpha);
         mController.scheduleApplyChangeInsets();
     }
 
@@ -148,17 +159,24 @@
             return false;
         }
         final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
+        final Float alphaOffset = 1 - mPendingAlpha;
         ArrayList<SurfaceParams> params = new ArrayList<>();
-        updateLeashesForSide(ISIDE_LEFT, offset.left, mPendingInsets.left, params, state);
-        updateLeashesForSide(ISIDE_TOP, offset.top, mPendingInsets.top, params, state);
-        updateLeashesForSide(ISIDE_RIGHT, offset.right, mPendingInsets.right, params, state);
-        updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mPendingInsets.bottom, params, state);
-        updateLeashesForSide(ISIDE_FLOATING, 0 /* offset */, 0 /* inset */, params, state);
+        updateLeashesForSide(ISIDE_LEFT, offset.left, mShownInsets.left, mPendingInsets.left,
+                params, state, alphaOffset);
+        updateLeashesForSide(ISIDE_TOP, offset.top, mShownInsets.top, mPendingInsets.top, params,
+                state, alphaOffset);
+        updateLeashesForSide(ISIDE_RIGHT, offset.right, mShownInsets.right, mPendingInsets.right,
+                params, state, alphaOffset);
+        updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom,
+                mPendingInsets.bottom, params, state, alphaOffset);
+        updateLeashesForSide(ISIDE_FLOATING, 0 /* offset */, 0 /* inset */, 0 /* maxInset */,
+                params, state, alphaOffset);
 
         SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
         applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
         mCurrentInsets = mPendingInsets;
         mAnimation.setFraction(mPendingFraction);
+        mCurrentAlpha = 1 - alphaOffset;
         if (mFinished) {
             mController.notifyFinished(this, mShownOnFinish);
         }
@@ -233,7 +251,7 @@
     }
 
     private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset,
-            ArrayList<SurfaceParams> surfaceParams, InsetsState state) {
+            int maxInset, ArrayList<SurfaceParams> surfaceParams, InsetsState state, Float alpha) {
         ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side);
         if (items == null) {
             return;
@@ -257,7 +275,9 @@
 
             // If the system is controlling the insets source, the leash can be null.
             if (leash != null) {
-                surfaceParams.add(new SurfaceParams(leash, 1f /* alpha */, mTmpMatrix,
+                // TODO: use a better interpolation for fade.
+                alpha = mFade ? ((float) maxInset / inset * 0.3f + 0.7f) : alpha;
+                surfaceParams.add(new SurfaceParams(leash, alpha, mTmpMatrix,
                         null /* windowCrop */, 0 /* layer */, 0f /* cornerRadius*/,
                         side == ISIDE_FLOATING ? consumer.isVisible() : inset != 0 /* visible */));
             }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8870311..5563d62 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -361,12 +361,12 @@
             listener.onCancelled();
             return;
         }
-        controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs);
+        controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, false /* fade */);
     }
 
     private void controlAnimationUnchecked(@InsetsType int types,
             WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
-            long durationMs) {
+            long durationMs, boolean fade) {
         if (types == 0) {
             // nothing to animate.
             return;
@@ -397,7 +397,7 @@
 
         final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
                 frame, mState, listener, typesReady,
-                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this, durationMs);
+                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this, durationMs, fade);
         mAnimationControls.add(controller);
     }
 
@@ -588,7 +588,8 @@
         // Show/hide animations always need to be relative to the display frame, in order that shown
         // and hidden state insets are correct.
         controlAnimationUnchecked(
-                types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs());
+                types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
+                true /* fade */);
     }
 
     private void hideDirectly(@InsetsType int types) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2d0b954..44f211a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16185,7 +16185,7 @@
      * by the most recent call to {@link #measure(int, int)}.  This result is a bit mask
      * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
      * This should be used during measurement and layout calculations only. Use
-     * {@link #getHeight()} to see how wide a view is after layout.
+     * {@link #getHeight()} to see how high a view is after layout.
      *
      * @return The measured height of this view as a bit mask.
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e3f0da1..df6f3b8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -211,13 +211,6 @@
      * @see #USE_NEW_INSETS_PROPERTY
      * @hide
      */
-    public static int sNewInsetsMode =
-            SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, 0);
-
-    /**
-     * @see #USE_NEW_INSETS_PROPERTY
-     * @hide
-     */
     public static final int NEW_INSETS_MODE_NONE = 0;
 
     /**
@@ -233,6 +226,13 @@
     public static final int NEW_INSETS_MODE_FULL = 2;
 
     /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static int sNewInsetsMode =
+            SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, NEW_INSETS_MODE_IME);
+
+    /**
      * Set this system property to true to force the view hierarchy to render
      * at 60 Hz. This can be used to measure the potential framerate.
      */
diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java
index 8ae8520..5e71f27 100644
--- a/core/java/android/view/WindowInsetsAnimationCallback.java
+++ b/core/java/android/view/WindowInsetsAnimationCallback.java
@@ -89,6 +89,7 @@
         private float mFraction;
         @Nullable private final Interpolator mInterpolator;
         private long mDurationMs;
+        private float mAlpha;
 
         public InsetsAnimation(
                 @InsetsType int typeMask, @Nullable Interpolator interpolator, long durationMs) {
@@ -177,6 +178,18 @@
         public void setDuration(long durationMs) {
             mDurationMs = durationMs;
         }
+
+        /**
+         * @return alpha of {@link WindowInsets.Type.InsetsType}.
+         */
+        @FloatRange(from = 0f, to = 1f)
+        public float getAlpha() {
+            return mAlpha;
+        }
+
+        void setAlpha(@FloatRange(from = 0f, to = 1f) float alpha) {
+            mAlpha = alpha;
+        }
     }
 
     /**
diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java
index 5149103..2bf0d27 100644
--- a/core/java/android/view/WindowInsetsAnimationController.java
+++ b/core/java/android/view/WindowInsetsAnimationController.java
@@ -93,6 +93,12 @@
     float getCurrentFraction();
 
     /**
+     * Current alpha value of the window.
+     * @return float value between 0 and 1.
+     */
+    float getCurrentAlpha();
+
+    /**
      * @return The {@link InsetsType}s this object is currently controlling.
      */
     @InsetsType int getTypes();
diff --git a/core/java/android/view/inline/InlineContentView.java b/core/java/android/view/inline/InlineContentView.java
index 4bc2176..b143fad 100644
--- a/core/java/android/view/inline/InlineContentView.java
+++ b/core/java/android/view/inline/InlineContentView.java
@@ -50,7 +50,10 @@
 
             @Override
             public void surfaceDestroyed(SurfaceHolder holder) {
-                // TODO(b/137800469): implement this.
+                new SurfaceControl.Transaction()
+                        .setVisibility(surfaceControl, false)
+                        .reparent(surfaceControl, null)
+                        .apply();
             }
         });
     }
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index 25e34d3..c10144e 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -271,7 +271,7 @@
     };
 
     @DataClass.Generated(
-            time = 1574446220398L,
+            time = 1575933636929L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
             inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\npublic  void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.view.View>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 112653a..1e5a3b0 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -21,11 +21,16 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.util.Log;
+import android.view.autofill.AutofillId;
 
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
 
 /**
  * The InputMethod interface represents an input method which can generate key
@@ -104,6 +109,20 @@
     }
 
     /**
+     * Called to notify the IME that Autofill Frameworks requested an inline suggestions request.
+     *
+     * @hide
+     */
+    default void onCreateInlineSuggestionsRequest(ComponentName componentName,
+            AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+        try {
+            cb.onInlineSuggestionsUnsupported();
+        } catch (RemoteException e) {
+            Log.w("InputMethod", "RemoteException calling onInlineSuggestionsUnsupported: " + e);
+        }
+    }
+
+    /**
      * Called first thing after an input method is created, this supplies a
      * unique token for the session it has with the system service.  It is
      * needed to identify itself with the service to validate its operations.
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index f5708a5c..dec9ae7 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -259,7 +259,7 @@
                 throw new IllegalStateException("Failed to touch " + file + ": " + e);
             }
         }
-        MediaStore.scanFile(getContext(), file);
+        MediaStore.scanFile(getContext().getContentResolver(), file);
 
         return childId;
     }
@@ -316,10 +316,10 @@
 
     private void moveInMediaStore(@Nullable File oldVisibleFile, @Nullable File newVisibleFile) {
         if (oldVisibleFile != null) {
-            MediaStore.scanFile(getContext(), oldVisibleFile);
+            MediaStore.scanFile(getContext().getContentResolver(), oldVisibleFile);
         }
         if (newVisibleFile != null) {
-            MediaStore.scanFile(getContext(), newVisibleFile);
+            MediaStore.scanFile(getContext().getContentResolver(), newVisibleFile);
         }
     }
 
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 2ee902a..58aaa80 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -16,13 +16,16 @@
 
 package com.android.internal.view;
 
+import android.content.ComponentName;
 import android.os.IBinder;
 import android.os.ResultReceiver;
+import android.view.autofill.AutofillId;
 import android.view.InputChannel;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputMethodSubtype;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.IInputSessionCallback;
@@ -35,6 +38,9 @@
 oneway interface IInputMethod {
     void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
+    void onCreateInlineSuggestionsRequest(in ComponentName componentName, in AutofillId autofillId,
+            in IInlineSuggestionsRequestCallback cb);
+
     void bindInput(in InputBinding binding);
 
     void unbindInput();
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f7a994f..3cde887 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -129,6 +129,7 @@
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
 extern int register_android_database_SQLiteGlobal(JNIEnv* env);
 extern int register_android_database_SQLiteDebug(JNIEnv* env);
+extern int register_android_media_MediaMetrics(JNIEnv *env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_GraphicsEnvironment(JNIEnv* env);
 extern int register_android_os_HidlSupport(JNIEnv* env);
@@ -1520,6 +1521,7 @@
     REG_JNI(register_android_media_AudioProductStrategies),
     REG_JNI(register_android_media_AudioVolumeGroups),
     REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
+    REG_JNI(register_android_media_MediaMetrics),
     REG_JNI(register_android_media_MicrophoneInfo),
     REG_JNI(register_android_media_RemoteDisplay),
     REG_JNI(register_android_media_ToneGenerator),
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 0c2129f..e3e07de 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2472,4 +2472,9 @@
     // CATEGORY: SETTINGS
     // OS: R
     SETTINGS_BUGREPORT_HANDLER = 1808;
+
+    // Panel for adding Wi-Fi networks
+    // CATEGORY: SETTINGS
+    // OS: R
+    PANEL_ADD_WIFI_NETWORKS = 1809;
 }
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index 9c725b9..4d7846d 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -45,7 +45,8 @@
         android:ellipsize="end"
         android:fontFamily="@android:string/config_headlineFontFamily"
         android:textColor="?android:attr/textColorPrimary"
-        android:maxLines="2"/>
+        android:maxLines="2"
+        android:focusable="true"/>
 
     <LinearLayout
         android:id="@+id/copy_button"
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index cce38f6..68d95cd 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -116,7 +116,8 @@
         consumers.put(ITYPE_NAVIGATION_BAR, navConsumer);
         mController = new InsetsAnimationControlImpl(consumers,
                 new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
-                () -> mMockTransactionApplier, mMockController, 10 /* durationMs */);
+                () -> mMockTransactionApplier, mMockController, 10 /* durationMs */,
+                false /* fade */);
     }
 
     @Test
@@ -133,6 +134,7 @@
                 0f /* fraction */);
         mController.applyChangeInsets(new InsetsState());
         assertEquals(Insets.of(0, 30, 40, 0), mController.getCurrentInsets());
+        assertEquals(1f, mController.getCurrentAlpha(), 1f - mController.getCurrentAlpha());
 
         ArgumentCaptor<SurfaceParams> captor = ArgumentCaptor.forClass(SurfaceParams.class);
         verify(mMockTransactionApplier).scheduleApply(captor.capture());
@@ -147,6 +149,23 @@
     }
 
     @Test
+    public void testChangeAlphaNoInsets() {
+        Insets initialInsets = mController.getCurrentInsets();
+        mController.setInsetsAndAlpha(null, 0.5f, 0f /* fraction*/);
+        mController.applyChangeInsets(new InsetsState());
+        assertEquals(0.5f, mController.getCurrentAlpha(), 0.5f - mController.getCurrentAlpha());
+        assertEquals(initialInsets, mController.getCurrentInsets());
+    }
+
+    @Test
+    public void testChangeInsetsAndAlpha() {
+        mController.setInsetsAndAlpha(Insets.of(0, 30, 40, 0), 0.5f, 1f);
+        mController.applyChangeInsets(new InsetsState());
+        assertEquals(0.5f, mController.getCurrentAlpha(), 0.5f - mController.getCurrentAlpha());
+        assertEquals(Insets.of(0, 30, 40, 0), mController.getCurrentInsets());
+    }
+
+    @Test
     public void testFinishing() {
         when(mMockController.getState()).thenReturn(mInsetsState);
         mController.finish(true /* shown */);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e07edd4..624fc50 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -240,6 +240,13 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.tethering">
+        <permission name="android.permission.MANAGE_USB"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+        <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.server.telecom">
         <permission name="android.permission.BIND_CONNECTION_SERVICE"/>
         <permission name="android.permission.BIND_INCALL_SERVICE"/>
@@ -343,6 +350,8 @@
         <permission name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
         <!-- Permission required for Telecom car mode CTS tests. -->
         <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+        <!-- Permission required for Tethering CTS tests. -->
+        <permission name="android.permission.TETHER_PRIVILEGED"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/media/java/android/media/MediaMetrics.java b/media/java/android/media/MediaMetrics.java
new file mode 100644
index 0000000..88a8295
--- /dev/null
+++ b/media/java/android/media/MediaMetrics.java
@@ -0,0 +1,634 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Bundle;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * MediaMetrics is the Java interface to the MediaMetrics service.
+ *
+ * This is used to collect media statistics by the framework.
+ * It is not intended for direct application use.
+ *
+ * @hide
+ */
+public class MediaMetrics {
+    public static final String TAG = "MediaMetrics";
+
+    /**
+     * The TYPE constants below should match those in native MediaMetricsItem.h
+     */
+    private static final int TYPE_NONE = 0;
+    private static final int TYPE_INT32 = 1;     // Java integer
+    private static final int TYPE_INT64 = 2;     // Java long
+    private static final int TYPE_DOUBLE = 3;    // Java double
+    private static final int TYPE_CSTRING = 4;   // Java string
+    private static final int TYPE_RATE = 5;      // Two longs, ignored in Java
+
+    // The charset used for encoding Strings to bytes.
+    private static final Charset MEDIAMETRICS_CHARSET = StandardCharsets.UTF_8;
+
+    /**
+     * Item records properties and delivers to the MediaMetrics service
+     *
+     */
+    public static class Item {
+
+        /*
+         * MediaMetrics Item
+         *
+         * Creates a Byte String and sends to the MediaMetrics service.
+         * The Byte String serves as a compact form for logging data
+         * with low overhead for storage.
+         *
+         * The Byte String format is as follows:
+         *
+         * For Java
+         *  int64 corresponds to long
+         *  int32, uint32 corresponds to int
+         *  uint16 corresponds to char
+         *  uint8, int8 corresponds to byte
+         *
+         * For items transmitted from Java, uint8 and uint32 values are limited
+         * to INT8_MAX and INT32_MAX.  This constrains the size of large items
+         * to 2GB, which is consistent with ByteBuffer max size. A native item
+         * can conceivably have size of 4GB.
+         *
+         * Physical layout of integers and doubles within the MediaMetrics byte string
+         * is in Native / host order, which is usually little endian.
+         *
+         * Note that primitive data (ints, doubles) within a Byte String has
+         * no extra padding or alignment requirements, like ByteBuffer.
+         *
+         * -- begin of item
+         * -- begin of header
+         * (uint32) item size: including the item size field
+         * (uint32) header size, including the item size and header size fields.
+         * (uint16) version: exactly 0
+         * (uint16) key size, that is key strlen + 1 for zero termination.
+         * (int8)+ key, a string which is 0 terminated (UTF-8).
+         * (int32) pid
+         * (int32) uid
+         * (int64) timestamp
+         * -- end of header
+         * -- begin body
+         * (uint32) number of properties
+         * -- repeat for number of properties
+         *     (uint16) property size, including property size field itself
+         *     (uint8) type of property
+         *     (int8)+ key string, including 0 termination
+         *      based on type of property (given above), one of:
+         *       (int32)
+         *       (int64)
+         *       (double)
+         *       (int8)+ for TYPE_CSTRING, including 0 termination
+         *       (int64, int64) for rate
+         * -- end body
+         * -- end of item
+         *
+         * To record a MediaMetrics event, one creates a new item with an id,
+         * then use a series of puts to add properties
+         * and then a record() to send to the MediaMetrics service.
+         *
+         * The properties may not be unique, and putting a later property with
+         * the same name as an earlier property will overwrite the value and type
+         * of the prior property.
+         *
+         * The timestamp can only be recorded by a system service (and is ignored otherwise;
+         * the MediaMetrics service will fill in the timestamp as needed).
+         *
+         * The units of time are in SystemClock.elapsedRealtimeNanos().
+         *
+         * A clear() may be called to reset the properties to empty, the time to 0, but keep
+         * the other entries the same. This may be called after record().
+         * Additional properties may be added after calling record().  Changing the same property
+         * repeatedly is discouraged as - for this particular implementation - extra data
+         * is stored per change.
+         *
+         * new MediaMetrics.Item(mSomeId)
+         *     .putString("event", "javaCreate")
+         *     .putInt("value", intValue)
+         *     .record();
+         */
+
+        /**
+         * Creates an Item with server added uid, time.
+         *
+         * This is the typical way to record a MediaMetrics item.
+         *
+         * @param key the Metrics ID associated with the item.
+         */
+        public Item(String key) {
+            this(key, -1 /* pid */, -1 /* uid */, 0 /* SystemClock.elapsedRealtimeNanos() */,
+                    2048 /* capacity */);
+        }
+
+        /**
+         * Creates an Item specifying pid, uid, time, and initial Item capacity.
+         *
+         * This might be used by a service to specify a different PID or UID for a client.
+         *
+         * @param key the Metrics ID associated with the item.
+         *        An app may only set properties on an item which has already been
+         *        logged previously by a service.
+         * @param pid the process ID corresponding to the item.
+         *        A value of -1 (or a record() from an app instead of a service) causes
+         *        the MediaMetrics service to fill this in.
+         * @param uid the user ID corresponding to the item.
+         *        A value of -1 (or a record() from an app instead of a service) causes
+         *        the MediaMetrics service to fill this in.
+         * @param timeNs the time when the item occurred (may be in the past).
+         *        A value of 0 (or a record() from an app instead of a service) causes
+         *        the MediaMetrics service to fill it in.
+         *        Should be obtained from SystemClock.elapsedRealtimeNanos().
+         * @param capacity the anticipated size to use for the buffer.
+         *        If the capacity is too small, the buffer will be resized to accommodate.
+         *        This is amortized to copy data no more than twice.
+         */
+        public Item(String key, int pid, int uid, long timeNs, int capacity) {
+            final byte[] keyBytes = key.getBytes(MEDIAMETRICS_CHARSET);
+            final int keyLength = keyBytes.length;
+            if (keyLength > Character.MAX_VALUE - 1) {
+                throw new IllegalArgumentException("Key length too large");
+            }
+
+            // Version 0 - compute the header offsets here.
+            mHeaderSize = 4 + 4 + 2 + 2 + keyLength + 1 + 4 + 4 + 8; // see format above.
+            mPidOffset = mHeaderSize - 16;
+            mUidOffset = mHeaderSize - 12;
+            mTimeNsOffset = mHeaderSize - 8;
+            mPropertyCountOffset = mHeaderSize;
+            mPropertyStartOffset = mHeaderSize + 4;
+
+            mKey = key;
+            mBuffer = ByteBuffer.allocateDirect(
+                    Math.max(capacity, mHeaderSize + MINIMUM_PAYLOAD_SIZE));
+
+            // Version 0 - fill the ByteBuffer with the header (some details updated later).
+            mBuffer.order(ByteOrder.nativeOrder())
+                .putInt((int) 0)                      // total size in bytes (filled in later)
+                .putInt((int) mHeaderSize)            // size of header
+                .putChar((char) FORMAT_VERSION)       // version
+                .putChar((char) (keyLength + 1))      // length, with zero termination
+                .put(keyBytes).put((byte) 0)
+                .putInt(pid)
+                .putInt(uid)
+                .putLong(timeNs);
+            if (mHeaderSize != mBuffer.position()) {
+                throw new IllegalStateException("Mismatched sizing");
+            }
+            mBuffer.putInt(0);     // number of properties (to be later filled in by record()).
+        }
+
+        /**
+         * Sets the property with key to an integer (32 bit) value.
+         *
+         * @param key
+         * @param value
+         * @return itself
+         */
+        public Item putInt(String key, int value) {
+            final byte[] keyBytes = key.getBytes(MEDIAMETRICS_CHARSET);
+            final char propSize = (char) reserveProperty(keyBytes, 4 /* payloadSize */);
+            final int estimatedFinalPosition = mBuffer.position() + propSize;
+            mBuffer.putChar(propSize)
+                .put((byte) TYPE_INT32)
+                .put(keyBytes).put((byte) 0) // key, zero terminated
+                .putInt(value);
+            ++mPropertyCount;
+            if (mBuffer.position() != estimatedFinalPosition) {
+                throw new IllegalStateException("Final position " + mBuffer.position()
+                        + " != estimatedFinalPosition " + estimatedFinalPosition);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the property with key to a long (64 bit) value.
+         *
+         * @param key
+         * @param value
+         * @return itself
+         */
+        public Item putLong(String key, long value) {
+            final byte[] keyBytes = key.getBytes(MEDIAMETRICS_CHARSET);
+            final char propSize = (char) reserveProperty(keyBytes, 8 /* payloadSize */);
+            final int estimatedFinalPosition = mBuffer.position() + propSize;
+            mBuffer.putChar(propSize)
+                .put((byte) TYPE_INT64)
+                .put(keyBytes).put((byte) 0) // key, zero terminated
+                .putLong(value);
+            ++mPropertyCount;
+            if (mBuffer.position() != estimatedFinalPosition) {
+                throw new IllegalStateException("Final position " + mBuffer.position()
+                    + " != estimatedFinalPosition " + estimatedFinalPosition);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the property with key to a double value.
+         *
+         * @param key
+         * @param value
+         * @return itself
+         */
+        public Item putDouble(String key, double value) {
+            final byte[] keyBytes = key.getBytes(MEDIAMETRICS_CHARSET);
+            final char propSize = (char) reserveProperty(keyBytes, 8 /* payloadSize */);
+            final int estimatedFinalPosition = mBuffer.position() + propSize;
+            mBuffer.putChar(propSize)
+                .put((byte) TYPE_DOUBLE)
+                .put(keyBytes).put((byte) 0) // key, zero terminated
+                .putDouble(value);
+            ++mPropertyCount;
+            if (mBuffer.position() != estimatedFinalPosition) {
+                throw new IllegalStateException("Final position " + mBuffer.position()
+                    + " != estimatedFinalPosition " + estimatedFinalPosition);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the property with key to a String value.
+         *
+         * @param key
+         * @param value
+         * @return itself
+         */
+        public Item putString(String key, String value) {
+            final byte[] keyBytes = key.getBytes(MEDIAMETRICS_CHARSET);
+            final byte[] valueBytes = value.getBytes(MEDIAMETRICS_CHARSET);
+            final char propSize = (char) reserveProperty(keyBytes, valueBytes.length + 1);
+            final int estimatedFinalPosition = mBuffer.position() + propSize;
+            mBuffer.putChar(propSize)
+                .put((byte) TYPE_CSTRING)
+                .put(keyBytes).put((byte) 0) // key, zero terminated
+                .put(valueBytes).put((byte) 0); // value, zero term.
+            ++mPropertyCount;
+            if (mBuffer.position() != estimatedFinalPosition) {
+                throw new IllegalStateException("Final position " + mBuffer.position()
+                    + " != estimatedFinalPosition " + estimatedFinalPosition);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the pid to the provided value.
+         *
+         * @param pid which can be -1 if the service is to fill it in from the calling info.
+         * @return itself
+         */
+        public Item setPid(int pid) {
+            mBuffer.putInt(mPidOffset, pid); // pid location in byte string.
+            return this;
+        }
+
+        /**
+         * Sets the uid to the provided value.
+         *
+         * The UID represents the client associated with the property. This must be the UID
+         * of the application if it comes from the application client.
+         *
+         * Trusted services are allowed to set the uid for a client-related item.
+         *
+         * @param uid which can be -1 if the service is to fill it in from calling info.
+         * @return itself
+         */
+        public Item setUid(int uid) {
+            mBuffer.putInt(mUidOffset, uid); // uid location in byte string.
+            return this;
+        }
+
+        /**
+         * Sets the timestamp to the provided value.
+         *
+         * The time is referenced by the Boottime obtained by SystemClock.elapsedRealtimeNanos().
+         * This should be associated with the occurrence of the event.  It is recommended that
+         * the event be registered immediately when it occurs, and no later than 500ms
+         * (and certainly not in the future).
+         *
+         * @param timeNs which can be 0 if the service is to fill it in at the time of call.
+         * @return itself
+         */
+        public Item setTimestamp(long timeNs) {
+            mBuffer.putLong(mTimeNsOffset, timeNs); // time location in byte string.
+            return this;
+        }
+
+        /**
+         * Clears the properties and resets the time to 0.
+         *
+         * No other values are changed.
+         *
+         * @return itself
+         */
+        public Item clear() {
+            mBuffer.position(mPropertyStartOffset);
+            mBuffer.limit(mBuffer.capacity());
+            mBuffer.putLong(mTimeNsOffset, 0); // reset time.
+            mPropertyCount = 0;
+            return this;
+        }
+
+        /**
+         * Sends the item to the MediaMetrics service.
+         *
+         * The item properties are unchanged, hence record() may be called more than once
+         * to send the same item twice. Also, record() may be called without any properties.
+         *
+         * @return true if successful.
+         */
+        public boolean record() {
+            updateHeader();
+            return native_submit_bytebuffer(mBuffer, mBuffer.limit()) >= 0;
+        }
+
+        /**
+         * Converts the Item to a Bundle.
+         *
+         * This is primarily used as a test API for CTS.
+         *
+         * @return a Bundle with the keys set according to data in the Item's buffer.
+         */
+        @TestApi
+        public Bundle toBundle() {
+            updateHeader();
+
+            final ByteBuffer buffer = mBuffer.duplicate();
+            buffer.order(ByteOrder.nativeOrder()) // restore order property
+                .flip();                          // convert from write buffer to read buffer
+
+            return toBundle(buffer);
+        }
+
+        // The following constants are used for tests to extract
+        // the content of the Bundle for CTS testing.
+        @TestApi
+        public static final String BUNDLE_TOTAL_SIZE = "_totalSize";
+        @TestApi
+        public static final String BUNDLE_HEADER_SIZE = "_headerSize";
+        @TestApi
+        public static final String BUNDLE_VERSION = "_version";
+        @TestApi
+        public static final String BUNDLE_KEY_SIZE = "_keySize";
+        @TestApi
+        public static final String BUNDLE_KEY = "_key";
+        @TestApi
+        public static final String BUNDLE_PID = "_pid";
+        @TestApi
+        public static final String BUNDLE_UID = "_uid";
+        @TestApi
+        public static final String BUNDLE_TIMESTAMP = "_timestamp";
+        @TestApi
+        public static final String BUNDLE_PROPERTY_COUNT = "_propertyCount";
+
+        /**
+         * Converts a buffer contents to a bundle
+         *
+         * This is primarily used as a test API for CTS.
+         *
+         * @param buffer contains the byte data serialized according to the byte string version.
+         * @return a Bundle with the keys set according to data in the buffer.
+         */
+        @TestApi
+        public static Bundle toBundle(ByteBuffer buffer) {
+            final Bundle bundle = new Bundle();
+
+            final int totalSize = buffer.getInt();
+            final int headerSize = buffer.getInt();
+            final char version = buffer.getChar();
+            final char keySize = buffer.getChar(); // includes zero termination, i.e. keyLength + 1
+
+            if (totalSize < 0 || headerSize < 0) {
+                throw new IllegalArgumentException("Item size cannot be > " + Integer.MAX_VALUE);
+            }
+            final String key;
+            if (keySize > 0) {
+                key = getStringFromBuffer(buffer, keySize);
+            } else {
+                throw new IllegalArgumentException("Illegal null key");
+            }
+
+            final int pid = buffer.getInt();
+            final int uid = buffer.getInt();
+            final long timestamp = buffer.getLong();
+
+            // Verify header size (depending on version).
+            final int headerRead = buffer.position();
+            if (version == 0) {
+                if (headerRead != headerSize) {
+                    throw new IllegalArgumentException(
+                            "Item key:" + key
+                            + " headerRead:" + headerRead + " != headerSize:" + headerSize);
+                }
+            } else {
+                // future versions should only increase header size
+                // by adding to the end.
+                if (headerRead > headerSize) {
+                    throw new IllegalArgumentException(
+                            "Item key:" + key
+                            + " headerRead:" + headerRead + " > headerSize:" + headerSize);
+                } else if (headerRead < headerSize) {
+                    buffer.position(headerSize);
+                }
+            }
+
+            // Body always starts with properties.
+            final int propertyCount = buffer.getInt();
+            if (propertyCount < 0) {
+                throw new IllegalArgumentException(
+                        "Cannot have more than " + Integer.MAX_VALUE + " properties");
+            }
+            bundle.putInt(BUNDLE_TOTAL_SIZE, totalSize);
+            bundle.putInt(BUNDLE_HEADER_SIZE, headerSize);
+            bundle.putChar(BUNDLE_VERSION, version);
+            bundle.putChar(BUNDLE_KEY_SIZE, keySize);
+            bundle.putString(BUNDLE_KEY, key);
+            bundle.putInt(BUNDLE_PID, pid);
+            bundle.putInt(BUNDLE_UID, uid);
+            bundle.putLong(BUNDLE_TIMESTAMP, timestamp);
+            bundle.putInt(BUNDLE_PROPERTY_COUNT, propertyCount);
+
+            for (int i = 0; i < propertyCount; ++i) {
+                final int initialBufferPosition = buffer.position();
+                final char propSize = buffer.getChar();
+                final byte type = buffer.get();
+
+                // Log.d(TAG, "(" + i + ") propSize:" + ((int)propSize) + " type:" + type);
+                final String propKey = getStringFromBuffer(buffer);
+                switch (type) {
+                    case TYPE_INT32:
+                        bundle.putInt(propKey, buffer.getInt());
+                        break;
+                    case TYPE_INT64:
+                        bundle.putLong(propKey, buffer.getLong());
+                        break;
+                    case TYPE_DOUBLE:
+                        bundle.putDouble(propKey, buffer.getDouble());
+                        break;
+                    case TYPE_CSTRING:
+                        bundle.putString(propKey, getStringFromBuffer(buffer));
+                        break;
+                    case TYPE_NONE:
+                        break; // ignore on Java side
+                    case TYPE_RATE:
+                        buffer.getLong();  // consume the first int64_t of rate
+                        buffer.getLong();  // consume the second int64_t of rate
+                        break; // ignore on Java side
+                    default:
+                        // These are unsupported types for version 0
+                        // We ignore them if the version is greater than 0.
+                        if (version == 0) {
+                            throw new IllegalArgumentException(
+                                    "Property " + propKey + " has unsupported type " + type);
+                        }
+                        buffer.position(initialBufferPosition + propSize); // advance and skip
+                        break;
+                }
+                final int deltaPosition = buffer.position() - initialBufferPosition;
+                if (deltaPosition != propSize) {
+                    throw new IllegalArgumentException("propSize:" + propSize
+                        + " != deltaPosition:" + deltaPosition);
+                }
+            }
+
+            final int finalPosition = buffer.position();
+            if (finalPosition != totalSize) {
+                throw new IllegalArgumentException("totalSize:" + totalSize
+                    + " != finalPosition:" + finalPosition);
+            }
+            return bundle;
+        }
+
+        // Version 0 byte offsets for the header.
+        private static final int FORMAT_VERSION = 0;
+        private static final int TOTAL_SIZE_OFFSET = 0;
+        private static final int HEADER_SIZE_OFFSET = 4;
+        private static final int MINIMUM_PAYLOAD_SIZE = 4;
+        private final int mPidOffset;            // computed in constructor
+        private final int mUidOffset;            // computed in constructor
+        private final int mTimeNsOffset;         // computed in constructor
+        private final int mPropertyCountOffset;  // computed in constructor
+        private final int mPropertyStartOffset;  // computed in constructor
+        private final int mHeaderSize;           // computed in constructor
+
+        private final String mKey;
+
+        private ByteBuffer mBuffer;     // may be reallocated if capacity is insufficient.
+        private int mPropertyCount = 0; // overflow not checked (mBuffer would overflow first).
+
+        private int reserveProperty(byte[] keyBytes, int payloadSize) {
+            final int keyLength = keyBytes.length;
+            if (keyLength > Character.MAX_VALUE) {
+                throw new IllegalStateException("property key too long "
+                        + new String(keyBytes, MEDIAMETRICS_CHARSET));
+            }
+            if (payloadSize > Character.MAX_VALUE) {
+                throw new IllegalStateException("payload too large " + payloadSize);
+            }
+
+            // See the byte string property format above.
+            final int size = 2      /* length */
+                    + 1             /* type */
+                    + keyLength + 1 /* key length with zero termination */
+                    + payloadSize;  /* payload size */
+
+            if (size > Character.MAX_VALUE) {
+                throw new IllegalStateException("Item property "
+                        + new String(keyBytes, MEDIAMETRICS_CHARSET) + " is too large to send");
+            }
+
+            if (mBuffer.remaining() < size) {
+                int newCapacity = mBuffer.position() + size;
+                if (newCapacity > Integer.MAX_VALUE >> 1) {
+                    throw new IllegalStateException(
+                        "Item memory requirements too large: " + newCapacity);
+                }
+                newCapacity <<= 1;
+                ByteBuffer buffer = ByteBuffer.allocateDirect(newCapacity);
+                buffer.order(ByteOrder.nativeOrder());
+
+                // Copy data from old buffer to new buffer.
+                mBuffer.flip();
+                buffer.put(mBuffer);
+
+                // set buffer to new buffer
+                mBuffer = buffer;
+            }
+            return size;
+        }
+
+        // Used for test
+        private static String getStringFromBuffer(ByteBuffer buffer) {
+            return getStringFromBuffer(buffer, Integer.MAX_VALUE);
+        }
+
+        // Used for test
+        private static String getStringFromBuffer(ByteBuffer buffer, int size) {
+            int i = buffer.position();
+            int limit = buffer.limit();
+            if (size < Integer.MAX_VALUE - i && i + size < limit) {
+                limit = i + size;
+            }
+            for (; i < limit; ++i) {
+                if (buffer.get(i) == 0) {
+                    final int newPosition = i + 1;
+                    if (size != Integer.MAX_VALUE && newPosition - buffer.position() != size) {
+                        throw new IllegalArgumentException("chars consumed at " + i + ": "
+                            + (newPosition - buffer.position()) + " != size: " + size);
+                    }
+                    final String found;
+                    if (buffer.hasArray()) {
+                        found = new String(
+                            buffer.array(), buffer.position() + buffer.arrayOffset(),
+                            i - buffer.position(), MEDIAMETRICS_CHARSET);
+                        buffer.position(newPosition);
+                    } else {
+                        final byte[] array = new byte[i - buffer.position()];
+                        buffer.get(array);
+                        found = new String(array, MEDIAMETRICS_CHARSET);
+                        buffer.get(); // remove 0.
+                    }
+                    return found;
+                }
+            }
+            throw new IllegalArgumentException(
+                    "No zero termination found in string position: "
+                    + buffer.position() + " end: " + i);
+        }
+
+        /**
+         * May be called multiple times - just makes the header consistent with the current
+         * properties written.
+         */
+        private void updateHeader() {
+            // Buffer sized properly in constructor.
+            mBuffer.putInt(TOTAL_SIZE_OFFSET, mBuffer.position())      // set total length
+                .putInt(mPropertyCountOffset, (char) mPropertyCount); // set number of properties
+        }
+    }
+
+    private static native int native_submit_bytebuffer(@NonNull ByteBuffer buffer, int length);
+}
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 515f6a8..40e9073 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -19,6 +19,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ServiceConnection;
 import android.net.Uri;
@@ -197,7 +198,7 @@
     private static Uri scanFileQuietly(ContentProviderClient client, File file) {
         Uri uri = null;
         try {
-            uri = MediaStore.scanFile(client, file.getCanonicalFile());
+            uri = MediaStore.scanFile(ContentResolver.wrap(client), file.getCanonicalFile());
             Log.d(TAG, "Scanned " + file + " to " + uri);
         } catch (Exception e) {
             Log.w(TAG, "Failed to scan " + file + ": " + e);
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 9064e68..a1e1591 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -908,7 +908,7 @@
         }
 
         // Tell MediaScanner about the new file. Wait for it to assign a {@link Uri}.
-        return MediaStore.scanFile(mContext, outFile);
+        return MediaStore.scanFile(mContext.getContentResolver(), outFile);
     }
 
     private static final String getExternalDirectoryForType(final int type) {
diff --git a/media/java/android/media/RouteSessionController.java b/media/java/android/media/RouteSessionController.java
new file mode 100644
index 0000000..5ff7218
--- /dev/null
+++ b/media/java/android/media/RouteSessionController.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+
+/**
+ * A class to control media route session in media route provider.
+ * For example, adding/removing/transferring routes to session can be done through this class.
+ * Instances are created by {@link MediaRouter2}.
+ *
+ * TODO: When session is introduced, change Javadoc of all methods/classes by using [@link Session].
+ *
+ * @hide
+ */
+public class RouteSessionController {
+    private final int mSessionId;
+    private final String mCategory;
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final CopyOnWriteArrayList<CallbackRecord> mCallbackRecords =
+            new CopyOnWriteArrayList<>();
+
+    private volatile boolean mIsReleased;
+
+    /**
+     * @param sessionId the ID of the session.
+     * @param category The category of media routes that the session includes.
+     */
+    RouteSessionController(int sessionId, @NonNull String category) {
+        mSessionId = sessionId;
+        mCategory = category;
+    }
+
+    /**
+     * @return the ID of this controller
+     */
+    public int getSessionId() {
+        return mSessionId;
+    }
+
+    /**
+     * @return the category of routes that the session includes.
+     */
+    @NonNull
+    public String getCategory() {
+        return mCategory;
+    }
+
+    /**
+     * @return the list of currently connected routes
+     */
+    @NonNull
+    public List<MediaRoute2Info> getRoutes() {
+        // TODO: Implement this when SessionInfo is introduced.
+        return null;
+    }
+
+    /**
+     * Returns true if the session is released, false otherwise.
+     * If it is released, then all other getters from this instance may return invalid values.
+     * Also, any operations to this instance will be ignored once released.
+     *
+     * @see #release
+     * @see Callback#onReleased
+     */
+    public boolean isReleased() {
+        return mIsReleased;
+    }
+
+    /**
+     * Add routes to the remote session.
+     *
+     * @see #getRoutes()
+     * @see Callback#onSessionInfoChanged
+     */
+    public void addRoutes(List<MediaRoute2Info> routes) {
+        // TODO: Implement this when the actual connection logic is implemented.
+    }
+
+    /**
+     * Remove routes from this session. Media may be stopped on those devices.
+     * Route removal requests that are not currently in {@link #getRoutes()} will be ignored.
+     *
+     * @see #getRoutes()
+     * @see Callback#onSessionInfoChanged
+     */
+    public void removeRoutes(List<MediaRoute2Info> routes) {
+        // TODO: Implement this when the actual connection logic is implemented.
+    }
+
+    /**
+     * Registers a {@link Callback} for monitoring route changes.
+     * If the same callback is registered previously, previous executor will be overwritten with the
+     * new one.
+     */
+    public void registerCallback(Executor executor, Callback callback) {
+        if (mIsReleased) {
+            return;
+        }
+        Objects.requireNonNull(executor, "executor must not be null");
+        Objects.requireNonNull(callback, "callback must not be null");
+
+        synchronized (mLock) {
+            CallbackRecord recordWithSameCallback = null;
+            for (CallbackRecord record : mCallbackRecords) {
+                if (callback == record.mCallback) {
+                    recordWithSameCallback = record;
+                    break;
+                }
+            }
+
+            if (recordWithSameCallback != null) {
+                recordWithSameCallback.mExecutor = executor;
+            } else {
+                mCallbackRecords.add(new CallbackRecord(executor, callback));
+            }
+        }
+    }
+
+    /**
+     * Unregisters a previously registered {@link Callback}.
+     */
+    public void unregisterCallback(Callback callback) {
+        Objects.requireNonNull(callback, "callback must not be null");
+
+        synchronized (mLock) {
+            CallbackRecord recordToRemove = null;
+            for (CallbackRecord record : mCallbackRecords) {
+                if (callback == record.mCallback) {
+                    recordToRemove = record;
+                    break;
+                }
+            }
+
+            if (recordToRemove != null) {
+                mCallbackRecords.remove(recordToRemove);
+            }
+        }
+    }
+
+    /**
+     * Release this session.
+     * Any operation on this session after calling this method will be ignored.
+     *
+     * @param stopMedia Should the device where the media is played
+     *                  be stopped after this session is released.
+     */
+    public void release(boolean stopMedia) {
+        mIsReleased = true;
+        mCallbackRecords.clear();
+        // TODO: Use stopMedia variable when the actual connection logic is implemented.
+    }
+
+    /**
+     * Callback class for getting updates on routes and session release.
+     */
+    public static class Callback {
+
+        /**
+         * Called when the session info has changed.
+         * TODO: When SessionInfo is introduced, uncomment below argument.
+         */
+        void onSessionInfoChanged(/* SessionInfo info */) {}
+
+        /**
+         * Called when the session is released. Session can be released by the controller using
+         * {@link #release(boolean)}, or by the {@link MediaRoute2ProviderService} itself.
+         * One can do clean-ups here.
+         *
+         * TODO: When SessionInfo is introduced, change the javadoc of releasing session on
+         * provider side.
+         */
+        void onReleased(int reason, boolean shouldStop) {}
+    }
+
+    private class CallbackRecord {
+        public final Callback mCallback;
+        public Executor mExecutor;
+
+        CallbackRecord(@NonNull Executor executor, @NonNull Callback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+    }
+}
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index a315c1e..6705b0c 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -33,14 +33,13 @@
 import android.graphics.ImageDecoder.ImageInfo;
 import android.graphics.ImageDecoder.Source;
 import android.graphics.Matrix;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
 import android.os.CancellationSignal;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.provider.MediaStore.ThumbnailConstants;
+import android.provider.MediaStore;
 import android.util.Log;
 import android.util.Size;
 
@@ -77,15 +76,7 @@
     public static final int OPTIONS_RECYCLE_INPUT = 0x2;
 
     private static Size convertKind(int kind) {
-        if (kind == ThumbnailConstants.MICRO_KIND) {
-            return Point.convert(ThumbnailConstants.MICRO_SIZE);
-        } else if (kind == ThumbnailConstants.FULL_SCREEN_KIND) {
-            return Point.convert(ThumbnailConstants.FULL_SCREEN_SIZE);
-        } else if (kind == ThumbnailConstants.MINI_KIND) {
-            return Point.convert(ThumbnailConstants.MINI_SIZE);
-        } else {
-            throw new IllegalArgumentException("Unsupported kind: " + kind);
-        }
+        return MediaStore.Images.Thumbnails.getKindSize(kind);
     }
 
     private static class Resizer implements ImageDecoder.OnHeaderDecodedListener {
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 0f402eb..f3c071a0 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -16,8 +16,10 @@
 
 package android.mtp;
 
+import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
 import android.content.ContentProviderClient;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
@@ -422,13 +424,13 @@
         }
         // Add the new file to MediaProvider
         if (succeeded) {
-            MediaStore.scanFile(mContext, obj.getPath().toFile());
+            MediaStore.scanFile(mContext.getContentResolver(), obj.getPath().toFile());
         }
     }
 
     @VisibleForNative
     private void rescanFile(String path, int handle, int format) {
-        MediaStore.scanFile(mContext, new File(path));
+        MediaStore.scanFile(mContext.getContentResolver(), new File(path));
     }
 
     @VisibleForNative
@@ -587,13 +589,13 @@
         if (obj.isDir()) {
             // for directories, check if renamed from something hidden to something non-hidden
             if (oldPath.getFileName().startsWith(".") && !newPath.startsWith(".")) {
-                MediaStore.scanFile(mContext, newPath.toFile());
+                MediaStore.scanFile(mContext.getContentResolver(), newPath.toFile());
             }
         } else {
             // for files, check if renamed from .nomedia to something else
             if (oldPath.getFileName().toString().toLowerCase(Locale.US).equals(NO_MEDIA)
                     && !newPath.getFileName().toString().toLowerCase(Locale.US).equals(NO_MEDIA)) {
-                MediaStore.scanFile(mContext, newPath.getParent().toFile());
+                MediaStore.scanFile(mContext.getContentResolver(), newPath.getParent().toFile());
             }
         }
         return MtpConstants.RESPONSE_OK;
@@ -662,7 +664,7 @@
                 mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs);
             } else {
                 // Old parent doesn't exist - add the object
-                MediaStore.scanFile(mContext, path.toFile());
+                MediaStore.scanFile(mContext.getContentResolver(), path.toFile());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in mMediaProvider.update", e);
@@ -689,7 +691,7 @@
         if (!success) {
             return;
         }
-        MediaStore.scanFile(mContext, obj.getPath().toFile());
+        MediaStore.scanFile(mContext.getContentResolver(), obj.getPath().toFile());
     }
 
     @VisibleForNative
@@ -909,7 +911,7 @@
             String[] whereArgs = new String[]{path.toString()};
             if (mMediaProvider.delete(objectsUri, PATH_WHERE, whereArgs) > 0) {
                 if (!isDir && path.toString().toLowerCase(Locale.US).endsWith(NO_MEDIA)) {
-                    MediaStore.scanFile(mContext, path.getParent().toFile());
+                    MediaStore.scanFile(mContext.getContentResolver(), path.getParent().toFile());
                 }
             } else {
                 Log.i(TAG, "Mediaprovider didn't delete " + path);
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 65d0fef..c7dbca6 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -41,11 +41,7 @@
         mDescription = volume.getDescription(null);
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
-        if (volume.isPrimary()) {
-            mVolumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY;
-        } else {
-            mVolumeName = volume.getNormalizedUuid();
-        }
+        mVolumeName = volume.getMediaStoreVolumeName();
     }
 
     /**
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index 494c617..e17a617 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -23,6 +23,7 @@
 
 #include "android_media_MediaMetricsJNI.h"
 #include "android_os_Parcel.h"
+#include "android_runtime/AndroidRuntime.h"
 
 // This source file is compiled and linked into:
 // core/jni/ (libandroid_runtime.so)
@@ -124,6 +125,28 @@
     return bh.bundle;
 }
 
+// Implementation of MediaMetrics.native_submit_bytebuffer(),
+// Delivers the byte buffer to the mediametrics service.
+static jint android_media_MediaMetrics_submit_bytebuffer(
+        JNIEnv* env, jobject thiz, jobject byteBuffer, jint length)
+{
+    const jbyte* buffer =
+            reinterpret_cast<const jbyte*>(env->GetDirectBufferAddress(byteBuffer));
+    if (buffer == nullptr) {
+        ALOGE("Error retrieving source of audio data to play, can't play");
+        return (jint)BAD_VALUE;
+    }
+
+    // TODO: directly record item to MediaMetrics service.
+    mediametrics::Item item;
+    if (item.readFromByteString((char *)buffer, length) != NO_ERROR) {
+        ALOGW("%s: cannot read from byte string", __func__);
+        return (jint)BAD_VALUE;
+    }
+    item.selfrecord();
+    return (jint)NO_ERROR;
+}
+
 // Helper function to convert a native PersistableBundle to a Java
 // PersistableBundle.
 jobject MediaMetricsJNI::nativeToJavaPersistableBundle(JNIEnv *env,
@@ -191,5 +214,18 @@
     return newBundle;
 }
 
-};  // namespace android
+// ----------------------------------------------------------------------------
 
+static constexpr JNINativeMethod gMethods[] = {
+    {"native_submit_bytebuffer", "(Ljava/nio/ByteBuffer;I)I",
+            (void *)android_media_MediaMetrics_submit_bytebuffer},
+};
+
+// Registers the native methods, called from core/jni/AndroidRuntime.cpp
+int register_android_media_MediaMetrics(JNIEnv *env)
+{
+    return AndroidRuntime::registerNativeMethods(
+            env, "android/media/MediaMetrics", gMethods, std::size(gMethods));
+}
+
+};  // namespace android
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 5d0db01..19ff244 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -215,7 +215,6 @@
                     Settings.Global.DEFAULT_DNS_SERVER,
                     Settings.Global.DEFAULT_INSTALL_LOCATION,
                     Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA,
-                    Settings.Global.DEFAULT_USER_ID_TO_BOOT_INTO,
                     Settings.Global.DESK_DOCK_SOUND,
                     Settings.Global.DESK_UNDOCK_SOUND,
                     Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b89f141..51bf441 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -224,6 +224,9 @@
     <!-- Permission requried for CTS test - CellBroadcastIntentsTest -->
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"/>
 
+    <!-- Permission required for CTS test - TetheringManagerTest -->
+    <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtoneOverlayService.java b/packages/SoundPicker/src/com/android/soundpicker/RingtoneOverlayService.java
index 2d37b4c..15fd1f7 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtoneOverlayService.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtoneOverlayService.java
@@ -101,7 +101,7 @@
     }
 
     private Uri scanFile(@NonNull final File file) {
-        return MediaStore.scanFile(this, file);
+        return MediaStore.scanFile(getContentResolver(), file);
     }
 
     private void set(@NonNull final String name, @NonNull final Uri uri) {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0407ffe..45318fd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -915,7 +915,7 @@
     <!-- QuickSettings: Label for the toggle to activate dark theme (A.K.A Dark Mode). [CHAR LIMIT=20] -->
     <string name="quick_settings_ui_mode_night_label">Dark theme</string>
     <!-- QuickSettings: Secondary text for the dark theme tile when enabled by battery saver. [CHAR LIMIT=20] -->
-    <string name="quick_settings_dark_mode_secondary_label_battery_saver">Battery saver</string>
+    <string name="quick_settings_dark_mode_secondary_label_battery_saver">Battery Saver</string>
     <!-- QuickSettings: Secondary text for when the Dark Mode will be enabled at sunset. [CHAR LIMIT=20] -->
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset">On at sunset</string>
     <!-- QuickSettings: Secondary text for when the Dark Mode will be on until sunrise. [CHAR LIMIT=20] -->
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 0383dee..d3ccbeb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -371,7 +371,8 @@
         Bitmap thumbnailBitmap = null;
         try {
             ContentResolver resolver = getContentResolver();
-            Size size = Point.convert(MediaStore.ThumbnailConstants.MINI_SIZE);
+            DisplayMetrics metrics = getResources().getDisplayMetrics();
+            Size size = new Size(metrics.widthPixels, metrics.heightPixels / 2);
             thumbnailBitmap = resolver.loadThumbnail(uri, size, null);
         } catch (IOException e) {
             Log.e(TAG, "Error creating thumbnail: " + e.getMessage());
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 76925b4..2f401e5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -23,6 +23,8 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
@@ -48,7 +50,9 @@
 import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.provider.MediaStore;
+import android.provider.MediaStore.MediaColumns;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -275,6 +279,7 @@
         Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
 
         Context context = mParams.context;
+        ContentResolver resolver = context.getContentResolver();
         Bitmap image = mParams.image;
         Resources r = context.getResources();
 
@@ -284,23 +289,27 @@
                             mSmartActionsProvider, mSmartActionsEnabled, isManagedProfile(context));
 
             // Save the screenshot to the MediaStore
-            final MediaStore.PendingParams params = new MediaStore.PendingParams(
-                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mImageFileName, "image/png");
-            params.setRelativePath(Environment.DIRECTORY_PICTURES + File.separator
-                    + Environment.DIRECTORY_SCREENSHOTS);
+            final ContentValues values = new ContentValues();
+            values.put(MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
+                    + File.separator + Environment.DIRECTORY_SCREENSHOTS);
+            values.put(MediaColumns.DISPLAY_NAME, mImageFileName);
+            values.put(MediaColumns.MIME_TYPE, "image/png");
+            values.put(MediaColumns.DATE_ADDED, mImageTime / 1000);
+            values.put(MediaColumns.DATE_MODIFIED, mImageTime / 1000);
+            values.put(MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
+            values.put(MediaColumns.IS_PENDING, 1);
 
-            final Uri uri = MediaStore.createPending(context, params);
-            final MediaStore.PendingSession session = MediaStore.openPending(context, uri);
+            final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
             try {
                 // First, write the actual data for our screenshot
-                try (OutputStream out = session.openOutputStream()) {
+                try (OutputStream out = resolver.openOutputStream(uri)) {
                     if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                         throw new IOException("Failed to compress");
                     }
                 }
 
                 // Next, write metadata to help index the screenshot
-                try (ParcelFileDescriptor pfd = session.open()) {
+                try (ParcelFileDescriptor pfd = resolver.openFile(uri, "rw", null)) {
                     final ExifInterface exif = new ExifInterface(pfd.getFileDescriptor());
 
                     exif.setAttribute(ExifInterface.TAG_SOFTWARE,
@@ -327,12 +336,15 @@
 
                     exif.saveAttributes();
                 }
-                session.publish();
+
+                // Everything went well above, publish it!
+                values.clear();
+                values.put(MediaColumns.IS_PENDING, 0);
+                values.putNull(MediaColumns.DATE_EXPIRES);
+                resolver.update(uri, values, null, null);
             } catch (Exception e) {
-                session.abandon();
+                resolver.delete(uri, null);
                 throw e;
-            } finally {
-                IoUtils.closeQuietly(session);
             }
 
             populateNotificationActions(context, r, uri, smartActionsFuture, mNotificationBuilder);
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 4657de2..f4c7e23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -810,6 +810,8 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mWallpaperSupported =
+                mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
 
         // Connect in to the status bar manager service
         mCommandQueue.addCallback(this);
@@ -823,9 +825,6 @@
 
         createAndAddWindows(result);
 
-        mWallpaperSupported =
-                mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
-
         if (mWallpaperSupported) {
             // Make sure we always have the most current wallpaper info.
             IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d7ed2e9..202f900 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -82,6 +82,7 @@
 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -168,6 +169,8 @@
     @Nullable
     private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
 
+    private final InputMethodManagerInternal mInputMethodManagerInternal;
+
     AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
             AutofillCompatState autofillCompatState,
@@ -179,6 +182,7 @@
         mUi = ui;
         mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId);
         mAutofillCompatState = autofillCompatState;
+        mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
 
         updateLocked(disabled);
     }
@@ -493,7 +497,7 @@
                 sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback,
                 mUiLatencyHistory, mWtfHistory, serviceComponentName,
                 componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
-                flags);
+                flags, mInputMethodManagerInternal);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3b2da91..67bcccd 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -42,6 +42,8 @@
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.AutofillOverlay;
 import android.app.assist.AssistStructure.ViewNode;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -80,6 +82,8 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
+import android.util.Log;
+import android.util.Size;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -90,22 +94,38 @@
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.view.inline.InlinePresentationSpec;
+import android.view.inputmethod.InlineSuggestion;
+import android.view.inputmethod.InlineSuggestionInfo;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.IInlineSuggestionsResponseCallback;
+import com.android.internal.view.inline.IInlineContentCallback;
+import com.android.internal.view.inline.IInlineContentProvider;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.autofill.ui.PendingUi;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -290,6 +310,23 @@
     @GuardedBy("mLock")
     private boolean mForAugmentedAutofillOnly;
 
+    @NonNull
+    private final InputMethodManagerInternal mInputMethodManagerInternal;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private CompletableFuture<InlineSuggestionsRequest> mSuggestionsRequestFuture;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private CompletableFuture<IInlineSuggestionsResponseCallback>
+            mInlineSuggestionsResponseCallbackFuture;
+
+    @Nullable
+    private InlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
+
+    private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
+
     /**
      * Receiver of assist data from the app's {@link Activity}.
      */
@@ -386,7 +423,23 @@
 
                 final ArrayList<FillContext> contexts =
                         mergePreviousSessionLocked(/* forSave= */ false);
-                request = new FillRequest(requestId, contexts, mClientState, flags);
+
+                InlineSuggestionsRequest suggestionsRequest = null;
+                if (mSuggestionsRequestFuture != null) {
+                    try {
+                        suggestionsRequest = mSuggestionsRequestFuture.get(
+                                INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                    } catch (TimeoutException e) {
+                        Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
+                    } catch (CancellationException e) {
+                        Log.w(TAG, "Inline suggestions request cancelled");
+                    } catch (InterruptedException | ExecutionException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+
+                request = new FillRequest(requestId, contexts, mClientState, flags,
+                        suggestionsRequest);
             }
 
             mRemoteFillService.onFillRequest(request);
@@ -569,6 +622,70 @@
     }
 
     /**
+     * Returns whether inline suggestions are enabled for Autofill.
+     */
+    // TODO(b/137800469): Implement this
+    private boolean isInlineSuggestionsEnabled() {
+        return true;
+    }
+
+    /**
+     * Ask the IME to make an inline suggestions request if enabled.
+     */
+    private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState,
+            int newState, int flags) {
+        if (isInlineSuggestionsEnabled()) {
+            mSuggestionsRequestFuture = new CompletableFuture<>();
+            mInlineSuggestionsResponseCallbackFuture = new CompletableFuture<>();
+
+            if (mInlineSuggestionsRequestCallback == null) {
+                mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallback(this);
+            }
+
+            mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
+                    mComponentName, mCurrentViewId, mInlineSuggestionsRequestCallback);
+        }
+
+        requestNewFillResponseLocked(viewState, newState, flags);
+    }
+
+    private static final class InlineSuggestionsRequestCallback
+            extends IInlineSuggestionsRequestCallback.Stub {
+        private final WeakReference<Session> mSession;
+
+        private InlineSuggestionsRequestCallback(Session session) {
+            mSession = new WeakReference<>(session);
+        }
+
+        @Override
+        public void onInlineSuggestionsUnsupported() throws RemoteException {
+            Log.i(TAG, "inline suggestions request unsupported, "
+                    + "falling back to regular autofill");
+            final Session session = mSession.get();
+            if (session != null) {
+                synchronized (session.mLock) {
+                    session.mSuggestionsRequestFuture.cancel(true);
+                    session.mInlineSuggestionsResponseCallbackFuture.cancel(true);
+                }
+            }
+        }
+
+        @Override
+        public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
+                IInlineSuggestionsResponseCallback callback) throws RemoteException {
+            Log.i(TAG, "onInlineSuggestionsRequest() received: "
+                    + request);
+            final Session session = mSession.get();
+            if (session != null) {
+                synchronized (session.mLock) {
+                    session.mSuggestionsRequestFuture.complete(request);
+                    session.mInlineSuggestionsResponseCallbackFuture.complete(callback);
+                }
+            }
+        }
+    }
+
+    /**
      * Reads a new structure and then request a new fill response from the fill service.
      */
     @GuardedBy("mLock")
@@ -584,6 +701,7 @@
             triggerAugmentedAutofillLocked();
             return;
         }
+
         viewState.setState(newState);
 
         int requestId;
@@ -636,7 +754,8 @@
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
             @NonNull LocalLog wtfHistory, @Nullable ComponentName serviceComponentName,
             @NonNull ComponentName componentName, boolean compatMode,
-            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
+            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags,
+            @NonNull InputMethodManagerInternal inputMethodManagerInternal) {
         if (sessionId < 0) {
             wtf(null, "Non-positive sessionId: %s", sessionId);
         }
@@ -661,6 +780,8 @@
         mForAugmentedAutofillOnly = forAugmentedAutofillOnly;
         setClientLocked(client);
 
+        mInputMethodManagerInternal = inputMethodManagerInternal;
+
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
     }
@@ -2208,7 +2329,8 @@
         if ((flags & FLAG_MANUAL_REQUEST) != 0) {
             mForAugmentedAutofillOnly = false;
             if (sDebug) Slog.d(TAG, "Re-starting session on view " + id + " and flags " + flags);
-            requestNewFillResponseLocked(viewState, ViewState.STATE_RESTARTED_SESSION, flags);
+            maybeRequestInlineSuggestionsRequestThenFillLocked(viewState,
+                    ViewState.STATE_RESTARTED_SESSION, flags);
             return;
         }
 
@@ -2218,7 +2340,8 @@
                 Slog.d(TAG, "Starting partition or augmented request for view id " + id + ": "
                         + viewState.getStateAsString());
             }
-            requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_PARTITION, flags);
+            maybeRequestInlineSuggestionsRequestThenFillLocked(viewState,
+                    ViewState.STATE_STARTED_PARTITION, flags);
         } else {
             if (sVerbose) {
                 Slog.v(TAG, "Not starting new partition for view " + id + ": "
@@ -2325,7 +2448,8 @@
                 // View is triggering autofill.
                 mCurrentViewId = viewState.id;
                 viewState.update(value, virtualBounds, flags);
-                requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
+                maybeRequestInlineSuggestionsRequestThenFillLocked(viewState,
+                        ViewState.STATE_STARTED_SESSION, flags);
                 break;
             case ACTION_VALUE_CHANGED:
                 if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
@@ -2527,6 +2651,16 @@
             wtf(null, "onFillReady(): no service label or icon");
             return;
         }
+
+        final List<Slice> inlineSuggestionSlices = response.getInlineSuggestionSlices();
+        if (inlineSuggestionSlices != null) {
+            if (requestShowInlineSuggestions(inlineSuggestionSlices, response)) {
+                //TODO(b/137800469): Add logging instead of bypassing below logic.
+                return;
+            }
+        }
+
+
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mComponentName,
                 serviceLabel, serviceIcon, this, id, mCompatMode);
@@ -2558,6 +2692,109 @@
         }
     }
 
+    /**
+     * Returns whether we made a request to show inline suggestions.
+     */
+    private boolean requestShowInlineSuggestions(List<Slice> inlineSuggestionSlices,
+            FillResponse response) {
+        IInlineSuggestionsResponseCallback inlineContentCallback = null;
+        synchronized (mLock) {
+            if (mInlineSuggestionsResponseCallbackFuture != null) {
+                try {
+                    inlineContentCallback = mInlineSuggestionsResponseCallbackFuture.get(
+                            INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                } catch (TimeoutException e) {
+                    Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
+                } catch (CancellationException e) {
+                    Log.w(TAG, "Inline suggestions callback cancelled");
+                } catch (InterruptedException | ExecutionException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
+        if (inlineContentCallback == null) {
+            Log.w(TAG, "Session input method callback is not set yet");
+            return false;
+        }
+
+        final List<Dataset> datasets = response.getDatasets();
+        if (datasets == null) {
+            Log.w(TAG, "response returned null datasets");
+            return false;
+        }
+
+        final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
+        final int slicesSize = inlineSuggestionSlices.size();
+        if (datasets.size() < slicesSize) {
+            Log.w(TAG, "Too many slices provided, not enough corresponding datasets");
+            return false;
+        }
+
+        for (int sliceIndex = 0; sliceIndex < slicesSize; sliceIndex++) {
+            Log.i(TAG, "Reading slice-" + sliceIndex + " at requestshowinlinesuggestions");
+            final Slice inlineSuggestionSlice = inlineSuggestionSlices.get(sliceIndex);
+            final List<SliceItem> sliceItems = inlineSuggestionSlice.getItems();
+
+            final int itemsSize = sliceItems.size();
+            int minWidth = -1;
+            int maxWidth = -1;
+            int minHeight = -1;
+            int maxHeight = -1;
+            for (int itemIndex = 0; itemIndex < itemsSize; itemIndex++) {
+                final SliceItem item = sliceItems.get(itemIndex);
+                final String subtype = item.getSubType();
+                switch (item.getSubType()) {
+                    case "SUBTYPE_MIN_WIDTH":
+                        minWidth = item.getInt();
+                        break;
+                    case "SUBTYPE_MAX_WIDTH":
+                        maxWidth = item.getInt();
+                        break;
+                    case "SUBTYPE_MIN_HEIGHT":
+                        minHeight = item.getInt();
+                        break;
+                    case "SUBTYPE_MAX_HEIGHT":
+                        maxHeight = item.getInt();
+                        break;
+                    default:
+                        Log.i(TAG, "unrecognized inline suggestions subtype: " + subtype);
+                }
+            }
+
+            if (minWidth < 0 || maxWidth < 0 || minHeight < 0 || maxHeight < 0) {
+                Log.w(TAG, "missing inline suggestion requirements");
+                return false;
+            }
+
+            final InlinePresentationSpec spec = new InlinePresentationSpec.Builder(
+                    new Size(minWidth, minHeight), new Size(maxWidth, maxHeight)).build();
+            final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
+                    spec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[] { "" });
+            final Dataset dataset = datasets.get(sliceIndex);
+
+            inlineSuggestions.add(new InlineSuggestion(inlineSuggestionInfo,
+                    new IInlineContentProvider.Stub() {
+                        @Override
+                        public void provideContent(int width, int height,
+                                IInlineContentCallback callback) throws RemoteException {
+                            getUiForShowing().getSuggestionSurfaceForShowing(dataset, response,
+                                    mCurrentViewId, width, height, callback);
+                        }
+                    }));
+        }
+
+        try  {
+            inlineContentCallback.onInlineSuggestionsResponse(
+                    new InlineSuggestionsResponse(inlineSuggestions));
+        } catch (RemoteException e) {
+            Log.w(TAG, "onFillReady() remote error calling onInlineSuggestionsResponse()");
+            return false;
+        }
+
+        return true;
+    }
+
     boolean isDestroyed() {
         synchronized (mLock) {
             return mDestroyed;
@@ -2831,6 +3068,7 @@
 
         final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
 
+        // TODO(b/137800469): implement inlined suggestions for augmented autofill
         remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
                 currentValue);
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 26bb7c3..eadfd31 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -24,6 +24,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.metrics.LogMaker;
 import android.os.Bundle;
@@ -37,13 +39,19 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.view.KeyEvent;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.view.WindowlessViewRoot;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.view.inline.IInlineContentCallback;
 import com.android.server.LocalServices;
 import com.android.server.UiModeManagerInternal;
 import com.android.server.UiThread;
@@ -171,6 +179,75 @@
     }
 
     /**
+     * TODO(b/137800469): Fill in javadoc.
+     * TODO(b/137800469): peoperly manage lifecycle of suggestions surfaces.
+     */
+    public void getSuggestionSurfaceForShowing(@NonNull Dataset dataset,
+            @NonNull FillResponse response, AutofillId autofillId, int width, int height,
+            IInlineContentCallback cb) {
+        if (dataset == null) {
+            Slog.w(TAG, "getSuggestionSurfaceForShowing() called with null dataset");
+        }
+        mHandler.post(() -> {
+            final SurfaceControl suggestionSurface = inflateInlineSuggestion(dataset, response,
+                    autofillId, width, height);
+
+            try {
+                cb.onContent(suggestionSurface);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "RemoteException replying onContent(" + suggestionSurface + "): " + e);
+            }
+        });
+    }
+
+    /**
+     * TODO(b/137800469): Fill in javadoc, generate custom templated view for inline suggestions.
+     * TODO: Move to ExtServices.
+     *
+     * @return a {@link SurfaceControl} with the inflated content embedded in it.
+     */
+    private SurfaceControl inflateInlineSuggestion(@NonNull Dataset dataset,
+            @NonNull FillResponse response, AutofillId autofillId, int width, int height) {
+        Slog.i(TAG, "inflate() called");
+        final Context context = mContext;
+        final int index = dataset.getFieldIds().indexOf(autofillId);
+        if (index < 0) {
+            Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
+                    + " not found in dataset");
+        }
+
+        final AutofillValue datasetValue = dataset.getFieldValues().get(index);
+        final SurfaceControl sc = new SurfaceControl.Builder()
+                // TODO(b/137800469): sanitize name
+                .setName("af suggestion")
+                .build();
+
+        //TODO(b/137800469): Pass in inputToken from IME.
+        final WindowlessViewRoot wvr = new WindowlessViewRoot(context, context.getDisplay(), sc,
+                null);
+
+        TextView textView = new TextView(context);
+        textView.setText(datasetValue.getTextValue());
+        textView.setBackgroundColor(Color.WHITE);
+        textView.setTextColor(Color.BLACK);
+        textView.setOnClickListener(v -> {
+            Slog.d(TAG, "Inline suggestion clicked");
+            hideFillUiUiThread(mCallback, true);
+            if (mCallback != null) {
+                final int datasetIndex = response.getDatasets().indexOf(dataset);
+                mCallback.fill(response.getRequestId(), datasetIndex, dataset);
+            }
+        });
+
+        WindowManager.LayoutParams lp =
+                new WindowManager.LayoutParams(width, height,
+                        WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
+        wvr.addView(textView, lp);
+
+        return sc;
+    }
+
+    /**
      * Shows the fill UI, removing the previous fill UI if the has changed.
      *
      * @param focusedId the currently focused field
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 9b1d9e9..5a78036 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -118,6 +118,7 @@
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.DataUnit;
 import android.util.FeatureFlagUtils;
@@ -3161,16 +3162,20 @@
         final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
         final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
         final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
+        final boolean includeRecent = (flags & StorageManager.FLAG_INCLUDE_RECENT) != 0;
 
         // Report all volumes as unmounted until we've recorded that user 0 has unlocked. There
         // are no guarantees that callers will see a consistent view of the volume before that
         // point
         final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM);
 
+        final boolean userIsDemo;
         final boolean userKeyUnlocked;
         final boolean storagePermission;
         final long token = Binder.clearCallingIdentity();
         try {
+            userIsDemo = LocalServices.getService(UserManagerInternal.class)
+                    .getUserInfo(userId).isDemo();
             userKeyUnlocked = isUserKeyUnlocked(userId);
             storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName);
         } finally {
@@ -3180,6 +3185,7 @@
         boolean foundPrimary = false;
 
         final ArrayList<StorageVolume> res = new ArrayList<>();
+        final ArraySet<String> resUuids = new ArraySet<>();
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
@@ -3222,7 +3228,43 @@
                 } else {
                     res.add(userVol);
                 }
+                resUuids.add(userVol.getUuid());
             }
+
+            if (includeRecent) {
+                final long lastWeek = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
+                for (int i = 0; i < mRecords.size(); i++) {
+                    final VolumeRecord rec = mRecords.valueAt(i);
+
+                    // Skip if we've already included it above
+                    if (resUuids.contains(rec.fsUuid)) continue;
+
+                    // Treat as recent if mounted within the last week
+                    if (rec.lastSeenMillis > 0 && rec.lastSeenMillis < lastWeek) {
+                        final StorageVolume userVol = rec.buildStorageVolume(mContext);
+                        res.add(userVol);
+                        resUuids.add(userVol.getUuid());
+                    }
+                }
+            }
+        }
+
+        // Synthesize a volume for preloaded media under demo users, so that
+        // it's scanned into MediaStore
+        if (userIsDemo) {
+            final String id = "demo";
+            final File path = Environment.getDataPreloadsMediaDirectory();
+            final boolean primary = false;
+            final boolean removable = false;
+            final boolean emulated = true;
+            final boolean allowMassStorage = false;
+            final long maxFileSize = 0;
+            final UserHandle user = new UserHandle(userId);
+            final String envState = Environment.MEDIA_MOUNTED_READ_ONLY;
+            final String description = mContext.getString(android.R.string.unknownName);
+
+            res.add(new StorageVolume(id, path, path, description, primary, removable,
+                    emulated, allowMassStorage, maxFileSize, user, id, envState));
         }
 
         if (!foundPrimary) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 2de18c3..60f0e8e 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -16,6 +16,7 @@
 
 package com.android.server.biometrics;
 
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
 
 import android.app.ActivityManager;
@@ -1013,8 +1014,13 @@
 
     private boolean isForegroundActivity(int uid, int pid) {
         try {
-            List<ActivityManager.RunningAppProcessInfo> procs =
+            final List<ActivityManager.RunningAppProcessInfo> procs =
                     ActivityManager.getService().getRunningAppProcesses();
+            if (procs == null) {
+                Slog.e(getTag(), "Processes null, defaulting to true");
+                return true;
+            }
+
             int N = procs.size();
             for (int i = 0; i < N; i++) {
                 ActivityManager.RunningAppProcessInfo proc = procs.get(i);
@@ -1206,6 +1212,11 @@
      * @return authenticator id for the calling user
      */
     protected long getAuthenticatorId(String opPackageName) {
+        if (isKeyguard(opPackageName)) {
+            // If an app tells us it's keyguard, check that it actually is.
+            checkPermission(USE_BIOMETRIC_INTERNAL);
+        }
+
         final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
         return mAuthenticatorIds.getOrDefault(userId, 0L);
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 944a95d..44c8971 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -18,8 +18,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodInfo;
 
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.server.LocalServices;
 
 import java.util.Collections;
@@ -57,6 +63,17 @@
     public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId);
 
     /**
+     * Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from
+     * the input method.
+     *
+     * @param componentName {@link ComponentName} of current app/activity.
+     * @param autofillId {@link AutofillId} of currently focused field.
+     * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object.
+     */
+    public abstract void onCreateInlineSuggestionsRequest(ComponentName componentName,
+            AutofillId autofillId, IInlineSuggestionsRequestCallback cb);
+
+    /**
      * Fake implementation of {@link InputMethodManagerInternal}.  All the methods do nothing.
      */
     private static final InputMethodManagerInternal NOP =
@@ -78,6 +95,17 @@
                 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
                     return Collections.emptyList();
                 }
+
+                @Override
+                public void onCreateInlineSuggestionsRequest(ComponentName componentName,
+                        AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+                    try {
+                        cb.onInlineSuggestionsUnsupported();
+                    } catch (RemoteException e) {
+                        Log.w("IMManagerInternal", "RemoteException calling"
+                                + " onInlineSuggestionsUnsupported: " + e);
+                    }
+                }
             };
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 471fa72..5865dc4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -109,6 +109,7 @@
 import android.view.Window;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.autofill.AutofillId;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
@@ -140,6 +141,7 @@
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
 import com.android.internal.view.IInputMethodClient;
@@ -211,6 +213,8 @@
 
     static final int MSG_SYSTEM_UNLOCK_USER = 5000;
 
+    static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
+
     static final long TIME_TO_RECONNECT = 3 * 1000;
 
     static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
@@ -1785,6 +1789,16 @@
         return settings.getEnabledInputMethodListLocked();
     }
 
+    @GuardedBy("mMethodMap")
+    private void onCreateInlineSuggestionsRequestLocked(ComponentName componentName,
+            AutofillId autofillId, IInlineSuggestionsRequestCallback callback) {
+        if (mCurMethod != null) {
+            executeOrSendMessage(mCurMethod,
+                    mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
+                            componentName, autofillId, callback));
+        }
+    }
+
     /**
      * @param imiId if null, returns enabled subtypes for the current imi
      * @return enabled subtypes of the specified imi
@@ -3874,6 +3888,21 @@
                 final int userId = msg.arg1;
                 onUnlockUser(userId);
                 return true;
+
+            // ---------------------------------------------------------------
+            case MSG_INLINE_SUGGESTIONS_REQUEST:
+                args = (SomeArgs) msg.obj;
+                final ComponentName componentName = (ComponentName) args.arg2;
+                final AutofillId autofillId = (AutofillId) args.arg3;
+                final IInlineSuggestionsRequestCallback callback =
+                        (IInlineSuggestionsRequestCallback) args.arg4;
+                try {
+                    ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(componentName,
+                            autofillId, callback);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
+                }
+                return true;
         }
         return false;
     }
@@ -4434,6 +4463,13 @@
         }
     }
 
+    private void onCreateInlineSuggestionsRequest(ComponentName componentName,
+            AutofillId autofillId, IInlineSuggestionsRequestCallback callback) {
+        synchronized (mMethodMap) {
+            onCreateInlineSuggestionsRequestLocked(componentName, autofillId, callback);
+        }
+    }
+
     private static final class LocalServiceImpl extends InputMethodManagerInternal {
         @NonNull
         private final InputMethodManagerService mService;
@@ -4464,6 +4500,12 @@
         public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
             return mService.getEnabledInputMethodListAsUser(userId);
         }
+
+        @Override
+        public void onCreateInlineSuggestionsRequest(ComponentName componentName,
+                AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+            mService.onCreateInlineSuggestionsRequest(componentName, autofillId, cb);
+        }
     }
 
     @BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 02e29e0..c13d55a 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -59,10 +59,12 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.InputChannel;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.autofill.AutofillId;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 import android.view.inputmethod.InputMethodInfo;
@@ -82,6 +84,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
@@ -187,6 +190,18 @@
                                 @UserIdInt int userId) {
                             return userIdToInputMethodInfoMapper.getAsList(userId);
                         }
+
+                        @Override
+                        public void onCreateInlineSuggestionsRequest(ComponentName componentName,
+                                AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
+                            try {
+                                //TODO(b/137800469): support multi client IMEs.
+                                cb.onInlineSuggestionsUnsupported();
+                            } catch (RemoteException e) {
+                                Log.w("MultiClientIMManager", "RemoteException calling"
+                                        + " onInlineSuggestionsUnsupported: " + e);
+                            }
+                        }
                     });
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1153fb5..99d5e4a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17962,14 +17962,6 @@
                 }
             }
             mPermissionManager.resetRuntimePermissions(pkg, nextUserId);
-            // Also delete contributed media, when requested
-            if ((flags & PackageManager.DELETE_CONTRIBUTED_MEDIA) != 0) {
-                try {
-                    MediaStore.deleteContributedMedia(mContext, ps.name, UserHandle.of(nextUserId));
-                } catch (IOException e) {
-                    Slog.w(TAG, "Failed to delete contributed media for " + ps.name, e);
-                }
-            }
         }
 
         if (outInfo != null) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 9324870..6cdfcff 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -58,6 +58,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.PackageWatchdog;
+import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
 import com.android.server.pm.Installer;
 
@@ -1008,11 +1009,19 @@
                 installerPackageName) == PackageManager.PERMISSION_GRANTED;
 
         // For now only allow rollbacks for modules or for testing.
-        return (isModule(packageName) && manageRollbacksGranted)
+        return (isRollbackWhitelisted(packageName) && manageRollbacksGranted)
             || testManageRollbacksGranted;
     }
 
     /**
+     * Returns true is this package is eligible for enabling rollback.
+     */
+    private boolean isRollbackWhitelisted(String packageName) {
+        // TODO: Remove #isModule when the white list is ready.
+        return SystemConfig.getInstance().getRollbackWhitelistedPackages().contains(packageName)
+                || isModule(packageName);
+    }
+    /**
      * Returns true if the package name is the name of a module.
      */
     private boolean isModule(String packageName) {
diff --git a/services/core/java/com/android/server/utils/TEST_MAPPING b/services/core/java/com/android/server/utils/TEST_MAPPING
new file mode 100644
index 0000000..bb7cea9
--- /dev/null
+++ b/services/core/java/com/android/server/utils/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.utils"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/utils/quota/UptcMap.java b/services/core/java/com/android/server/utils/quota/UptcMap.java
new file mode 100644
index 0000000..7b49913
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/UptcMap.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils.quota;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.SparseArrayMap;
+
+import java.util.function.Consumer;
+
+/**
+ * A SparseArrayMap of ArrayMaps, which is suitable for holding userId-packageName-tag combination
+ * (UPTC)->object associations. Tags are any desired String.
+ *
+ * @see Uptc
+ */
+class UptcMap<T> {
+    private final SparseArrayMap<ArrayMap<String, T>> mData = new SparseArrayMap<>();
+
+    public void add(int userId, @NonNull String packageName, @Nullable String tag,
+            @Nullable T obj) {
+        ArrayMap<String, T> data = mData.get(userId, packageName);
+        if (data == null) {
+            data = new ArrayMap<>();
+            mData.add(userId, packageName, data);
+        }
+        data.put(tag, obj);
+    }
+
+    public void clear() {
+        mData.clear();
+    }
+
+    public boolean contains(int userId, @NonNull String packageName) {
+        return mData.contains(userId, packageName);
+    }
+
+    public boolean contains(int userId, @NonNull String packageName, @Nullable String tag) {
+        // This structure never inserts a null ArrayMap, so if get(userId, packageName) returns
+        // null, the UPTC was never inserted.
+        ArrayMap<String, T> data = mData.get(userId, packageName);
+        return data != null && data.containsKey(tag);
+    }
+
+    /** Removes all the data for the user, if there was any. */
+    public void delete(int userId) {
+        mData.delete(userId);
+    }
+
+    /** Removes the data for the user, package, and tag, if there was any. */
+    public void delete(int userId, @NonNull String packageName, @Nullable String tag) {
+        final ArrayMap<String, T> data = mData.get(userId, packageName);
+        if (data != null) {
+            data.remove(tag);
+            if (data.size() == 0) {
+                mData.delete(userId, packageName);
+            }
+        }
+    }
+
+    /** Removes the data for the user and package, if there was any. */
+    public ArrayMap<String, T> delete(int userId, @NonNull String packageName) {
+        return mData.delete(userId, packageName);
+    }
+
+    /**
+     * Returns the set of tag -> object mappings for the given userId and packageName
+     * combination.
+     */
+    @Nullable
+    public ArrayMap<String, T> get(int userId, @NonNull String packageName) {
+        return mData.get(userId, packageName);
+    }
+
+    /** Returns the saved object for the given UPTC. */
+    @Nullable
+    public T get(int userId, @NonNull String packageName, @Nullable String tag) {
+        final ArrayMap<String, T> data = mData.get(userId, packageName);
+        return data != null ? data.get(tag) : null;
+    }
+
+    /**
+     * Returns the index for which {@link #getUserIdAtIndex(int)} would return the specified userId,
+     * or a negative number if the specified userId is not mapped.
+     */
+    public int indexOfUserId(int userId) {
+        return mData.indexOfKey(userId);
+    }
+
+    /**
+     * Returns the index for which {@link #getPackageNameAtIndex(int, int)} would return the
+     * specified userId, or a negative number if the specified userId and packageName are not mapped
+     * together.
+     */
+    public int indexOfUserIdAndPackage(int userId, @NonNull String packageName) {
+        return mData.indexOfKey(userId, packageName);
+    }
+
+    /** Returns the userId at the given index. */
+    public int getUserIdAtIndex(int index) {
+        return mData.keyAt(index);
+    }
+
+    /** Returns the package name at the given index. */
+    @NonNull
+    public String getPackageNameAtIndex(int userIndex, int packageIndex) {
+        return mData.keyAt(userIndex, packageIndex);
+    }
+
+    /** Returns the tag at the given index. */
+    @NonNull
+    public String getTagAtIndex(int userIndex, int packageIndex, int tagIndex) {
+        // This structure never inserts a null ArrayMap, so if the indices are valid, valueAt()
+        // won't return null.
+        return mData.valueAt(userIndex, packageIndex).keyAt(tagIndex);
+    }
+
+    /** Returns the size of the outer (userId) array. */
+    public int userCount() {
+        return mData.numMaps();
+    }
+
+    /** Returns the number of packages saved for a given userId. */
+    public int packageCountForUser(int userId) {
+        return mData.numElementsForKey(userId);
+    }
+
+    /** Returns the number of tags saved for a given userId-packageName combination. */
+    public int tagCountForUserAndPackage(int userId, @NonNull String packageName) {
+        final ArrayMap data = mData.get(userId, packageName);
+        return data != null ? data.size() : 0;
+    }
+
+    /** Returns the value T at the given user, package, and tag indices. */
+    @Nullable
+    public T valueAt(int userIndex, int packageIndex, int tagIndex) {
+        final ArrayMap<String, T> data = mData.valueAt(userIndex, packageIndex);
+        return data != null ? data.valueAt(tagIndex) : null;
+    }
+
+    public void forEach(Consumer<T> consumer) {
+        mData.forEach((tagMap) -> {
+            for (int i = tagMap.size() - 1; i >= 0; --i) {
+                consumer.accept(tagMap.valueAt(i));
+            }
+        });
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e3ea2c5..4667eab 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4955,7 +4955,11 @@
         // Re-parent IME's SurfaceControl when MagnificationSpec changed.
         updateImeParent();
 
-        applyMagnificationSpec(getPendingTransaction(), spec);
+        if (spec.scale != 1.0) {
+            applyMagnificationSpec(getPendingTransaction(), spec);
+        } else {
+            clearMagnificationSpec(getPendingTransaction());
+        }
         getPendingTransaction().apply();
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d73cb50f..06cea37 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -244,6 +244,8 @@
     protected final Rect mTmpRect = new Rect();
     final Rect mTmpPrevBounds = new Rect();
 
+    private MagnificationSpec mLastMagnificationSpec;
+
     WindowContainer(WindowManagerService wms) {
         mWmService = wms;
         mPendingTransaction = wms.mTransactionFactory.get();
@@ -1726,6 +1728,7 @@
         if (shouldMagnify()) {
             t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale)
                     .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY);
+            mLastMagnificationSpec = spec;
         } else {
             for (int i = 0; i < mChildren.size(); i++) {
                 mChildren.get(i).applyMagnificationSpec(t, spec);
@@ -1733,6 +1736,17 @@
         }
     }
 
+    void clearMagnificationSpec(Transaction t) {
+        if (mLastMagnificationSpec != null) {
+            t.setMatrix(mSurfaceControl, 1, 0, 0, 1)
+                .setPosition(mSurfaceControl, 0, 0);
+        }
+        mLastMagnificationSpec = null;
+        for (int i = 0; i < mChildren.size(); i++) {
+            mChildren.get(i).clearMagnificationSpec(t);
+        }
+    }
+
     void prepareSurfaces() {
         // If a leash has been set when the transaction was committed, then the leash reparent has
         // been committed.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7d6b0c9..a1e0237 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -105,6 +105,7 @@
 import com.android.server.gpu.GpuService;
 import com.android.server.hdmi.HdmiControlService;
 import com.android.server.incident.IncidentCompanionService;
+import com.android.server.incremental.IncrementalManagerService;
 import com.android.server.input.InputManagerService;
 import com.android.server.inputmethod.InputMethodManagerService;
 import com.android.server.inputmethod.InputMethodSystemProperty;
@@ -324,6 +325,7 @@
     private ContentResolver mContentResolver;
     private EntropyMixer mEntropyMixer;
     private DataLoaderManagerService mDataLoaderManagerService;
+    private IncrementalManagerService mIncrementalManagerService;
 
     private boolean mOnlyCore;
     private boolean mFirstBoot;
@@ -706,6 +708,11 @@
                 DataLoaderManagerService.class);
         t.traceEnd();
 
+        // Incremental service needs to be started before package manager
+        t.traceBegin("StartIncrementalManagerService");
+        mIncrementalManagerService = IncrementalManagerService.start(mSystemContext);
+        t.traceEnd();
+
         // Power manager needs to be started early because other services need it.
         // Native daemons may be watching for it to be registered so it must be ready
         // to handle incoming binder calls immediately (including being able to verify
@@ -2066,6 +2073,12 @@
         mPackageManagerService.systemReady();
         t.traceEnd();
 
+        if (mIncrementalManagerService != null) {
+            t.traceBegin("MakeIncrementalManagerServiceReady");
+            mIncrementalManagerService.systemReady();
+            t.traceEnd();
+        }
+
         t.traceBegin("MakeDisplayManagerServiceReady");
         try {
             // TODO: use boot phase and communicate these flags some other way
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 37f3388..cab5286 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -1998,6 +1998,27 @@
         }
     }
 
+    /**
+     * Gets the total capacity of SMS storage on RUIM and SIM cards
+     *
+     * @return the total capacity count of SMS on RUIM and SIM cards
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public int getSmsCapacityOnIcc() {
+        int ret = 0;
+        try {
+            ISms iccISms = getISmsService();
+            if (iccISms != null) {
+                ret = iccISms.getSmsCapacityOnIccForSubscriber(getSubscriptionId());
+            }
+        } catch (RemoteException ex) {
+            //ignore it
+        }
+        return ret;
+    }
+
     // see SmsMessage.getStatusOnIcc
 
     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index ac4c8ec..9f4d066 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -594,4 +594,12 @@
      * @return true for success, false otherwise.
      */
     boolean setSmscAddressOnIccEfForSubscriber(String smsc, int subId, String callingPackage);
+
+    /**
+     * Get the capacity count of sms on Icc card.
+     *
+     * @param subId for subId which getSmsCapacityOnIcc is queried.
+     * @return capacity of ICC
+     */
+    int getSmsCapacityOnIccForSubscriber(int subId);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 9865f76..2430d82 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -211,4 +211,9 @@
             String smsc, int subId, String callingPackage) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public int getSmsCapacityOnIccForSubscriber(int subId) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 0208c3a..9d913b9 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -16,6 +16,7 @@
 
 package android.test.mock;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
@@ -211,6 +212,15 @@
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * {@inheritDoc Context#getCrateDir()}
+     * @hide
+     */
+    @Override
+    public File getCrateDir(@NonNull String crateId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public File getNoBackupFilesDir() {
         throw new UnsupportedOperationException();
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index abe6c61..daa85bd 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -1098,4 +1098,28 @@
             InstallUtils.dropShellPermissionIdentity();
         }
     }
+
+    /**
+     * Test we can't enable rollback for non-whitelisted app without
+     * TEST_MANAGE_ROLLBACKS permission
+     */
+    @Test
+    public void testNonRollbackWhitelistedApp() throws Exception {
+        try {
+            InstallUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
+
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            Thread.sleep(TimeUnit.SECONDS.toMillis(2));
+            assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
+        } finally {
+            InstallUtils.dropShellPermissionIdentity();
+        }
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 7b289d8..879ac64 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -40,6 +40,7 @@
 import com.android.cts.install.lib.Uninstall;
 import com.android.cts.rollback.lib.Rollback;
 import com.android.cts.rollback.lib.RollbackUtils;
+import com.android.internal.R;
 
 import libcore.io.IoUtils;
 
@@ -341,6 +342,37 @@
                         getNetworkStackPackageName())).isNull();
     }
 
+    private static String getModuleMetadataPackageName() {
+        return InstrumentationRegistry.getInstrumentation().getContext()
+                .getResources().getString(R.string.config_defaultModuleMetadataProvider);
+    }
+
+    @Test
+    public void testRollbackWhitelistedApp_Phase1() throws Exception {
+        // Remove available rollbacks
+        String pkgName = getModuleMetadataPackageName();
+        RollbackUtils.getRollbackManager().expireRollbackForPackage(pkgName);
+        assertThat(RollbackUtils.getAvailableRollback(pkgName)).isNull();
+
+        // Overwrite existing permissions. We don't want TEST_MANAGE_ROLLBACKS which allows us
+        // to enable rollback for any app
+        InstallUtils.adoptShellPermissionIdentity(
+                Manifest.permission.INSTALL_PACKAGES,
+                Manifest.permission.MANAGE_ROLLBACKS);
+
+        // Re-install a whitelisted app with rollbacks enabled
+        String filePath = InstrumentationRegistry.getInstrumentation().getContext()
+                .getPackageManager().getPackageInfo(pkgName, 0).applicationInfo.sourceDir;
+        TestApp app = new TestApp("ModuleMetadata", pkgName, -1, false, new File(filePath));
+        Install.single(app).setStaged().setEnableRollback()
+                .addInstallFlags(PackageManager.INSTALL_REPLACE_EXISTING).commit();
+    }
+
+    @Test
+    public void testRollbackWhitelistedApp_Phase2() throws Exception {
+        assertThat(RollbackUtils.getAvailableRollback(getModuleMetadataPackageName())).isNotNull();
+    }
+
     private static void runShellCommand(String cmd) {
         ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index e4a8feb..07d829d 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -175,6 +175,16 @@
         runPhase("testPreviouslyAbandonedRollbacks_Phase3");
     }
 
+    /**
+     * Tests we can enable rollback for a whitelisted app.
+     */
+    @Test
+    public void testRollbackWhitelistedApp() throws Exception {
+        runPhase("testRollbackWhitelistedApp_Phase1");
+        getDevice().reboot();
+        runPhase("testRollbackWhitelistedApp_Phase2");
+    }
+
     private void crashProcess(String processName, int numberOfCrashes) throws Exception {
         String pid = "";
         String lastPid = "invalid";
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 7733761..15c3278 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -21,6 +21,7 @@
     name: "stats-log-api-gen",
     srcs: [
         "Collation.cpp",
+        "atoms_info_writer.cpp",
         "java_writer.cpp",
         "java_writer_q.cpp",
         "main.cpp",
@@ -102,13 +103,19 @@
 cc_library {
     name: "libstatslog",
     host_supported: true,
-    generated_sources: ["statslog.cpp"],
-    generated_headers: ["statslog.h"],
+    generated_sources: [
+        "statslog.cpp",
+    ],
+    generated_headers: [
+        "statslog.h"
+    ],
     cflags: [
         "-Wall",
         "-Werror",
     ],
-    export_generated_headers: ["statslog.h"],
+    export_generated_headers: [
+        "statslog.h"
+    ],
     shared_libs: [
         "liblog",
         "libcutils",
@@ -127,3 +134,4 @@
         },
     },
 }
+
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 373adca..fa55601 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -379,6 +379,7 @@
   int errorCount = 0;
   const bool dbg = false;
 
+  int maxPushedAtomId = 2;
   for (int i = 0; i < descriptor->field_count(); i++) {
     const FieldDescriptor *atomField = descriptor->field(i);
 
@@ -447,8 +448,14 @@
         }
         atoms->non_chained_decls.insert(nonChainedAtomDecl);
     }
+
+    if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
+        maxPushedAtomId = atomDecl.code;
+    }
   }
 
+  atoms->maxPushedAtomId = maxPushedAtomId;
+
   if (dbg) {
     printf("signatures = [\n");
     for (map<vector<java_type_t>, set<string>>::const_iterator it =
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 44746c9..3efdd52 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -111,6 +111,7 @@
     set<AtomDecl> decls;
     set<AtomDecl> non_chained_decls;
     map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules;
+    int maxPushedAtomId;
 };
 
 /**
@@ -123,4 +124,4 @@
 }  // namespace android
 
 
-#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
\ No newline at end of file
+#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
new file mode 100644
index 0000000..54a9982
--- /dev/null
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "atoms_info_writer.h"
+#include "utils.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+namespace android {
+namespace stats_log_api_gen {
+
+static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) {
+    fprintf(out, "struct StateAtomFieldOptions {\n");
+    fprintf(out, "  std::vector<int> primaryFields;\n");
+    fprintf(out, "  int exclusiveField;\n");
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "struct AtomsInfo {\n");
+    fprintf(out,
+            "  const static std::set<int> "
+            "kTruncatingTimestampAtomBlackList;\n");
+    fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
+    fprintf(out,
+            "  const static std::set<int> kAtomsWithAttributionChain;\n");
+    fprintf(out,
+            "  const static std::map<int, StateAtomFieldOptions> "
+            "kStateAtomsFieldOptions;\n");
+    fprintf(out,
+            "  const static std::map<int, std::vector<int>> "
+            "kBytesFieldAtoms;\n");
+    fprintf(out,
+            "  const static std::set<int> kWhitelistedAtoms;\n");
+    fprintf(out, "};\n");
+    fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId);
+
+}
+
+static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
+    std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
+                                                 "audio_state_changed",
+                                                 "call_state_changed",
+                                                 "phone_signal_strength_changed",
+                                                 "mobile_bytes_transfer_by_fg_bg",
+                                                 "mobile_bytes_transfer"};
+    fprintf(out,
+            "const std::set<int> "
+            "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
+    for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin();
+         blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) {
+            fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str());
+    }
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    fprintf(out,
+            "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        for (vector<AtomField>::const_iterator field = atom->fields.begin();
+             field != atom->fields.end(); field++) {
+            if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+                string constant = make_constant_name(atom->name);
+                fprintf(out, " %s,\n", constant.c_str());
+                break;
+            }
+        }
+    }
+
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    fprintf(out,
+            "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->whitelisted) {
+            string constant = make_constant_name(atom->name);
+            fprintf(out, " %s,\n", constant.c_str());
+        }
+    }
+
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
+    fprintf(out, "  std::map<int, int> uidField;\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->uidField == 0) {
+            continue;
+        }
+        fprintf(out,
+                "\n    // Adding uid field for atom "
+                "(%d)%s\n",
+                atom->code, atom->name.c_str());
+        fprintf(out, "    uidField[static_cast<int>(%s)] = %d;\n",
+                make_constant_name(atom->name).c_str(), atom->uidField);
+    }
+
+    fprintf(out, "    return uidField;\n");
+    fprintf(out, "};\n");
+
+    fprintf(out,
+            "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
+            "getAtomUidField();\n");
+
+    fprintf(out,
+            "static std::map<int, StateAtomFieldOptions> "
+            "getStateAtomFieldOptions() {\n");
+    fprintf(out, "    std::map<int, StateAtomFieldOptions> options;\n");
+    fprintf(out, "    StateAtomFieldOptions opt;\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
+            continue;
+        }
+        fprintf(out,
+                "\n    // Adding primary and exclusive fields for atom "
+                "(%d)%s\n",
+                atom->code, atom->name.c_str());
+        fprintf(out, "    opt.primaryFields.clear();\n");
+        for (const auto& field : atom->primaryFields) {
+            fprintf(out, "    opt.primaryFields.push_back(%d);\n", field);
+        }
+
+        fprintf(out, "    opt.exclusiveField = %d;\n", atom->exclusiveField);
+        fprintf(out, "    options[static_cast<int>(%s)] = opt;\n",
+                make_constant_name(atom->name).c_str());
+    }
+
+    fprintf(out, "    return options;\n");
+    fprintf(out, "}\n");
+
+    fprintf(out,
+            "const std::map<int, StateAtomFieldOptions> "
+            "AtomsInfo::kStateAtomsFieldOptions = "
+            "getStateAtomFieldOptions();\n");
+
+    fprintf(out,
+            "static std::map<int, std::vector<int>> "
+            "getBinaryFieldAtoms() {\n");
+    fprintf(out, "    std::map<int, std::vector<int>> options;\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->binaryFields.size() == 0) {
+            continue;
+        }
+        fprintf(out,
+                "\n    // Adding binary fields for atom "
+                "(%d)%s\n",
+                atom->code, atom->name.c_str());
+
+        for (const auto& field : atom->binaryFields) {
+            fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
+                    make_constant_name(atom->name).c_str(), field);
+        }
+    }
+
+    fprintf(out, "    return options;\n");
+    fprintf(out, "}\n");
+
+    fprintf(out,
+            "const std::map<int, std::vector<int>> "
+            "AtomsInfo::kBytesFieldAtoms = "
+            "getBinaryFieldAtoms();\n");
+
+}
+
+int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespaceStr) {
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+    fprintf(out, "#pragma once\n");
+    fprintf(out, "\n");
+    fprintf(out, "#include <vector>\n");
+    fprintf(out, "#include <map>\n");
+    fprintf(out, "#include <set>\n");
+    fprintf(out, "\n");
+
+    write_namespace(out, namespaceStr);
+
+    write_atoms_info_header_body(out, atoms);
+
+    fprintf(out, "\n");
+    write_closing_namespace(out, namespaceStr);
+
+    return 0;
+}
+
+int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr,
+        const string& importHeader, const string& statslogHeader) {
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+    fprintf(out, "#include <%s>\n", importHeader.c_str());
+    fprintf(out, "#include <%s>\n", statslogHeader.c_str());
+    fprintf(out, "\n");
+
+    write_namespace(out, namespaceStr);
+
+    write_atoms_info_cpp_body(out, atoms);
+
+    // Print footer
+    fprintf(out, "\n");
+    write_closing_namespace(out, namespaceStr);
+
+    return 0;
+}
+
+}  // namespace stats_log_api_gen
+}  // namespace android
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
new file mode 100644
index 0000000..bc67782
--- /dev/null
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Collation.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace stats_log_api_gen {
+
+using namespace std;
+
+int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
+        const string& importHeader, const string& statslogHeader
+);
+
+int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
+
+}  // namespace stats_log_api_gen
+}  // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index bc6d82a..ad171da 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1,6 +1,7 @@
 
 
 #include "Collation.h"
+#include "atoms_info_writer.h"
 #if !defined(STATS_SCHEMA_LEGACY)
 #include "java_writer.h"
 #endif
@@ -18,8 +19,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "android-base/strings.h"
-
 using namespace google::protobuf;
 using namespace std;
 
@@ -28,152 +27,6 @@
 
 using android::os::statsd::Atom;
 
-static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) {
-    std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
-                                                 "audio_state_changed",
-                                                 "call_state_changed",
-                                                 "phone_signal_strength_changed",
-                                                 "mobile_bytes_transfer_by_fg_bg",
-                                                 "mobile_bytes_transfer"};
-    fprintf(out,
-            "const std::set<int> "
-            "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
-    for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin();
-         blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) {
-            fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str());
-    }
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
-
-    fprintf(out,
-            "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
-        for (vector<AtomField>::const_iterator field = atom->fields.begin();
-             field != atom->fields.end(); field++) {
-            if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                string constant = make_constant_name(atom->name);
-                fprintf(out, " %s,\n", constant.c_str());
-                break;
-            }
-        }
-    }
-
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
-
-    fprintf(out,
-            "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
-        if (atom->whitelisted) {
-            string constant = make_constant_name(atom->name);
-            fprintf(out, " %s,\n", constant.c_str());
-        }
-    }
-
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
-
-    fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
-    fprintf(out, "  std::map<int, int> uidField;\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
-        if (atom->uidField == 0) {
-            continue;
-        }
-        fprintf(out,
-                "\n    // Adding uid field for atom "
-                "(%d)%s\n",
-                atom->code, atom->name.c_str());
-        fprintf(out, "    uidField[static_cast<int>(%s)] = %d;\n",
-                make_constant_name(atom->name).c_str(), atom->uidField);
-    }
-
-    fprintf(out, "    return uidField;\n");
-    fprintf(out, "};\n");
-
-    fprintf(out,
-            "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
-            "getAtomUidField();\n");
-
-    fprintf(out,
-            "static std::map<int, StateAtomFieldOptions> "
-            "getStateAtomFieldOptions() {\n");
-    fprintf(out, "    std::map<int, StateAtomFieldOptions> options;\n");
-    fprintf(out, "    StateAtomFieldOptions opt;\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
-        if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
-            continue;
-        }
-        fprintf(out,
-                "\n    // Adding primary and exclusive fields for atom "
-                "(%d)%s\n",
-                atom->code, atom->name.c_str());
-        fprintf(out, "    opt.primaryFields.clear();\n");
-        for (const auto& field : atom->primaryFields) {
-            fprintf(out, "    opt.primaryFields.push_back(%d);\n", field);
-        }
-
-        fprintf(out, "    opt.exclusiveField = %d;\n", atom->exclusiveField);
-        fprintf(out, "    options[static_cast<int>(%s)] = opt;\n",
-                make_constant_name(atom->name).c_str());
-    }
-
-    fprintf(out, "    return options;\n");
-    fprintf(out, "}\n");
-
-    fprintf(out,
-            "const std::map<int, StateAtomFieldOptions> "
-            "AtomsInfo::kStateAtomsFieldOptions = "
-            "getStateAtomFieldOptions();\n");
-
-    fprintf(out,
-            "static std::map<int, std::vector<int>> "
-            "getBinaryFieldAtoms() {\n");
-    fprintf(out, "    std::map<int, std::vector<int>> options;\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
-        if (atom->binaryFields.size() == 0) {
-            continue;
-        }
-        fprintf(out,
-                "\n    // Adding binary fields for atom "
-                "(%d)%s\n",
-                atom->code, atom->name.c_str());
-
-        for (const auto& field : atom->binaryFields) {
-            fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
-                    make_constant_name(atom->name).c_str(), field);
-        }
-    }
-
-    fprintf(out, "    return options;\n");
-    fprintf(out, "}\n");
-
-    fprintf(out,
-            "const std::map<int, std::vector<int>> "
-            "AtomsInfo::kBytesFieldAtoms = "
-            "getBinaryFieldAtoms();\n");
-}
-
-// Writes namespaces for the cpp and header files, returning the number of namespaces written.
-void write_namespace(FILE* out, const string& cppNamespaces) {
-    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
-    for (string cppNamespace : cppNamespaceVec) {
-        fprintf(out, "namespace %s {\n", cppNamespace.c_str());
-    }
-}
-
-// Writes namespace closing brackets for cpp and header files.
-void write_closing_namespace(FILE* out, const string& cppNamespaces) {
-    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
-    for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
-        fprintf(out, "} // namespace %s\n", it->c_str());
-    }
-}
-
 static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
                                const string& moduleName, const string& cppNamespace,
                                const string& importHeader) {
@@ -202,11 +55,6 @@
     fprintf(out, "const static bool kStatsdEnabled = false;\n");
     fprintf(out, "#endif\n");
 
-    // AtomsInfo is only used by statsd internally and is not needed for other modules.
-    if (moduleName == DEFAULT_MODULE_NAME) {
-        write_atoms_info_cpp(out, atoms);
-    }
-
     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
     fprintf(out, "static std::mutex mLogdRetryMutex;\n");
@@ -543,42 +391,6 @@
     return 0;
 }
 
-static void write_cpp_usage(
-    FILE* out, const string& method_name, const string& atom_code_name,
-    const AtomDecl& atom, const AtomDecl &attributionDecl) {
-    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(),
-            atom_code_name.c_str());
-
-    for (vector<AtomField>::const_iterator field = atom.fields.begin();
-            field != atom.fields.end(); field++) {
-        if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            for (auto chainField : attributionDecl.fields) {
-                if (chainField.javaType == JAVA_TYPE_STRING) {
-                    fprintf(out, ", const std::vector<%s>& %s",
-                         cpp_type_name(chainField.javaType),
-                         chainField.name.c_str());
-                } else {
-                    fprintf(out, ", const %s* %s, size_t %s_length",
-                         cpp_type_name(chainField.javaType),
-                         chainField.name.c_str(), chainField.name.c_str());
-                }
-            }
-        } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
-            fprintf(out, ", const std::map<int, int32_t>& %s_int"
-                         ", const std::map<int, int64_t>& %s_long"
-                         ", const std::map<int, char const*>& %s_str"
-                         ", const std::map<int, float>& %s_float",
-                         field->name.c_str(),
-                         field->name.c_str(),
-                         field->name.c_str(),
-                         field->name.c_str());
-        } else {
-            fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
-        }
-    }
-    fprintf(out, ");\n");
-}
-
 static void write_cpp_method_header(
         FILE* out,
         const string& method_name,
@@ -645,45 +457,8 @@
     fprintf(out, " * API For logging statistics events.\n");
     fprintf(out, " */\n");
     fprintf(out, "\n");
-    fprintf(out, "/**\n");
-    fprintf(out, " * Constants for atom codes.\n");
-    fprintf(out, " */\n");
-    fprintf(out, "enum {\n");
 
-    std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
-    build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
-
-    size_t i = 0;
-    int maxPushedAtomId = 2;
-    // Print atom constants
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-        atom != atoms.decls.end(); atom++) {
-        // Skip if the atom is not needed for the module.
-        if (!atom_needed_for_module(*atom, moduleName)) {
-            continue;
-        }
-        string constant = make_constant_name(atom->name);
-        fprintf(out, "\n");
-        fprintf(out, "    /**\n");
-        fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
-        write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
-
-        auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
-        if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
-            write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
-                attributionDecl);
-        }
-        fprintf(out, "     */\n");
-        char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
-        fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
-        if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
-            maxPushedAtomId = atom->code;
-        }
-        i++;
-    }
-    fprintf(out, "\n");
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
+    write_native_atom_constants(out, atoms, attributionDecl, moduleName);
 
     // Print constants for the enum values.
     fprintf(out, "//\n");
@@ -723,36 +498,6 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
-    // This metadata is only used by statsd, which uses the default libstatslog.
-    if (moduleName == DEFAULT_MODULE_NAME) {
-
-        fprintf(out, "struct StateAtomFieldOptions {\n");
-        fprintf(out, "  std::vector<int> primaryFields;\n");
-        fprintf(out, "  int exclusiveField;\n");
-        fprintf(out, "};\n");
-        fprintf(out, "\n");
-
-        fprintf(out, "struct AtomsInfo {\n");
-        fprintf(out,
-                "  const static std::set<int> "
-                "kTruncatingTimestampAtomBlackList;\n");
-        fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
-        fprintf(out,
-                "  const static std::set<int> kAtomsWithAttributionChain;\n");
-        fprintf(out,
-                "  const static std::map<int, StateAtomFieldOptions> "
-                "kStateAtomsFieldOptions;\n");
-        fprintf(out,
-                "  const static std::map<int, std::vector<int>> "
-                "kBytesFieldAtoms;");
-        fprintf(out,
-                "  const static std::set<int> kWhitelistedAtoms;\n");
-        fprintf(out, "};\n");
-
-        fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
-                maxPushedAtomId);
-    }
-
     // Print write methods
     fprintf(out, "//\n");
     fprintf(out, "// Write methods\n");
@@ -1235,15 +980,21 @@
     fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
     fprintf(stderr, "\n");
     fprintf(stderr, "OPTIONS\n");
-    fprintf(stderr, "  --cpp FILENAME       the header file to output\n");
-    fprintf(stderr, "  --header FILENAME    the cpp file to output\n");
+    fprintf(stderr, "  --cpp FILENAME       the header file to output for write helpers\n");
+    fprintf(stderr, "  --header FILENAME    the cpp file to output for write helpers\n");
+    fprintf(stderr,
+            "  --atomsInfoCpp FILENAME       the header file to output for statsd metadata\n");
+    fprintf(stderr, "  --atomsInfoHeader FILENAME    the cpp file to output for statsd metadata\n");
     fprintf(stderr, "  --help               this message\n");
     fprintf(stderr, "  --java FILENAME      the java file to output\n");
     fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
     fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
     fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
     fprintf(stderr, "                                    comma separated namespace of the files\n");
-    fprintf(stderr, "  --importHeader NAME  required for cpp/jni to say which header to import\n");
+    fprintf(stderr,"  --importHeader NAME  required for cpp/jni to say which header to import "
+            "for write helpers\n");
+    fprintf(stderr,"  --atomsInfoImportHeader NAME  required for cpp to say which header to import "
+            "for statsd metadata\n");
     fprintf(stderr, "  --javaPackage PACKAGE             the package for the java file.\n");
     fprintf(stderr, "                                    required for java with module\n");
     fprintf(stderr, "  --javaClass CLASS    the class name of the java class.\n");
@@ -1260,10 +1011,13 @@
     string headerFilename;
     string javaFilename;
     string jniFilename;
+    string atomsInfoCppFilename;
+    string atomsInfoHeaderFilename;
 
     string moduleName = DEFAULT_MODULE_NAME;
     string cppNamespace = DEFAULT_CPP_NAMESPACE;
     string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
+    string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT;
     string javaPackage = DEFAULT_JAVA_PACKAGE;
     string javaClass = DEFAULT_JAVA_CLASS;
 
@@ -1335,14 +1089,38 @@
                 return 1;
             }
             javaClass = argv[index];
+        } else if (0 == strcmp("--atomsInfoHeader", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            atomsInfoHeaderFilename = argv[index];
+        } else if (0 == strcmp("--atomsInfoCpp", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            atomsInfoCppFilename = argv[index];
+        } else if (0 == strcmp("--atomsInfoImportHeader", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            atomsInfoCppHeaderImport = argv[index];
         }
+
         index++;
     }
 
     if (cppFilename.size() == 0
             && headerFilename.size() == 0
             && javaFilename.size() == 0
-            && jniFilename.size() == 0) {
+            && jniFilename.size() == 0
+            && atomsInfoHeaderFilename.size() == 0
+            && atomsInfoCppFilename.size() == 0) {
         print_usage();
         return 1;
     }
@@ -1359,6 +1137,30 @@
     collate_atom(android::os::statsd::AttributionNode::descriptor(),
                  &attributionDecl, &attributionSignature);
 
+    // Write the atoms info .cpp file
+    if (atomsInfoCppFilename.size() != 0) {
+        FILE* out = fopen(atomsInfoCppFilename.c_str(), "w");
+        if (out == NULL) {
+            fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str());
+            return 1;
+        }
+        errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
+            out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport);
+        fclose(out);
+    }
+
+    // Write the atoms info .h file
+    if (atomsInfoHeaderFilename.size() != 0) {
+        FILE* out = fopen(atomsInfoHeaderFilename.c_str(), "w");
+        if (out == NULL) {
+            fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoHeaderFilename.c_str());
+            return 1;
+        }
+        errorCount = android::stats_log_api_gen::write_atoms_info_header(out, atoms, cppNamespace);
+        fclose(out);
+    }
+
+
     // Write the .cpp file
     if (cppFilename.size() != 0) {
         FILE* out = fopen(cppFilename.c_str(), "w");
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 141861d..d6cfe95 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -16,9 +16,19 @@
 
 #include "utils.h"
 
+#include "android-base/strings.h"
+
 namespace android {
 namespace stats_log_api_gen {
 
+static void build_non_chained_decl_map(const Atoms& atoms,
+                                std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
+    for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
+        atom != atoms.non_chained_decls.end(); atom++) {
+        decl_map->insert(std::make_pair(atom->code, atom));
+    }
+}
+
 /**
  * Turn lower and camel case into upper case with underscores.
  */
@@ -102,14 +112,98 @@
     return modules.find(moduleName) != modules.end();
 }
 
-void build_non_chained_decl_map(const Atoms& atoms,
-                                std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
-    for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
-        atom != atoms.non_chained_decls.end(); atom++) {
-        decl_map->insert(std::make_pair(atom->code, atom));
+// Native
+// Writes namespaces for the cpp and header files, returning the number of namespaces written.
+void write_namespace(FILE* out, const string& cppNamespaces) {
+    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    for (string cppNamespace : cppNamespaceVec) {
+        fprintf(out, "namespace %s {\n", cppNamespace.c_str());
     }
 }
 
+// Writes namespace closing brackets for cpp and header files.
+void write_closing_namespace(FILE* out, const string& cppNamespaces) {
+    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
+        fprintf(out, "} // namespace %s\n", it->c_str());
+    }
+}
+
+static void write_cpp_usage(
+    FILE* out, const string& method_name, const string& atom_code_name,
+    const AtomDecl& atom, const AtomDecl &attributionDecl) {
+    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(),
+            atom_code_name.c_str());
+
+    for (vector<AtomField>::const_iterator field = atom.fields.begin();
+            field != atom.fields.end(); field++) {
+        if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+            for (auto chainField : attributionDecl.fields) {
+                if (chainField.javaType == JAVA_TYPE_STRING) {
+                    fprintf(out, ", const std::vector<%s>& %s",
+                         cpp_type_name(chainField.javaType),
+                         chainField.name.c_str());
+                } else {
+                    fprintf(out, ", const %s* %s, size_t %s_length",
+                         cpp_type_name(chainField.javaType),
+                         chainField.name.c_str(), chainField.name.c_str());
+                }
+            }
+        } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
+            fprintf(out, ", const std::map<int, int32_t>& %s_int"
+                         ", const std::map<int, int64_t>& %s_long"
+                         ", const std::map<int, char const*>& %s_str"
+                         ", const std::map<int, float>& %s_float",
+                         field->name.c_str(),
+                         field->name.c_str(),
+                         field->name.c_str(),
+                         field->name.c_str());
+        } else {
+            fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
+        }
+    }
+    fprintf(out, ");\n");
+}
+
+void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+        const string& moduleName) {
+    fprintf(out, "/**\n");
+    fprintf(out, " * Constants for atom codes.\n");
+    fprintf(out, " */\n");
+    fprintf(out, "enum {\n");
+
+    std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
+    build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
+
+    size_t i = 0;
+    // Print atom constants
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+        atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
+        string constant = make_constant_name(atom->name);
+        fprintf(out, "\n");
+        fprintf(out, "    /**\n");
+        fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
+        write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
+
+        auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
+        if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
+            write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
+                attributionDecl);
+        }
+        fprintf(out, "     */\n");
+        char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
+        fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
+        i++;
+    }
+    fprintf(out, "\n");
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+}
+
 // Java
 void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) {
     fprintf(out, "    // Constants for atom codes.\n");
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index e860fa9..a89387f 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -33,6 +33,7 @@
 const string DEFAULT_MODULE_NAME = "DEFAULT";
 const string DEFAULT_CPP_NAMESPACE = "android,util";
 const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+const string DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT = "atoms_info.h";
 const string DEFAULT_JAVA_PACKAGE = "android.util";
 const string DEFAULT_JAVA_CLASS = "StatsLogInternal";
 
@@ -49,8 +50,14 @@
 
 bool signature_needed_for_module(const set<string>& modules, const string& moduleName);
 
-void build_non_chained_decl_map(const Atoms& atoms,
-                                std::map<int, set<AtomDecl>::const_iterator>* decl_map);
+// Common Native helpers
+void write_namespace(FILE* out, const string& cppNamespaces);
+
+void write_closing_namespace(FILE* out, const string& cppNamespaces);
+
+void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+        const string& moduleName
+);
 
 // Common Java helpers.
 void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName);