Merge "Update comments for smart selection actions."
diff --git a/api/current.txt b/api/current.txt
index 568f4c4..f750e33 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -41867,6 +41867,9 @@
     field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+    field public static final java.lang.String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
+    field public static final java.lang.String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
+    field public static final java.lang.String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
     field public static final java.lang.String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final java.lang.String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
@@ -44486,6 +44489,11 @@
     method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
   }
 
+  public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan {
+    ctor public LineHeightSpan.Standard(int);
+    method public void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
+  }
+
   public static abstract interface LineHeightSpan.WithDensity implements android.text.style.LineHeightSpan {
     method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt, android.text.TextPaint);
   }
diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java
index 50ee5f3..2742ae0 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -16,11 +16,16 @@
 
 package android.text.style;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Px;
 import android.graphics.Paint;
 import android.text.TextPaint;
 
+import com.android.internal.util.Preconditions;
+
 /**
- * The classes that affect the height of the line should implement this interface.
+ * The classes that affect the line height of paragraph should implement this interface.
  */
 public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan {
     /**
@@ -38,8 +43,8 @@
             Paint.FontMetricsInt fm);
 
     /**
-     * The classes that affect the height of the line with respect to density, should implement this
-     * interface.
+     * The classes that affect the line height of paragraph with respect to density,
+     * should implement this interface.
      */
     public interface WithDensity extends LineHeightSpan {
 
@@ -57,4 +62,38 @@
                 int spanstartv, int lineHeight,
                 Paint.FontMetricsInt fm, TextPaint paint);
     }
+
+    /**
+     * Default implementation of the {@link LineHeightSpan}, which changes the line height of the
+     * attached paragraph.
+     * <p>
+     * LineHeightSpan will change the line height of the entire paragraph, even though it
+     * covers only part of the paragraph.
+     * </p>
+     */
+    class Standard implements LineHeightSpan {
+
+        private final @Px int mHeight;
+        /**
+         * Set the line height of the paragraph to <code>height</code> physical pixels.
+         */
+        public Standard(@Px @IntRange(from = 1) int height) {
+            Preconditions.checkArgument(height > 0, "Height:" + height + "must be positive");
+            mHeight = height;
+        }
+
+        @Override
+        public void chooseHeight(@NonNull CharSequence text, int start, int end,
+                int spanstartv, int lineHeight,
+                @NonNull Paint.FontMetricsInt fm) {
+            final int originHeight = fm.descent - fm.ascent;
+            // If original height is not positive, do nothing.
+            if (originHeight <= 0) {
+                return;
+            }
+            final float ratio = mHeight * 1.0f / originHeight;
+            fm.descent = Math.round(fm.descent * ratio);
+            fm.ascent = fm.descent - mHeight;
+        }
+    }
 }
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 3280d47..8e2786d 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -215,11 +215,11 @@
             final Point windowCoords = getCurrentClampedWindowCoordinates();
             final InternalPopupWindow currentWindowInstance = mWindow;
             sPixelCopyHandlerThread.getThreadHandler().post(() -> {
-                if (mWindow != currentWindowInstance) {
-                    // The magnifier was dismissed (and maybe shown again) in the meantime.
-                    return;
-                }
                 synchronized (mLock) {
+                    if (mWindow != currentWindowInstance) {
+                        // The magnifier was dismissed (and maybe shown again) in the meantime.
+                        return;
+                    }
                     mWindow.setContentPositionForNextDraw(windowCoords.x, windowCoords.y);
                 }
             });
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index d582983..edce305 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -72,6 +72,7 @@
         "libft2",
         "libminikin",
         "libandroidfw",
+        "libcrypto",
     ],
     static_libs: [
         "libEGL_blobCache",
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 6700748..073b481 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -18,6 +18,8 @@
 #include <algorithm>
 #include <log/log.h>
 #include <thread>
+#include <array>
+#include <openssl/sha.h>
 #include "FileBlobCache.h"
 #include "Properties.h"
 #include "utils/TraceUtils.h"
@@ -41,7 +43,40 @@
     return sCache;
 }
 
-void ShaderCache::initShaderDiskCache() {
+bool ShaderCache::validateCache(const void* identity, ssize_t size) {
+    if (nullptr == identity && size == 0)
+        return true;
+
+    if (nullptr == identity || size < 0) {
+        if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) {
+            ALOGW("ShaderCache::validateCache invalid cache identity");
+        }
+        mBlobCache->clear();
+        return false;
+    }
+
+    SHA256_CTX ctx;
+    SHA256_Init(&ctx);
+
+    SHA256_Update(&ctx, identity, size);
+    mIDHash.resize(SHA256_DIGEST_LENGTH);
+    SHA256_Final(mIDHash.data(), &ctx);
+
+    std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
+    auto key = sIDKey;
+    auto loaded = mBlobCache->get(&key, sizeof(key), hash.data(), hash.size());
+
+    if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin()))
+        return true;
+
+    if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) {
+        ALOGW("ShaderCache::validateCache cache validation fails");
+    }
+    mBlobCache->clear();
+    return false;
+}
+
+void ShaderCache::initShaderDiskCache(const void* identity, ssize_t size) {
     ATRACE_NAME("initShaderDiskCache");
     std::lock_guard<std::mutex> lock(mMutex);
 
@@ -50,6 +85,7 @@
     // desktop / laptop GPUs. Thus, disable the shader disk cache for emulator builds.
     if (!Properties::runningInEmulator && mFilename.length() > 0) {
         mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename));
