Merge "Store keys instead of notification entries." into udc-qpr-dev
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0b486c0..a55183c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10505,6 +10505,14 @@
                 "search_press_hold_nav_handle_enabled";
 
         /**
+         * Whether long-pressing on the home button can trigger search.
+         *
+         * @hide
+         */
+        public static final String SEARCH_LONG_PRESS_HOME_ENABLED =
+                "search_long_press_home_enabled";
+
+        /**
          * Control whether Trust Agents are in active unlock or extend unlock mode.
          * @hide
          */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d680d04..c2afb4b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -434,15 +434,15 @@
         /**
          * Called when the typing hint is changed. This would be invoked by the
          * {@link android.view.inputmethod.RemoteInputConnectionImpl}
-         * to hint if the user is typing when the it is {@link #isActive() active}.
+         * to hint if the user is typing when it is {@link #isActive() active}.
          *
-         * This can be only happened on the UI thread. The behavior won't be guaranteed if
-         * invoking this on a non-UI thread.
+         * The operation in this method should be dispatched to the UI thread to
+         * keep the sequence.
          *
          * @param isTyping {@code true} if the user is typing.
+         * @param deactivate {code true} if the input connection deactivate
          */
-        @UiThread
-        void onTypingHintChanged(boolean isTyping);
+        void onTypingHintChanged(boolean isTyping, boolean deactivate);
 
         /**
          * Indicates whether the notifier is currently in active state or not.
@@ -468,19 +468,40 @@
         @NonNull
         private final ViewRootRefreshRateController mController;
 
+        @NonNull
+        private final Handler mHandler;
+
+        @NonNull
+        private final Thread mThread;
+
         TypingHintNotifierImpl(@NonNull AtomicReference<TypingHintNotifier> notifier,
-                @NonNull ViewRootRefreshRateController controller) {
+                @NonNull ViewRootRefreshRateController controller, @NonNull Handler handler,
+                @NonNull Thread thread) {
             mController = controller;
             mActiveNotifier = notifier;
+            mHandler = handler;
+            mThread = thread;
         }
 
         @Override
-        public void onTypingHintChanged(boolean isTyping) {
-            if (!isActive()) {
-                // No-op when the listener was deactivated.
-                return;
+        public void onTypingHintChanged(boolean isTyping, boolean deactivate) {
+            final Runnable runnable = () -> {
+                if (!isActive()) {
+                    // No-op when the listener was deactivated.
+                    return;
+                }
+                mController.updateRefreshRatePreference(isTyping ? LOWER : RESTORE);
+                if (deactivate) {
+                    deactivate();
+                }
+            };
+
+            if (Thread.currentThread() == mThread) {
+                // Run directly if it's on the UiThread.
+                runnable.run();
+            } else {
+                mHandler.post(runnable);
             }
-            mController.updateRefreshRatePreference(isTyping ? LOWER : RESTORE);
         }
 
         @Override
@@ -521,7 +542,7 @@
             return null;
         }
         final TypingHintNotifier newNotifier = new TypingHintNotifierImpl(mActiveTypingHintNotifier,
-                mRefreshRateController);
+                mRefreshRateController, mHandler, mThread);
         mActiveTypingHintNotifier.set(newNotifier);
 
         return newNotifier;
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index 364adc7..1e56598 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -28,7 +28,6 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UiThread;
 import android.graphics.RectF;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -373,11 +372,8 @@
             return;
         }
         dispatch(() -> {
-            notifyTypingHint(false /* isTyping */);
             // Deactivate the notifier when finishing typing.
-            if (mTypingHintNotifier != null) {
-                mTypingHintNotifier.deactivate();
-            }
+            notifyTypingHint(false /* isTyping */, true /* deactivate */);
 
             // Note that we do not need to worry about race condition here, because 1) mFinished is
             // updated only inside this block, and 2) the code here is running on a Handler hence we
@@ -643,7 +639,7 @@
                 return;
             }
             ic.commitText(text, newCursorPosition);
-            notifyTypingHint(true /* isTyping */);
+            notifyTypingHint(true /* isTyping */, false /* deactivate */);
         });
     }
 