+        validateCache(identity, size);
         mInitialized = true;
     }
 }
@@ -104,6 +140,18 @@
     return SkData::MakeFromMalloc(valueBuffer, valueSize);
 }
 
+void ShaderCache::saveToDiskLocked() {
+    ATRACE_NAME("ShaderCache::saveToDiskLocked");
+    if (mInitialized && mBlobCache && mSavePending) {
+        if (mIDHash.size()) {
+            auto key = sIDKey;
+            mBlobCache->set(&key, sizeof(key), mIDHash.data(), mIDHash.size());
+        }
+        mBlobCache->writeToFile();
+    }
+    mSavePending = false;
+}
+
 void ShaderCache::store(const SkData& key, const SkData& data) {
     ATRACE_NAME("ShaderCache::store");
     std::lock_guard<std::mutex> lock(mMutex);
@@ -129,11 +177,7 @@
         std::thread deferredSaveThread([this]() {
             sleep(mDeferredSaveDelay);
             std::lock_guard<std::mutex> lock(mMutex);
-            ATRACE_NAME("ShaderCache::saveToDisk");
-            if (mInitialized && mBlobCache) {
-                mBlobCache->writeToFile();
-            }
-            mSavePending = false;
+            saveToDiskLocked();
         });
         deferredSaveThread.detach();
     }
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 27473d6..82804cf 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -40,12 +40,21 @@
     ANDROID_API static ShaderCache& get();
 
     /**
-     * "initShaderDiskCache" loads the serialized cache contents from disk and puts the ShaderCache
-     * into an initialized state, such that it is able to insert and retrieve entries from the
-     * cache.  This should be called when HWUI pipeline is initialized.  When not in the initialized
-     * state the load and store methods will return without performing any cache operations.
+     * initShaderDiskCache" loads the serialized cache contents from disk,
+     * optionally checks that the on-disk cache matches a provided identity,
+     * and puts the ShaderCache into an initialized state, such that it is
+     * able to insert and retrieve entries from the cache. If identity is
+     * non-null and validation fails, the cache is initialized but contains
+     * no data. If size is less than zero, the cache is initilaized but
+     * contains no data.
+     *
+     * This should be called when HWUI pipeline is initialized. When not in
+     * the initialized state the load and store methods will return without
+     * performing any cache operations.
      */
-    virtual void initShaderDiskCache();
+    virtual void initShaderDiskCache(const void *identity, ssize_t size);
+
+    virtual void initShaderDiskCache() { initShaderDiskCache(nullptr, 0); }
 
     /**
      * "setFilename" sets the name of the file that should be used to store
@@ -83,6 +92,19 @@
     BlobCache* getBlobCacheLocked();
 
     /**
+     * "validateCache" updates the cache to match the given identity.  If the
+     * cache currently has the wrong identity, all entries in the cache are cleared.
+     */
+    bool validateCache(const void* identity, ssize_t size);
+
+    /**
+     * "saveToDiskLocked" attemps to save the current contents of the cache to
+     * disk. If the identity hash exists, we will insert the identity hash into
+     * the cache for next validation.
+     */
+    void saveToDiskLocked();
+
+    /**
      * "mInitialized" indicates whether the ShaderCache is in the initialized
      * state.  It is initialized to false at construction time, and gets set to
      * true when initialize is called.
@@ -111,6 +133,15 @@
     std::string mFilename;
 
     /**
+     * "mIDHash" is the current identity hash for the cache validation. It is
+     * initialized to an empty vector at construction time, and its content is
+     * generated in the call of the validateCache method. An empty vector
+     * indicates that cache validation is not performed, and the hash should
+     * not be stored on disk.
+     */
+    std::vector<uint8_t> mIDHash;
+
+    /**
      * "mSavePending" indicates whether or not a deferred save operation is
      * pending.  Each time a key/value pair is inserted into the cache via
      * load, a deferred save is initiated if one is not already pending.
@@ -140,6 +171,11 @@
      */
     static ShaderCache sCache;
 
+    /**
+     * "sIDKey" is the cache key of the identity hash
+     */
+    static constexpr uint8_t sIDKey = 0;
+
     friend class ShaderCacheTestUtils; //used for unit testing
 };
 
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index bec80b1e..82bfc49 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -50,7 +50,6 @@
     mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
             mMaxSurfaceArea / 2,
             skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
-    skiapipeline::ShaderCache::get().initShaderDiskCache();
 }
 
 void CacheManager::reset(sk_sp<GrContext> context) {
@@ -103,7 +102,7 @@
     }
 };
 
-void CacheManager::configureContext(GrContextOptions* contextOptions) {
+void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
     contextOptions->fAllowPathMaskCaching = true;
 
     float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f;
@@ -133,7 +132,9 @@
         contextOptions->fExecutor = mTaskProcessor.get();
     }
 