@@ -799,7 +795,7 @@
                 return;
             }
             ic.setComposingText(text, newCursorPosition);
-            notifyTypingHint(true /* isTyping */);
+            notifyTypingHint(true /* isTyping */, false /* deactivate */);
         });
     }
 
@@ -927,7 +923,7 @@
                 return;
             }
             ic.deleteSurroundingText(beforeLength, afterLength);
-            notifyTypingHint(true /* isTyping */);
+            notifyTypingHint(true /* isTyping */, false /* deactivate */);
         });
     }
 
@@ -1497,10 +1493,9 @@
      * The input connection indicates that the user is typing when {@link #commitText} or
      * {@link #setComposingText)} and the user finish typing when {@link #deactivate()}.
      */
-    @UiThread
-    private void notifyTypingHint(boolean isTyping) {
+    private void notifyTypingHint(boolean isTyping, boolean deactivate) {
         if (mTypingHintNotifier != null) {
-            mTypingHintNotifier.onTypingHintChanged(isTyping);
+            mTypingHintNotifier.onTypingHintChanged(isTyping, deactivate);
         }
     }
 }
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 481a2fb..f425c60 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -138,6 +138,7 @@
         optional SettingProto touch_gesture_enabled = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto long_press_home_enabled = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto search_press_hold_nav_handle_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto search_long_press_home_enabled = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Assist assist = 7;
 
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b6c39c6..16e94f8 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1015,6 +1015,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
     },
+    "-1152771606": {
+      "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "-1145384901": {
       "message": "shouldWaitAnimatingExit: isTransition: %s",
       "level": "DEBUG",
@@ -2323,6 +2329,12 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "1877956": {
+      "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "3593205": {
       "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
       "level": "VERBOSE",
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ceda902..898fee2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -54,6 +54,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Stream;
 
 /**
  * CachedBluetoothDevice represents a remote Bluetooth device. It contains
@@ -652,6 +653,20 @@
         return mDevice.getBatteryLevel();
     }
 
+    /**
+     * Get the lowest battery level from remote device and its member devices
+     * @return battery level in percentage [0-100] or
+     * {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
+     */
+    public int getMinBatteryLevelWithMemberDevices() {
+        return Stream.concat(Stream.of(this), mMemberDevices.stream())
+                .mapToInt(cachedDevice -> cachedDevice.getBatteryLevel())
+                .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
+                .min()
+                .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+    }
+
+
     void refresh() {
         ThreadUtils.postOnBackgroundThread(() -> {
             if (BluetoothUtils.isAdvancedDetailsHeader(mDevice)) {
@@ -1147,7 +1162,7 @@
         // BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF, or BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
         // any other value should be a framework bug. Thus assume here that if value is greater
         // than BluetoothDevice.BATTERY_LEVEL_UNKNOWN, it must be valid
-        final int batteryLevel = getBatteryLevel();
+        final int batteryLevel = getMinBatteryLevelWithMemberDevices();
         if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
             // TODO: name com.android.settingslib.bluetooth.Utils something different
             batteryLevelPercentageString =
@@ -1322,7 +1337,7 @@
         // BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF, or BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
         // any other value should be a framework bug. Thus assume here that if value is greater
         // than BluetoothDevice.BATTERY_LEVEL_UNKNOWN, it must be valid
-        final int batteryLevel = getBatteryLevel();
+        final int batteryLevel = getMinBatteryLevelWithMemberDevices();
         if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
             // TODO: name com.android.settingslib.bluetooth.Utils something different
             batteryLevelPercentageString =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4b61ff1..85efe69 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -529,6 +529,51 @@
     }
 
     @Test
+    public void getConnectionSummary_testMemberDevicesExist_returnMinBattery() {
+        // One device is active with battery level 70.
+        mBatteryLevel = 70;
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+
+
+        // Add a member device with battery level 30.
+        int lowerBatteryLevel = 30;
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        doAnswer((invocation) -> lowerBatteryLevel).when(mSubCachedDevice).getBatteryLevel();
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 30% battery");
+    }
+
+    @Test
+    public void getConnectionSummary_testMemberDevicesBatteryUnknown_returnMinBattery() {
+        // One device is active with battery level 70.
+        mBatteryLevel = 70;
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+
+        // Add a member device with battery level unknown.
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when(
+                mSubCachedDevice).getBatteryLevel();
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 70% battery");
+    }
+
+    @Test
+    public void getConnectionSummary_testAllDevicesBatteryUnknown_returnNoBattery() {
+        // One device is active with battery level unknown.
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+
+        // Add a member device with battery level unknown.
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when(
+                mSubCachedDevice).getBatteryLevel();
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
+    }
+
+    @Test
     public void getConnectionSummary_testMultipleProfilesActiveDevice() {
         // Test without battery level
         // Set A2DP and HFP profiles to be connected and test connection state summary
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index c2dbf98..be63021 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -241,6 +241,7 @@
         Settings.Secure.HEARING_AID_MEDIA_ROUTING,
         Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
         Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
-        Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED
+        Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
+        Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index a49461e..ff32bad 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -199,6 +199,7 @@
         VALIDATORS.put(Secure.ASSIST_TOUCH_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ASSIST_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SEARCH_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"}));
         VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ef4e84f..5c67295 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1929,6 +1929,9 @@
         dumpSetting(s, p,
                 Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
                 SecureSettingsProto.Assist.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
+                SecureSettingsProto.Assist.SEARCH_LONG_PRESS_HOME_ENABLED);
         p.end(assistToken);
 
         final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index e3153e0..0a98032 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -94,6 +94,7 @@
 
     static final int SETTINGS_VERSION_NEW_ENCODING = 121;
 
+    public static final int MAX_LENGTH_PER_STRING = 32768;
     private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
     private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;
 
@@ -430,6 +431,19 @@
             return false;
         }
 
+        final boolean isNameTooLong = name.length() > SettingsState.MAX_LENGTH_PER_STRING;
+        final boolean isValueTooLong =
+                value != null && value.length() > SettingsState.MAX_LENGTH_PER_STRING;
+        if (isNameTooLong || isValueTooLong) {
+            // only print the first few bytes of the name in case it is long
+            final String errorMessage = "The " + (isNameTooLong ? "name" : "value")
+                    + " of your setting ["
+                    + (name.length() > 20 ? (name.substring(0, 20) + "...") : name)
+                    + "] is too long. The max length allowed for the string is "
+                    + MAX_LENGTH_PER_STRING + ".";
+            throw new IllegalArgumentException(errorMessage);
+        }
+
         Setting oldState = mSettings.get(name);
         String oldValue = (oldState != null) ? oldState.value : null;
         String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
@@ -831,6 +845,7 @@
 
     private void doWriteState() {
         boolean wroteState = false;
+        String settingFailedToBePersisted = null;
         final int version;
         final ArrayMap<String, Setting> settings;
         final ArrayMap<String, String> namespaceBannedHashes;
@@ -860,7 +875,6 @@
 
                 final int settingCount = settings.size();
                 for (int i = 0; i < settingCount; i++) {
-
                     Setting setting = settings.valueAt(i);
                     if (setting.isTransient()) {
                         if (DEBUG_PERSISTENCE) {
@@ -869,14 +883,27 @@
                         continue;
                     }
 
-                    if (writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
-                            setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
-                            setting.getTag(), setting.isDefaultFromSystem(),
-                            setting.isValuePreservedInRestore())) {
-                        if (DEBUG_PERSISTENCE) {
-                            Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
-                                    + setting.getValue());
+                    try {
+                        if (writeSingleSetting(mVersion, serializer, setting.getId(),
+                                setting.getName(),
+                                setting.getValue(), setting.getDefaultValue(),
+                                setting.getPackageName(),
+                                setting.getTag(), setting.isDefaultFromSystem(),
+                                setting.isValuePreservedInRestore())) {
+                            if (DEBUG_PERSISTENCE) {
+                                Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
+                                        + setting.getValue());
+                            }
                         }
+                    } catch (IOException ex) {
+                        Slog.e(LOG_TAG, "[ABORT PERSISTING]" + setting.getName()
+                                + " due to error writing to disk", ex);
+                        // A setting failed to be written. Abort the serialization to avoid leaving
+                        // a partially serialized setting on disk, which can cause parsing errors.
+                        // Note down the problematic setting, so that we can delete it before trying
+                        // again to persist the rest of the settings.
+                        settingFailedToBePersisted = setting.getName();
+                        throw ex;
                     }
                 }
                 serializer.endTag(null, TAG_SETTINGS);
@@ -902,14 +929,14 @@
                     Slog.i(LOG_TAG, "[PERSIST END]");
                 }
             } catch (Throwable t) {
-                Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t);
+                Slog.wtf(LOG_TAG, "Failed to write settings, restoring old file", t);
                 if (t instanceof IOException) {
-                    if (DEBUG) {
-                        // we failed to create a directory, so log the permissions and existence
-                        // state for the settings file and directory
-                        logSettingsDirectoryInformation(destination.getBaseFile());
-                    }
                     if (t.getMessage().contains("Couldn't create directory")) {
+                        if (DEBUG) {
+                            // we failed to create a directory, so log the permissions and existence
+                            // state for the settings file and directory
+                            logSettingsDirectoryInformation(destination.getBaseFile());
+                        }
                         // attempt to create the directory with Files.createDirectories, which
                         // throws more informative errors than File.mkdirs.
                         Path parentPath = destination.getBaseFile().getParentFile().toPath();
@@ -930,7 +957,15 @@
             }
         }
 
-        if (wroteState) {
+        if (!wroteState) {
+            if (settingFailedToBePersisted != null) {
+                synchronized (mLock) {
+                    // Delete the problematic setting. This will schedule a write as well.
+                    deleteSettingLocked(settingFailedToBePersisted);
+                }
+            }
+        } else {
+            // success
             synchronized (mLock) {
                 addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null);
             }
@@ -1090,7 +1125,10 @@
         } catch (FileNotFoundException fnfe) {
             final String message = "No fallback file found for: " + mStatePersistFile;
             Slog.wtf(LOG_TAG, message);
-            throw new IllegalStateException(message);
+            if (!isConfigSettingsKey(mKey)) {
+                // Allow partially deserialized config settings because they can be updated later
+                throw new IllegalStateException(message);
+            }
         }
         if (parseStateFromXmlStreamLocked(in)) {
             // Parsed state from fallback file. Restore original file with fallback file
@@ -1102,7 +1140,10 @@
         } else {
             final String message = "Failed parsing settings file: " + mStatePersistFile;
             Slog.wtf(LOG_TAG, message);
-            throw new IllegalStateException(message);
+            if (!isConfigSettingsKey(mKey)) {
+                // Allow partially deserialized config settings because they can be updated later
+                throw new IllegalStateException(message);
+            }
         }
     }
 
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 55160fb..26cac37 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -31,21 +31,21 @@
 public class SettingsStateTest extends AndroidTestCase {
     public static final String CRAZY_STRING =
             "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" +
-            "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
-            "\u001b\u001c\u001d\u001e\u001f\u0020" +
-            "fake_setting_value_1" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
-            "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" +
-            "\ud800\udc00\udbff\udfff" + // surrogate pairs
-            "\uD800ab\uDC00 " + // broken surrogate pairs
-            "日本語";
+                    "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
+                    "\u001b\u001c\u001d\u001e\u001f\u0020" +
+                    "fake_setting_value_1" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+                    "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" +
+                    "\ud800\udc00\udbff\udfff" + // surrogate pairs
+                    "\uD800ab\uDC00 " + // broken surrogate pairs
+                    "日本語";
 
     private static final String TEST_PACKAGE = "package";
     private static final String SYSTEM_PACKAGE = "android";
@@ -170,11 +170,11 @@
         final PrintStream os = new PrintStream(new FileOutputStream(file));
         os.print(
                 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" +
-                "<settings version=\"120\">" +
-                "  <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" +
-                "  <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" +
-                "  <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" +
-                "</settings>");
+                        "<settings version=\"120\">" +
+                        "  <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" +
+                        "  <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" +
+                        "  <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" +
+                        "</settings>");
         os.close();
 
         final SettingsState ss = new SettingsState(getContext(), lock, file, 1,
@@ -408,4 +408,50 @@
         }
         assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
     }
+
+    public void testLargeSettingKey() {
+        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+        final String largeKey = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
+        final String testValue = "testValue";
+        synchronized (mLock) {
+            // Test system package
+            try {
+                settingsState.insertSettingLocked(largeKey, testValue, null, true, SYSTEM_PACKAGE);
+                fail("Should throw because it exceeded max string length");
+            } catch (IllegalArgumentException ex) {
+                assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+            }
+            // Test non system package
+            try {
+                settingsState.insertSettingLocked(largeKey, testValue, null, true, TEST_PACKAGE);
+                fail("Should throw because it exceeded max string length");
+            } catch (IllegalArgumentException ex) {
+                assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+            }
+        }
+    }
+
+    public void testLargeSettingValue() {
+        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        final String testKey = "testKey";
+        final String largeValue = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
+        synchronized (mLock) {
+            // Test system package
+            try {
+                settingsState.insertSettingLocked(testKey, largeValue, null, true, SYSTEM_PACKAGE);
+                fail("Should throw because it exceeded max string length");
+            } catch (IllegalArgumentException ex) {
+                assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+            }
+            // Test non system package
+            try {
+                settingsState.insertSettingLocked(testKey, largeValue, null, true, TEST_PACKAGE);
+                fail("Should throw because it exceeded max string length");
+            } catch (IllegalArgumentException ex) {
+                assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 30218a6..26912f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -226,7 +226,7 @@
                 listenToMetadata(device);
             } else {
                 stopListeningToStaleDeviceMetadata();
-                batteryLevel = device.getBatteryLevel();
+                batteryLevel = device.getMinBatteryLevelWithMemberDevices();
             }
 
             if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 6db8df9..05f837b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1662,8 +1662,9 @@
 
     @VisibleForTesting
     void onKeyguardTransitionChanged(TransitionStep transitionStep) {
-        boolean isTransitionToAod = transitionStep.getFrom().equals(KeyguardState.GONE)
-                && transitionStep.getTo().equals(KeyguardState.AOD);
+        boolean isTransitionToAod = transitionStep.getTo().equals(KeyguardState.AOD)
+                && (transitionStep.getFrom().equals(KeyguardState.GONE)
+                || transitionStep.getFrom().equals(KeyguardState.OCCLUDED));
         if (mIsInTransitionToAod != isTransitionToAod) {
             mIsInTransitionToAod = isTransitionToAod;
             updateShowEmptyShadeView();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index 5e7f68c..e5c55d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -168,7 +168,7 @@
         val btDevice = mock<BluetoothDevice>()
         whenever(cachedDevice2.device).thenReturn(btDevice)
         whenever(btDevice.getMetadata(BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn(null)
-        whenever(cachedDevice2.batteryLevel).thenReturn(25)
+        whenever(cachedDevice2.minBatteryLevelWithMemberDevices).thenReturn(25)
         addConnectedDevice(cachedDevice2)
 
         tile.handleUpdateState(state, /* arg= */ null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 6f431be..79cf932 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -628,6 +628,16 @@
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(eq(false), anyBoolean());
     }
 
+    @Test
+    public void updateEmptyShadeView_onKeyguardOccludedTransitionToAod_hidesView() {
+        initController(/* viewIsAttached= */ true);
+        mController.onKeyguardTransitionChanged(
+                new TransitionStep(
+                        /* from= */ KeyguardState.OCCLUDED,
+                        /* to= */ KeyguardState.AOD));
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(eq(false), anyBoolean());
+    }
+
     private LogMaker logMatcher(int category, int type) {
         return argThat(new LogMatcher(category, type));
     }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 309a9c0..5b25e89 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -321,9 +321,6 @@
                             if (DEBUG) {
                                 Slog.d(TAG, "publish system wallpaper changed!");
                             }
-                            if (localSync != null) {
-                                localSync.complete();
-                            }
                             notifyWallpaperChanged(wallpaper);
                         }
                     };
@@ -331,7 +328,7 @@
                     // If this was the system wallpaper, rebind...
                     bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper,
                             callback);
-                    notifyColorsWhich |= FLAG_SYSTEM;
+                    notifyColorsWhich |= wallpaper.mWhich;
                 }
 
                 if (lockWallpaperChanged) {
@@ -345,9 +342,6 @@
                             if (DEBUG) {
                                 Slog.d(TAG, "publish lock wallpaper changed!");
                             }
-                            if (localSync != null) {
-                                localSync.complete();
-                            }
                             notifyWallpaperChanged(wallpaper);
                         }
                     };
@@ -372,9 +366,8 @@
                 }
 
                 saveSettingsLocked(wallpaper.userId);
-                // Notify the client immediately if only lockscreen wallpaper changed.
-                if (lockWallpaperChanged && !sysWallpaperChanged) {
-                    notifyWallpaperChanged(wallpaper);
+                if ((sysWallpaperChanged || lockWallpaperChanged) && localSync != null) {
+                    localSync.complete();
                 }
             }
 
@@ -1383,7 +1376,6 @@
                             lockWp.connection.mWallpaper = lockWp;
                             mOriginalSystem.mWhich = FLAG_LOCK;
                             updateEngineFlags(mOriginalSystem);
-                            notifyWallpaperColorsChanged(lockWp, FLAG_LOCK);
                         } else {
                             // Failed rename, use current system wp for both
                             if (DEBUG) {
@@ -1403,7 +1395,6 @@
                         updateEngineFlags(mOriginalSystem);
                         mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem);
                         mLastLockWallpaper = mOriginalSystem;
-                        notifyWallpaperColorsChanged(mOriginalSystem, FLAG_LOCK);
                     }
                 } else if (mNewWallpaper.mWhich == FLAG_LOCK) {
                     // New wp is lock only, so old system+lock is now system only
@@ -1417,10 +1408,7 @@
                     }
                 }
             }