-    contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get();
+    auto& cache = skiapipeline::ShaderCache::get();
+    cache.initShaderDiskCache(identity, size);
+    contextOptions->fPersistentCache = &cache;
     contextOptions->fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
 }
 
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 7d73352..35fc91a 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -44,7 +44,7 @@
 public:
     enum class TrimMemoryMode { Complete, UiHidden };
 
-    void configureContext(GrContextOptions* context);
+    void configureContext(GrContextOptions* context, const void* identity, ssize_t size);
     void trimMemory(TrimMemoryMode mode);
     void trimStaleResources();
     void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index c1284ec..36ffaee 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -191,7 +191,9 @@
     GrContextOptions options;
     options.fPreferExternalImagesOverES3 = true;
     options.fDisableDistanceFieldPaths = true;
-    cacheManager().configureContext(&options);
+    auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+    auto size = glesVersion ? strlen(glesVersion) : -1;
+    cacheManager().configureContext(&options, glesVersion, size);
     sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
     LOG_ALWAYS_FATAL_IF(!grContext.get());
     setGrContext(grContext);
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 1517f57..cc4b87a 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -391,7 +391,8 @@
 
     GrContextOptions options;
     options.fDisableDistanceFieldPaths = true;
-    mRenderThread.cacheManager().configureContext(&options);
+    // TODO: get a string describing the SPIR-V compiler version and use it here
+    mRenderThread.cacheManager().configureContext(&options, nullptr, 0);
     sk_sp<GrContext> grContext(GrContext::MakeVulkan(backendContext, options));
     LOG_ALWAYS_FATAL_IF(!grContext.get());
     mRenderThread.setGrContext(grContext);
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 43080a9..1433aa0 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -48,11 +48,18 @@
      */
     static void terminate(ShaderCache& cache, bool saveContent) {
         std::lock_guard<std::mutex> lock(cache.mMutex);
-        if (cache.mInitialized && cache.mBlobCache && saveContent) {
-            cache.mBlobCache->writeToFile();
-        }
+        cache.mSavePending = saveContent;
+        cache.saveToDiskLocked();
         cache.mBlobCache = NULL;
     }
+
+    /**
+     *
+     */
+    template <typename T>
+    static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
+        return cache.validateCache(hash.data(), hash.size() * sizeof(T));
+    }
 };
 
 } /* namespace skiapipeline */
@@ -75,26 +82,39 @@
     return false;
 }
 
-bool checkShader(const sk_sp<SkData>& shader, const char* program) {
-    sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
-    return shader->size() == shader2->size()
-            && 0 == memcmp(shader->data(), shader2->data(), shader->size());
+inline bool
+checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
+    return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size()
+            && 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
 }
 
-bool checkShader(const sk_sp<SkData>& shader, std::vector<char>& program) {
-    sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size());
-    return shader->size() == shader2->size()
-            && 0 == memcmp(shader->data(), shader2->data(), shader->size());
+inline bool
+checkShader(const sk_sp<SkData>& shader, const char* program) {
+    sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
+    return checkShader(shader, shader2);
+}
+
+template <typename T>
+bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) {
+    sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T));
+    return checkShader(shader, shader2);
 }
 
 void setShader(sk_sp<SkData>& shader, const char* program) {
     shader = SkData::MakeWithCString(program);
 }
 
-void setShader(sk_sp<SkData>& shader, std::vector<char>& program) {
-    shader = SkData::MakeWithCopy(program.data(), program.size());
+template <typename T>
+void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) {
+    shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T));
 }
 
+template <typename T>
+void genRandomData(std::vector<T>& buffer) {
+    for (auto& data : buffer) {
+        data = T(std::rand());
+    }
+}
 
 
 #define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
@@ -110,6 +130,7 @@
     //remove any test files from previous test run
     int deleteFile = remove(cacheFile1.c_str());
     ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
+    std::srand(0);
 
     //read the cache from a file that does not exist
     ShaderCache::get().setFilename(cacheFile1.c_str());
@@ -158,10 +179,8 @@
 
     //write and read big data chunk (50K)
     size_t dataSize = 50*1024;
-    std::vector<char> dataBuffer(dataSize);
-    for (size_t i = 0; i < dataSize; i++) {
-        dataBuffer[0] = dataSize % 256;
-    }
+    std::vector<uint8_t> dataBuffer(dataSize);
+    genRandomData(dataBuffer);
     setShader(inVS, dataBuffer);
     ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
     ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
@@ -173,4 +192,96 @@
     remove(cacheFile1.c_str());
 }
 
+TEST(ShaderCacheTest, testCacheValidation) {
+    if (!folderExist(getExternalStorageFolder())) {
+        //don't run the test if external storage folder is not available
+        return;
+    }
+    std::string cacheFile1 =  getExternalStorageFolder() + "/shaderCacheTest1";
+    std::string cacheFile2 =  getExternalStorageFolder() + "/shaderCacheTest2";
+
+    //remove any test files from previous test run
+    int deleteFile = remove(cacheFile1.c_str());
+    ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
+    std::srand(0);
+
+    //generate identity and read the cache from a file that does not exist
+    ShaderCache::get().setFilename(cacheFile1.c_str());
+    ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save
+    std::vector<uint8_t> identity(1024);
+    genRandomData(identity);
+    ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
+                                           sizeof(decltype(identity)::value_type));
+
+    // generate random content in cache and store to disk
+    constexpr size_t numBlob(10);
+    constexpr size_t keySize(1024);
+    constexpr size_t dataSize(50 * 1024);
+
+    std::vector< std::pair<sk_sp<SkData>, sk_sp<SkData>> > blobVec(numBlob);
+    for (auto& blob : blobVec) {
+        std::vector<uint8_t> keyBuffer(keySize);
+        std::vector<uint8_t> dataBuffer(dataSize);
+        genRandomData(keyBuffer);
+        genRandomData(dataBuffer);
+
+        sk_sp<SkData> key, data;
+        setShader(key, keyBuffer);
+        setShader(data, dataBuffer);
+
+        blob = std::make_pair(key, data);
+        ShaderCache::get().store(*key.get(), *data.get());
+    }
+    ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+
+    // change to a file that does not exist and verify validation fails
+    ShaderCache::get().setFilename(cacheFile2.c_str());
+    ShaderCache::get().initShaderDiskCache();
+    ASSERT_FALSE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) );
+    ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+
+    // restore the original file and verify validation succeeds
+    ShaderCache::get().setFilename(cacheFile1.c_str());
+    ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
+                                           sizeof(decltype(identity)::value_type));
+    ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) );
+    for (const auto& blob : blobVec) {
+        auto outVS = ShaderCache::get().load(*blob.first.get());
+        ASSERT_TRUE( checkShader(outVS, blob.second) );
+    }
+
+    // generate error identity and verify load fails
+    ShaderCache::get().initShaderDiskCache(identity.data(), -1);
+    for (const auto& blob : blobVec) {
+        ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() );
+    }
+    ShaderCache::get().initShaderDiskCache(nullptr, identity.size() *
+                                           sizeof(decltype(identity)::value_type));
+    for (const auto& blob : blobVec) {
+        ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() );
+    }
+
+    // verify the cache validation again after load fails
+    ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
+                                           sizeof(decltype(identity)::value_type));
+    ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) );
+    for (const auto& blob : blobVec) {
+        auto outVS = ShaderCache::get().load(*blob.first.get());
+        ASSERT_TRUE( checkShader(outVS, blob.second) );
+    }
+
+    // generate another identity and verify load fails
+    for (auto& data : identity) {
+        data += std::rand();
+    }
+    ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
+                                           sizeof(decltype(identity)::value_type));
+    for (const auto& blob : blobVec) {
+        ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() );
+    }
+
+    ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+    remove(cacheFile1.c_str());
+}
+
 }  // namespace
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 2be9311..7c81399 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -106,6 +106,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name=".PackageInstalledReceiver"
+                android:exported="true">
+            <intent-filter android:priority="1">
+                <action android:name="android.intent.action.PACKAGE_ADDED" />
+                <data android:scheme="package" />
+            </intent-filter>
+        </receiver>
+
         <activity android:name=".UninstallUninstalling"
             android:excludeFromRecents="true"
             android:exported="false" />
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
new file mode 100644
index 0000000..67ac99f
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receive new app installed broadcast and notify user new app installed.
+ */
+public class PackageInstalledReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "PackageInstalledReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // TODO: Add logic to handle new app installed.
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index f1b7eec..ca1b489 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -261,6 +261,12 @@
         return mPages.get(0).mColumns;
     }
 