-
-            synchronized (mLock) {
-                saveSettingsLocked(mNewWallpaper.userId);
-            }
+            saveSettingsLocked(mNewWallpaper.userId);
 
             if (DEBUG) {
                 Slog.v(TAG, "--- wallpaper changed --");
@@ -3300,7 +3288,6 @@
                         if (DEBUG) {
                             Slog.d(TAG, "publish system wallpaper changed!");
                         }
-                        liveSync.complete();
                     }
                 };
 
@@ -3356,6 +3343,7 @@
                         }
                         mLockWallpaperMap.remove(newWallpaper.userId);
                     }
+                    if (liveSync != null) liveSync.complete();
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -3474,6 +3462,11 @@
         }
         // Has the component changed?
         if (!force && changingToSame(componentName, wallpaper)) {
+            try {
+                if (reply != null) reply.sendResult(null);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to send callback", e);
+            }
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index f0e4149..7cd07d6 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -151,6 +151,20 @@
                 return;
             }
 
+            // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are
+            //  inaccurate.
+            if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+                final Task capturedTask = mRecordedWindowContainer.asTask();
+                if (capturedTask.inPinnedWindowingMode()) {
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Content Recording: Display %d was already recording, but "
+                                    + "pause capture since the task is in PIP",
+                            mDisplayContent.getDisplayId());
+                    pauseRecording();
+                    return;
+                }
+            }
+
             ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                     "Content Recording: Display %d was already recording, so apply "
                             + "transformations if necessary",