+    public int getNumVisibleTiles() {
+        if (mPages.size() == 0) return 0;
+        TilePage currentPage = mPages.get(getCurrentItem());
+        return currentPage.mRecords.size();
+    }
+
     public void startTileReveal(Set<String> tileSpecs, final Runnable postAnimation) {
         if (tileSpecs.isEmpty() || mPages.size() < 2 || getScrollX() != 0 || !beginFakeDrag()) {
             // Do not start the reveal animation unless there are tiles to animate, multiple
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 2a4bb60..3744d7d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -155,6 +155,7 @@
         TouchAnimator.Builder translationYBuilder = new Builder();
 
         if (mQsPanel.getHost() == null) return;
+        if (mQuickQsPanel.getTileLayout().getNumVisibleTiles() < 1) return;
         Collection<QSTile> tiles = mQsPanel.getHost().getTiles();
         int count = 0;
         int[] loc1 = new int[2];
@@ -169,6 +170,7 @@
         QSTileLayout tileLayout = mQsPanel.getTileLayout();
         mAllViews.add((View) tileLayout);
         int height = mQs.getView() != null ? mQs.getView().getMeasuredHeight() : 0;
+        int width = mQs.getView() != null ? mQs.getView().getMeasuredWidth() : 0;
         int heightDiff = height - mQs.getHeader().getBottom()
                 + mQs.getHeader().getPaddingBottom();
         firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
@@ -181,7 +183,9 @@
             }
             final View tileIcon = tileView.getIcon().getIconView();
             View view = mQs.getView();
-            if (count < mNumQuickTiles && mAllowFancy) {
+
+            // This case: less tiles to animate in small displays.
+            if (count < mQuickQsPanel.getTileLayout().getNumVisibleTiles() && mAllowFancy) {
                 // Quick tiles.
                 QSTileView quickTileView = mQuickQsPanel.getTileView(tile);
                 if (quickTileView == null) continue;
@@ -192,18 +196,26 @@
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
                 lastXDiff = loc1[0] - lastX;
-                // Move the quick tile right from its location to the new one.
-                translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
-                translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
 
-                // Counteract the parent translation on the tile. So we have a static base to
-                // animate the label position off from.
-                //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+                if (count < tileLayout.getNumVisibleTiles()) {
+                    // Move the quick tile right from its location to the new one.
+                    translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
+                    translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
 
-                // Move the real tile from the quick tile position to its final
-                // location.
-                translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
-                translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+                    // Counteract the parent translation on the tile. So we have a static base to
+                    // animate the label position off from.
+                    //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+
+                    // Move the real tile from the quick tile position to its final
+                    // location.
+                    translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
+                    translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+
+                } else { // These tiles disappear when expanding
+                    firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
+                    translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
+                    translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff + width);
+                }
 
                 mQuickQsViews.add(tileView.getIconWithBackground());
                 mAllViews.add(tileView.getIcon());
@@ -218,10 +230,9 @@
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
 
-                firstPageBuilder.addFloat(tileView, "translationY", heightDiff, 0);
-                translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
+                firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
                 translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
-                translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
+                translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
 
                 mAllViews.add(tileIcon);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 7cb22a3..03febda 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -101,12 +101,7 @@
         if (savedInstanceState != null) {
             setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
             setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
-            int[] loc = new int[2];
-            View edit = view.findViewById(android.R.id.edit);
-            edit.getLocationInWindow(loc);
-            int x = loc[0] + edit.getWidth() / 2;
-            int y = loc[1] + edit.getHeight() / 2;
-            mQSCustomizer.setEditLocation(x, y);
+            setEditLocation(view);
             mQSCustomizer.restoreInstanceState(savedInstanceState);
         }
         SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
@@ -161,15 +156,24 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        setEditLocation(getView());
         if (newConfig.getLayoutDirection() != mLayoutDirection) {
             mLayoutDirection = newConfig.getLayoutDirection();
-
             if (mQSAnimator != null) {
                 mQSAnimator.onRtlChanged();
             }
         }
     }
 