@@ -292,6 +306,17 @@
             return;
         }
 
+        // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are inaccurate.
+        if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+            if (mRecordedWindowContainer.asTask().inPinnedWindowingMode()) {
+                ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                        "Content Recording: Display %d should start recording, but "
+                                + "don't yet since the task is in PIP",
+                        mDisplayContent.getDisplayId());
+                return;
+            }
+        }
+
         final Point surfaceSize = fetchSurfaceSizeIfPresent();
         if (surfaceSize == null) {
             ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
@@ -305,9 +330,6 @@
                         + "state %d",
                 mDisplayContent.getDisplayId(), mDisplayContent.getDisplayInfo().state);
 
-        // TODO(b/274790702): Do not start recording if waiting for consent - for now,
-        //  go ahead.
-
         // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
         mRecordedSurface = SurfaceControl.mirrorSurface(
                 mRecordedWindowContainer.getSurfaceControl());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index aa2b935..b8f6cb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -360,6 +363,39 @@
     }
 
     @Test
+    public void testTaskWindowingModeChanged_pip_stopsRecording() {
+        // WHEN a recording is ongoing.
+        mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+        // WHEN a configuration change arrives, and the task is now pinned.
+        mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+        Configuration configuration = mTask.getConfiguration();
+        mTask.onConfigurationChanged(configuration);
+
+        // THEN recording is paused.
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testTaskWindowingModeChanged_fullscreen_startsRecording() {
+        // WHEN a recording is ongoing.
+        mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+
+        // WHEN the task is now fullscreen.
+        mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        mContentRecorder.updateRecording();
+
+        // THEN recording is started.
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+    }
+
+    @Test
     public void testStartRecording_notifiesCallback_taskSession() {
         // WHEN a recording is ongoing.
         mContentRecorder.setContentRecordingSession(mTaskSession);
@@ -384,6 +420,45 @@
     }
 
     @Test
+    public void testStartRecording_taskInPIP_recordingNotStarted() {
+        // GIVEN a task is in PIP.
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+
+        // WHEN a recording tries to start.
+        mContentRecorder.updateRecording();
+
+        // THEN recording does not start.
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testStartRecording_taskInSplit_recordingStarted() {
+        // GIVEN a task is in PIP.
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+
+        // WHEN a recording tries to start.
+        mContentRecorder.updateRecording();
+
+        // THEN recording does not start.
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+    }
+
+    @Test
+    public void testStartRecording_taskInFullscreen_recordingStarted() {
+        // GIVEN a task is in PIP.
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        // WHEN a recording tries to start.
+        mContentRecorder.updateRecording();
+
+        // THEN recording does not start.
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+    }
+
+    @Test
     public void testOnVisibleRequestedChanged_notifiesCallback() {
         // WHEN a recording is ongoing.
         mContentRecorder.setContentRecordingSession(mTaskSession);
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
index 3870dfd..4f99f14 100644
--- a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
@@ -95,21 +95,29 @@
         String newTaskId = cinematicEffectRequest.getTaskId();
         // Previous request is still being processed.
         if (mCinematicEffectListenerWrapper != null) {
+            CinematicEffectResponse cinematicEffectResponse;
             if (mCinematicEffectListenerWrapper.mTaskId.equals(newTaskId)) {
-                invokeCinematicListenerAndCleanup(
-                        new CinematicEffectResponse.Builder(
-                                CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING, newTaskId)
-                                .build()
-                );
+                cinematicEffectResponse =  new CinematicEffectResponse.Builder(
+                        CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING, newTaskId)
+                        .build();
             } else {
-                invokeCinematicListenerAndCleanup(
-                        new CinematicEffectResponse.Builder(
-                                CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS,
-                                newTaskId).build()
-                );
+                cinematicEffectResponse =  new CinematicEffectResponse.Builder(
+                        CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS,
+                        newTaskId)
+                        .build();
             }
-            return;
+            try {
+                cinematicEffectListener.onCinematicEffectGenerated(cinematicEffectResponse);
+                return;
+            } catch (RemoteException e) {
+                if (isDebug()) {
+                    Slog.w(TAG, "RemoteException invoking cinematic effect listener for task["
+                            + mCinematicEffectListenerWrapper.mTaskId + "]");
+                }
+                return;
+            }
         }
+
         RemoteWallpaperEffectsGenerationService remoteService = ensureRemoteServiceLocked();
         if (remoteService != null) {
             remoteService.executeOnResolvedService(