+    private void setEditLocation(View view) {
+        Log.w(TAG, "I'm changing the location of the button!!!");
+        View edit = view.findViewById(android.R.id.edit);
+        int[] loc = edit.getLocationOnScreen();
+        int x = loc[0] + edit.getWidth() / 2;
+        int y = loc[1] + edit.getHeight() / 2;
+        mQSCustomizer.setEditLocation(x, y);
+    }
+
     @Override
     public void setContainer(ViewGroup container) {
         if (container instanceof NotificationsQuickSettingsContainer) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 3fc258b..762fd75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -29,6 +29,7 @@
 import android.os.Message;
 import android.service.quicksettings.Tile;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -60,6 +61,8 @@
     public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
     public static final String QS_SHOW_HEADER = "qs_show_header";
 
+    private static final String TAG = "QSPanel";
+
     protected final Context mContext;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
     protected final View mBrightnessView;
@@ -313,7 +316,7 @@
 
     public void onCollapse() {
         if (mCustomizePanel != null && mCustomizePanel.isShown()) {
-            mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
+            mCustomizePanel.hide();
         }
     }
 
@@ -480,8 +483,7 @@
             public void run() {
                 if (mCustomizePanel != null) {
                     if (!mCustomizePanel.isCustomizing()) {
-                        int[] loc = new int[2];
-                        v.getLocationInWindow(loc);
+                        int[] loc = v.getLocationOnScreen();
                         int x = loc[0] + v.getWidth() / 2;
                         int y = loc[1] + v.getHeight() / 2;
                         mCustomizePanel.show(x, y);
@@ -495,7 +497,7 @@
     public void closeDetail() {
         if (mCustomizePanel != null && mCustomizePanel.isShown()) {
             // Treat this as a detail panel for now, to make things easy.
-            mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
+            mCustomizePanel.hide();
             return;
         }
         showDetail(false, mDetailRecord);
@@ -663,5 +665,7 @@
         void setListening(boolean listening);
 
         default void setExpansion(float expansion) {}
+
+        int getNumVisibleTiles();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 1c50f79..556786a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -18,18 +18,17 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.LinearLayout;
-import android.widget.Space;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
 import com.android.systemui.plugins.qs.QSTile.State;
-import com.android.systemui.plugins.qs.QSTileView;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
@@ -43,6 +42,7 @@
 public class QuickQSPanel extends QSPanel {
 
     public static final String NUM_QUICK_TILES = "sysui_qqs_count";
+    private static final String TAG = "QuickQSPanel";
 
     private boolean mDisabledByPolicy;
     private static int mDefaultMaxTiles;
@@ -178,121 +178,95 @@
         super.setVisibility(visibility);
     }
 
-    private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
+    private static class HeaderTileLayout extends TileLayout {
 
-        protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
         private boolean mListening;
-        /** Size of the QS tile (width & height). */
-        private int mTileDimensionSize;
 
         public HeaderTileLayout(Context context) {
             super(context);
             setClipChildren(false);
             setClipToPadding(false);
-
-            mTileDimensionSize = mContext.getResources().getDimensionPixelSize(
-                    R.dimen.qs_quick_tile_size);
-            updateLayoutParams();
         }
 
         @Override
         protected void onConfigurationChanged(Configuration newConfig) {
             super.onConfigurationChanged(newConfig);
-            updateLayoutParams();
+            updateResources();
+        }
+
+        @Override
+        public void onFinishInflate(){
+            updateResources();
         }
 
         private void updateLayoutParams() {
-            setGravity(Gravity.CENTER);
             int width = getResources().getDimensionPixelSize(R.dimen.qs_quick_layout_width);
-            LayoutParams lp = new LayoutParams(width, LayoutParams.MATCH_PARENT);
+            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, LayoutParams.MATCH_PARENT);
             lp.gravity = Gravity.CENTER_HORIZONTAL;
             setLayoutParams(lp);
         }
 
-        /**
-         * Returns {@link LayoutParams} based on the given {@code spaceWidth}. If the width is 0,
-         * then we're going to have the space expand to take up as much space as possible. If the
-         * width is non-zero, we want the inter-tile spacers to be fixed.
-         */
-        private LayoutParams generateSpaceLayoutParams() {
-            LayoutParams lp = new LayoutParams(0, mTileDimensionSize);
-            lp.weight = 1;
-            lp.gravity = Gravity.CENTER;
-            return lp;
-        }
-
-        @Override
-        public void setListening(boolean listening) {
-            if (mListening == listening) return;
-            mListening = listening;
-            for (TileRecord record : mRecords) {
-                record.tile.setListening(this, mListening);
-            }
-        }
-
-        @Override
-        public void addTile(TileRecord tile) {
-            if (getChildCount() != 0) {
-                addView(new Space(mContext), getChildCount(), generateSpaceLayoutParams());
-            }
-
-            addView(tile.tileView, getChildCount(), generateTileLayoutParams());
-            mRecords.add(tile);
-            tile.tile.setListening(this, mListening);
-        }
-
         private LayoutParams generateTileLayoutParams() {
-            LayoutParams lp = new LayoutParams(mTileDimensionSize, mTileDimensionSize);
-            lp.gravity = Gravity.CENTER;
+            LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight);
             return lp;
         }
 
         @Override
-        public void removeTile(TileRecord tile) {
-            int childIndex = getChildIndex(tile.tileView);
-            // Remove the tile.
-            removeViewAt(childIndex);
-            if (getChildCount() != 0) {
-                // Remove its spacer as well.
-                removeViewAt(childIndex);
-            }
-            mRecords.remove(tile);
-            tile.tile.setListening(this, false);
-        }
-
-        private int getChildIndex(QSTileView tileView) {
-            final int childViewCount = getChildCount();
-            for (int i = 0; i < childViewCount; i++) {
-                if (getChildAt(i) == tileView) {
-                    return i;
-                }
-            }
-            return -1;
+        protected void addTileView(TileRecord tile) {
+            addView(tile.tileView, getChildCount(), generateTileLayoutParams());
         }
 
         @Override
-        public int getOffsetTop(TileRecord tile) {
-            return 0;
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            // We only care about clipping on the right side
+            Rect bounds = new Rect(0, 0, r - l, 10000);
+            setClipBounds(bounds);
+
+            calculateColumns();
+
+            for (int i = 0; i < mRecords.size(); i++) {
+                mRecords.get(i).tileView.setVisibility( i < mColumns ? View.VISIBLE : View.GONE);
+            }
+
+            setAccessibilityOrder();
+            layoutTileRecords(mColumns);
         }
 
         @Override
         public boolean updateResources() {
-            // No resources here.
+            mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+            mCellHeight = mCellWidth;
+
+            updateLayoutParams();
+
             return false;
         }
 
-        @Override
-        public boolean hasOverlappingRendering() {
-            return false;
-        }
+        private boolean calculateColumns() {
+            int prevNumColumns = mColumns;
+            int maxTiles = mRecords.size();
 
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            if (hideOverflowingChildren(widthMeasureSpec)) {
-                return; // Rely on visibility change to trigger remeasure.
+            if (maxTiles == 0){ // Early return during setup
+                mColumns = 0;
+                return true;
             }
 
+            final int availableWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
+            final int leftoverWithespace = availableWidth - maxTiles * mCellWidth;
+            final int smallestHorizontalMarginNeeded = leftoverWithespace / (maxTiles - 1);
+
+            if (smallestHorizontalMarginNeeded > 0){
+                mCellMarginHorizontal = smallestHorizontalMarginNeeded;
+                mColumns = maxTiles;
+            } else{
+                mColumns = mCellWidth == 0 ? 1 :
+                        Math.min(maxTiles, availableWidth / mCellWidth );
+                mCellMarginHorizontal = (availableWidth - mColumns * mCellWidth) / (mColumns - 1);
+            }
+            return mColumns != prevNumColumns;
+        }
+
+        private void setAccessibilityOrder() {
             if (mRecords != null && mRecords.size() > 0) {
                 View previousView = this;
                 for (TileRecord record : mRecords) {
@@ -306,31 +280,28 @@
             }
         }
 
-        /**
-         * Hide child views that would otherwise be clipped.
-         * @return {@code true} if any child visibilities have changed.
-         */
-        private boolean hideOverflowingChildren(int widthMeasureSpec) {
-            if (getChildCount() == 0) {
-                return false;
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            // Measure each QS tile.
+            for (TileRecord record : mRecords) {
+                if (record.tileView.getVisibility() == GONE) continue;
+                record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
             }
-            boolean childVisibilityChanged = false;
-            int widthRemaining = MeasureSpec.getSize(widthMeasureSpec)
-                - getChildAt(0).getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
-            for (int i = 2; i < getChildCount(); i += 2) {
-                View tileChild = getChildAt(i);
-                LayoutParams lp = (LayoutParams) tileChild.getLayoutParams();
-                // All Space views have 0 width; only tiles contribute to the total width.
-                widthRemaining = widthRemaining
-                    - tileChild.getMeasuredWidth() - lp.getMarginEnd() - lp.getMarginStart();
-                int newVisibility = widthRemaining < 0 ? View.GONE : View.VISIBLE;
-                if (tileChild.getVisibility() != newVisibility) {
-                    tileChild.setVisibility(newVisibility);
-                    getChildAt(i - 1).setVisibility(newVisibility); // Hide spacer as well.
-                    childVisibilityChanged = true;
-                }
-            }
-            return childVisibilityChanged;
+
+            int height = mCellHeight;
+            if (height < 0) height = 0;
+
+            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
+        }
+
+        @Override
+        public int getNumVisibleTiles() {
+            return mColumns;
+        }
+
+        @Override
+        protected int getColumnStart(int column) {
+            return getPaddingStart() + column *  (mCellWidth + mCellMarginHorizontal);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 45d63e0..c67165e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -56,6 +56,10 @@
     public void addTile(TileRecord tile) {
         mRecords.add(tile);
         tile.tile.setListening(this, mListening);
+        addTileView(tile);
+    }
+
+    protected void addTileView(TileRecord tile) {
         addView(tile.tileView);
     }
 
@@ -120,19 +124,18 @@
         return false;
     }
 
-    private static int exactly(int size) {
+    protected static int exactly(int size) {
         return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
     }
 
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final int w = getWidth();
+
+    protected void layoutTileRecords(int numRecords) {
         final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         int row = 0;
         int column = 0;
 
         // Layout each QS tile.
-        for (int i = 0; i < mRecords.size(); i++, column++) {
+        for (int i = 0; i < numRecords; i++, column++) {
             // If we reached the last column available to layout a tile, wrap back to the next row.
             if (column == mColumns) {
                 column = 0;
@@ -147,12 +150,22 @@
         }
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        layoutTileRecords(mRecords.size());
+    }
+
     private int getRowTop(int row) {
         return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop;
     }
 
-    private int getColumnStart(int column) {
+    protected int getColumnStart(int column) {
         return getPaddingStart() + mSidePadding + mCellMarginHorizontal / 2 +
                 column *  (mCellWidth + mCellMarginHorizontal);
     }
+
+    @Override
+    public int getNumVisibleTiles() {
+        return mRecords.size();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 2ea15bd..3f7eeb8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -26,6 +26,7 @@
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -63,6 +64,7 @@
 
     private static final int MENU_RESET = Menu.FIRST;
     private static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
+    private static final String TAG = "QSCustomizer";
 
     private final QSDetailClipper mClipper;
     private final LightBarController mLightBarController;
@@ -94,7 +96,7 @@
         mToolbar.setNavigationOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
-                hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
+                hide();
             }
         });
         mToolbar.setOnMenuItemClickListener(this);
@@ -154,16 +156,20 @@
         mQs = qs;
     }
 
+    /** Animate and show QSCustomizer panel.
+     * @param x,y Location on screen of {@code edit} button to determine center of animation.
+     */
     public void show(int x, int y) {
         if (!isShown) {
-            mX = x;
-            mY = y;
+            int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
+            mX = x - containerLocation[0];
+            mY = y - containerLocation[1];
             MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
             isShown = true;
             mOpening = true;
             setTileSpecs();
             setVisibility(View.VISIBLE);
-            mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
+            mClipper.animateCircularClip(mX, mY, true, mExpandAnimationListener);
             queryTiles();
             mNotifQsContainer.setCustomizerAnimating(true);
             mNotifQsContainer.setCustomizerShowing(true);
@@ -192,7 +198,7 @@
         mTileQueryHelper.queryTiles(mHost);
     }
 
-    public void hide(int x, int y) {
+    public void hide() {
         if (isShown) {
             MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
             isShown = false;
@@ -278,16 +284,18 @@
             });
         }
     }
-
+    /** @param x,y Location on screen of animation center.
+     */
     public void setEditLocation(int x, int y) {
-        mX = x;
-        mY = y;
+        int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
+        mX = x - containerLocation[0];
+        mY = y - containerLocation[1];
     }
 
     private final Callback mKeyguardCallback = () -> {
         if (!isAttachedToWindow()) return;
         if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
-            hide(0, 0);
+            hide();
         }
     };
 
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 665c6b7..aa1b303 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1561,7 +1561,6 @@
                 final String defaultImiId = mSettings.getSelectedInputMethod();
                 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
                 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
-                resetDefaultImeLocked(mContext);
                 updateFromSettingsLocked(true);
                 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
                         mSettings.getEnabledInputMethodListLocked(), currentUserId,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9b097bf..07f3e17 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1988,6 +1988,14 @@
                             mRequiredVerifierPackage, null /*finishedReceiver*/,
                             updateUserIds, instantUserIds);
                 }
+                // If package installer is defined, notify package installer about new
+                // app installed
+                if (mRequiredInstallerPackage != null) {
+                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+                            extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
+                            mRequiredInstallerPackage, null /*finishedReceiver*/,
+                            firstUserIds, instantUserIds);
+                }
 
                 // Send replaced for users that don't see the package for the first time
                 if (update) {
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 9fae43a..82d7ab8 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -63,6 +63,7 @@
 import static org.robolectric.Shadows.shadowOf;
 import static org.robolectric.shadow.api.Shadow.extract;
 import static org.testng.Assert.fail;
+import static org.testng.Assert.expectThrows;
 
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 import static java.util.Collections.emptyList;
@@ -1941,6 +1942,29 @@
         task.markCancel();
     }
 
+    @Test
+    public void testHandleCancel_callsMarkCancelAndWaitCancel() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgentWithData(PACKAGE_1);
+        KeyValueBackupTask task = spy(createKeyValueBackupTask(transportMock, PACKAGE_1));
+        doNothing().when(task).waitCancel();
+
+        task.handleCancel(true);
+
+        InOrder inOrder = inOrder(task);
+        inOrder.verify(task).markCancel();
+        inOrder.verify(task).waitCancel();
+    }
+
+    @Test
+    public void testHandleCancel_whenCancelAllFalse_throws() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgentWithData(PACKAGE_1);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        expectThrows(IllegalArgumentException.class, () -> task.handleCancel(false));
+    }
+
     private void runTask(KeyValueBackupTask task) {
         // Pretend we are not on the main-thread to prevent RemoteCall from complaining
         mShadowMainLooper.setCurrentThread(false);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8703e65..ffbe7d3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -107,13 +107,34 @@
 
    /**
     * Boolean indicating if the "Call barring" item is visible in the Call Settings menu.
-    * true means visible. false means gone.
-    * @hide
+    * If true, the "Call Barring" menu will be visible. If false, the menu will be gone.
+    *
+    * Disabled by default.
     */
     public static final String KEY_CALL_BARRING_VISIBILITY_BOOL =
             "call_barring_visibility_bool";
 
     /**
+     * Flag indicating whether or not changing the call barring password via the "Call Barring"
+     * settings menu is supported. If true, the option will be visible in the "Call
+     * Barring" settings menu. If false, the option will not be visible.
+     *
+     * Enabled by default.
+     */
+    public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL =
+            "call_barring_supports_password_change_bool";
+
+    /**
+     * Flag indicating whether or not deactivating all call barring features via the "Call Barring"
+     * settings menu is supported. If true, the option will be visible in the "Call
+     * Barring" settings menu. If false, the option will not be visible.
+     *
+     * Enabled by default.
+     */
+    public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL =
+            "call_barring_supports_deactivate_all_bool";
+
+    /**
      * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
      * events from the Sim.
      * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
@@ -2125,6 +2146,8 @@
 
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
         sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
+        sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true);
+        sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true);
         sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true);
         sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true);
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 3517984..3b9f93e 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -18,14 +18,14 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
 
-import android.os.Parcel;
 import android.net.MacAddress;
 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
-import android.net.wifi.WifiInfo;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -33,6 +33,7 @@
 /**
  * Unit tests for {@link android.net.wifi.WifiConfiguration}.
  */
+@SmallTest
 public class WifiConfigurationTest {
 
     @Before
diff --git a/wifi/tests/src/android/net/wifi/WifiSsidTest.java b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
index e5794c5..b58f2c7 100644
--- a/wifi/tests/src/android/net/wifi/WifiSsidTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
@@ -19,14 +19,16 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
 
 /**
  * Unit tests for {@link android.net.wifi.WifiSsid}.
  */
+@SmallTest
 public class WifiSsidTest {
 
     private static final String TEST_SSID = "Test SSID";
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
index e492475..80f00a4 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
@@ -19,11 +19,14 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+
 import org.junit.Test;
 
 /**
  * Unit test harness for {@link android.net.wifi.p2p.WifiP2pDevice}
  */
+@SmallTest
 public class WifiP2pDeviceTest {
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
index e8e4dc2..2132b41 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
 
 import libcore.junit.util.ResourceLeakageDetector;
 
@@ -33,6 +34,7 @@
 /**
  * Unit test harness for WifiP2pManager.
  */
+@SmallTest
 public class WifiP2pManagerTest {
     private WifiP2pManager mDut;
     private TestLooper mTestLooper;
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index ccb9031..8997ae9 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -31,6 +31,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -45,6 +46,7 @@
 /**
  * Unit test harness for WifiRttManager class.
  */
+@SmallTest
 public class WifiRttManagerTest {
     private WifiRttManager mDut;
     private TestLooper mMockLooper;