Merge "Fail if the interface is not available when starting" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index 01117c9..7266606 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24371,8 +24371,6 @@
     field public static final int MEDIA_CALL_PAUSE = 4; // 0x4
     field public static final int MEDIA_CALL_PLAY = 5; // 0x5
     field public static final int MEDIA_CALL_PREPARE = 6; // 0x6
-    field public static final int MEDIA_CALL_PREPARE_DRM = 7; // 0x7
-    field public static final int MEDIA_CALL_PROVIDE_DRM_KEY_RESPONSE = 8; // 0x8
     field public static final int MEDIA_CALL_RELEASE_DRM = 12; // 0xc
     field public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13; // 0xd
     field public static final int MEDIA_CALL_SEEK_TO = 14; // 0xe
@@ -24381,8 +24379,6 @@
     field public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17; // 0x11
     field public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12
     field public static final int MEDIA_CALL_SET_DATA_SOURCE = 19; // 0x13
-    field public static final int MEDIA_CALL_SET_DRM_CONFIG_HELPER = 20; // 0x14
-    field public static final int MEDIA_CALL_SET_DRM_PROPERTY_STRING = 21; // 0x15
     field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22; // 0x16
     field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23; // 0x17
     field public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24; // 0x18
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1dc7549..ee667c2 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -541,13 +541,14 @@
             "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
 
     /** The profile is in disconnected state */
-    public static final int STATE_DISCONNECTED = 0;
+    public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
     /** The profile is in connecting state */
-    public static final int STATE_CONNECTING = 1;
+    public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
     /** The profile is in connected state */
-    public static final int STATE_CONNECTED = 2;
+    public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
     /** The profile is in disconnecting state */
-    public static final int STATE_DISCONNECTING = 3;
+    public static final int STATE_DISCONNECTING =
+            BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
 
     /** @hide */
     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
new file mode 100644
index 0000000..06ae2d3
--- /dev/null
+++ b/core/proto/android/bluetooth/enums.proto
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth;
+
+option java_outer_classname = "BluetoothProtoEnums";
+option java_multiple_files = true;
+
+// Bluetooth connection states.
+// Primarily used by android/bluetooth/BluetoothAdapter.java
+enum ConnectionStateEnum {
+  CONNECTION_STATE_DISCONNECTED = 0;
+  CONNECTION_STATE_CONNECTING = 1;
+  CONNECTION_STATE_CONNECTED = 2;
+  CONNECTION_STATE_DISCONNECTING = 3;
+}
\ No newline at end of file
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 0cc7441..f73c38e 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -130,22 +130,21 @@
  *         the internal player engine.</li>
  *         <li>IllegalStateException is
  *         thrown to prevent programming errors such as calling
- *         {@link #prepare()}, {@link #setDataSource(DataSourceDesc)}, or
- *         {@code setPlaylist} methods in an invalid state. </li>
+ *         {@link #prepare()}, {@link #setDataSource(DataSourceDesc)}
+ *         methods in an invalid state. </li>
  *         </ul>
  *         </li>
  *     <li>Calling
- *         {@link #setDataSource(DataSourceDesc)}, or
- *         {@code setPlaylist} transfers a
+ *         {@link #setDataSource(DataSourceDesc)} transfers a
  *         MediaPlayer2 object in the <em>Idle</em> state to the
  *         <em>Initialized</em> state.
  *         <ul>
  *         <li>An IllegalStateException is thrown if
- *         setDataSource() or setPlaylist() is called in any other state.</li>
+ *         setDataSource() is called in any other state.</li>
  *         <li>It is good programming
  *         practice to always look out for <code>IllegalArgumentException</code>
  *         and <code>IOException</code> that may be thrown from
- *         <code>setDataSource</code> and <code>setPlaylist</code> methods.</li>
+ *         <code>setDataSource</code>.</li>
  *         </ul>
  *         </li>
  *     <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
@@ -258,7 +257,7 @@
  * <tr><td>attachAuxEffect </p></td>
  *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
  *     <td>{Idle, Error} </p></td>
- *     <td>This method must be called after setDataSource or setPlaylist.
+ *     <td>This method must be called after setDataSource.
  *     Calling it does not change the object state. </p></td></tr>
  * <tr><td>getAudioSessionId </p></td>
  *     <td>any </p></td>
@@ -338,7 +337,7 @@
  *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
  *          Error} </p></td>
  *     <td>This method must be called in idle state as the audio session ID must be known before
- *         calling setDataSource or setPlaylist. Calling it does not change the object
+ *         calling setDataSource. Calling it does not change the object
  *         state. </p></td></tr>
  * <tr><td>setAudioStreamType (deprecated)</p></td>
  *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
@@ -358,13 +357,6 @@
  *     <td>Successful invoke of this method in a valid state transfers the
  *         object to the <em>Initialized</em> state. Calling this method in an
  *         invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>setPlaylist </p></td>
- *     <td>{Idle} </p></td>
- *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
- *          Error} </p></td>
- *     <td>Successful invoke of this method in a valid state transfers the
- *         object to the <em>Initialized</em> state. Calling this method in an
- *         invalid state throws an IllegalStateException.</p></td></tr>
  * <tr><td>setDisplay </p></td>
  *     <td>any </p></td>
  *     <td>{} </p></td>
@@ -500,6 +492,7 @@
      * This class implements the Java {@code AutoCloseable} interface and
      * may be used with try-with-resources.
      */
+    // This is a synchronous call.
     @Override
     public abstract void close();
 
@@ -511,6 +504,7 @@
      * prepared, the player will prepare the source and play.
      *
      */
+    // This is an asynchronous call.
     @Override
     public abstract void play();
 
@@ -521,18 +515,21 @@
      * call prepare().
      *
      */
+    // This is an asynchronous call.
     @Override
     public abstract void prepare();
 
     /**
      * Pauses playback. Call play() to resume.
      */
+    // This is an asynchronous call.
     @Override
     public abstract void pause();
 
     /**
      * Tries to play next data source if applicable.
      */
+    // This is an asynchronous call.
     @Override
     public abstract void skipToNext();
 
@@ -542,6 +539,7 @@
      *
      * @param msec the offset in milliseconds from the start to seek to
      */
+    // This is an asynchronous call.
     @Override
     public void seekTo(long msec) {
         seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
@@ -600,6 +598,7 @@
      * for the audio attributes to become effective thereafter.
      * @param attributes a non-null set of audio attributes
      */
+    // This is an asynchronous call.
     @Override
     public abstract void setAudioAttributes(@NonNull AudioAttributes attributes);
 
@@ -615,6 +614,7 @@
      *
      * @param dsd the descriptor of data source you want to play
      */
+    // This is an asynchronous call.
     @Override
     public abstract void setDataSource(@NonNull DataSourceDesc dsd);
 
@@ -624,6 +624,7 @@
      *
      * @param dsd the descriptor of data source you want to play after current one
      */
+    // This is an asynchronous call.
     @Override
     public abstract void setNextDataSource(@NonNull DataSourceDesc dsd);
 
@@ -632,6 +633,7 @@
      *
      * @param dsds the list of data sources you want to play after current one
      */
+    // This is an asynchronous call.
     @Override
     public abstract void setNextDataSources(@NonNull List<DataSourceDesc> dsds);
 
@@ -647,6 +649,7 @@
      * Configures the player to loop on the current data source.
      * @param loop true if the current data source is meant to loop.
      */
+    // This is an asynchronous call.
     @Override
     public abstract void loopCurrent(boolean loop);
 
@@ -659,6 +662,7 @@
      * by the player, see {@link #getPlaybackSpeed()}.
      * @param speed the desired playback speed
      */
+    // This is an asynchronous call.
     @Override
     public abstract void setPlaybackSpeed(float speed);
 
@@ -692,6 +696,7 @@
      * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
      * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
      */
+    // This is an asynchronous call.
     @Override
     public abstract void setPlayerVolume(float volume);
 
@@ -716,6 +721,7 @@
      * @param e the {@link Executor} to be used for the events.
      * @param cb the callback to receive the events.
      */
+    // This is a synchronous call.
     @Override
     public abstract void registerPlayerEventCallback(@NonNull Executor e,
             @NonNull PlayerEventCallback cb);
@@ -724,6 +730,7 @@
      * Removes a previously registered callback for player events
      * @param cb the callback to remove
      */
+    // This is a synchronous call.
     @Override
     public abstract void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb);
 
@@ -746,7 +753,7 @@
      * Invoke a generic method on the native player using opaque
      * parcels for the request and reply. Both payloads' format is a
      * convention between the java caller and the native player.
-     * Must be called after setDataSource or setPlaylist to make sure a native player
+     * Must be called after setDataSource to make sure a native player
      * exists. On failure, a RuntimeException is thrown.
      *
      * @param request Parcel with the data for the extension. The
@@ -769,6 +776,7 @@
      * @param label An application specific Object used to help to identify the completeness
      * of a batch of commands.
      */
+    // This is an asynchronous call.
     public void notifyWhenCommandLabelReached(Object label) { }
 
     /**
@@ -807,6 +815,7 @@
      * @throws IllegalStateException if the internal player engine has not been
      * initialized or has been released.
      */
+    // This is an asynchronous call.
     public abstract void setSurface(Surface surface);
 
     /* Do not change these video scaling mode values below without updating
@@ -855,6 +864,7 @@
     /**
      * Discards all pending commands.
      */
+    // This is a synchronous call.
     public abstract void clearPendingCommands();
 
     /**
@@ -878,6 +888,7 @@
      * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
      * does not correspond to a valid audio device.
      */
+    // This is an asynchronous call.
     @Override
     public abstract boolean setPreferredDevice(AudioDeviceInfo deviceInfo);
 
@@ -905,6 +916,7 @@
      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
      * the callback. If <code>null</code>, the handler on the main looper will be used.
      */
+    // This is a synchronous call.
     @Override
     public abstract void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
             Handler handler);
@@ -915,6 +927,7 @@
      * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
      * to remove.
      */
+    // This is a synchronous call.
     @Override
     public abstract void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener);
 
@@ -1070,6 +1083,7 @@
      * @throws IllegalArgumentException if params is invalid or not supported.
      * @hide
      */
+    // This is an asynchronous call.
     public void setBufferingParams(@NonNull BufferingParams params) { }
 
     /**
@@ -1152,6 +1166,7 @@
      *
      * @param params the playback params.
      */
+    // This is an asynchronous call.
     public abstract void setPlaybackParams(@NonNull PlaybackParams params);
 
     /**
@@ -1167,6 +1182,7 @@
      *
      * @param params the A/V sync params to apply
      */
+    // This is an asynchronous call.
     public abstract void setSyncParams(@NonNull SyncParams params);
 
     /**
@@ -1255,6 +1271,7 @@
      * {@link #SEEK_CLOSEST} often has larger performance overhead compared
      * to the other options if there is no sync frame located at msec.
      */
+    // This is an asynchronous call.
     public abstract void seekTo(long msec, @SeekMode int mode);
 
     /**
@@ -1327,6 +1344,7 @@
      * this method, you will have to initialize it again by setting the
      * data source and calling prepare().
      */
+    // This is a synchronous call.
     @Override
     public abstract void reset();
 
@@ -1365,6 +1383,7 @@
      * by calling this method.
      * This method must be called before one of the overloaded <code> setDataSource </code> methods.
      */
+    // This is an asynchronous call.
     public abstract void setAudioSessionId(int sessionId);
 
     /**
@@ -1389,6 +1408,7 @@
      * methods.
      * @param effectId system wide unique id of the effect to attach
      */
+    // This is an asynchronous call.
     public abstract void attachAuxEffect(int effectId);
 
 
@@ -1404,6 +1424,7 @@
      * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
      * @param level send level scalar
      */
+    // This is an asynchronous call.
     public abstract void setAuxEffectSendLevel(float level);
 
     /**
@@ -1618,6 +1639,7 @@
      *
      * @see android.media.MediaPlayer2#getTrackInfo
      */
+    // This is an asynchronous call.
     public abstract void selectTrack(int index);
 
     /**
@@ -1634,6 +1656,7 @@
      *
      * @see android.media.MediaPlayer2#getTrackInfo
      */
+    // This is an asynchronous call.
     public abstract void deselectTrack(int index);
 
     /** @hide */
@@ -1754,8 +1777,6 @@
          * <li>{@link #MEDIA_CALL_PAUSE}
          * <li>{@link #MEDIA_CALL_PLAY}
          * <li>{@link #MEDIA_CALL_PREPARE}
-         * <li>{@link #MEDIA_CALL_PREPARE_DRM}
-         * <li>{@link #MEDIA_CALL_PROVIDE_DRM_KEY_RESPONSE}
          * <li>{@link #MEDIA_CALL_RELEASE_DRM}
          * <li>{@link #MEDIA_CALL_RESTORE_DRM_KEYS}
          * <li>{@link #MEDIA_CALL_SEEK_TO}
@@ -1764,8 +1785,6 @@
          * <li>{@link #MEDIA_CALL_SET_AUDIO_SESSION_ID}
          * <li>{@link #MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL}
          * <li>{@link #MEDIA_CALL_SET_DATA_SOURCE}
-         * <li>{@link #MEDIA_CALL_SET_DRM_CONFIG_HELPER}
-         * <li>{@link #MEDIA_CALL_SET_DRM_PROPERTY_STRING}
          * <li>{@link #MEDIA_CALL_SET_NEXT_DATA_SOURCE}
          * <li>{@link #MEDIA_CALL_SET_NEXT_DATA_SOURCES}
          * <li>{@link #MEDIA_CALL_SET_PLAYBACK_PARAMS}
@@ -1804,12 +1823,14 @@
      * @param eventCallback the callback that will be run
      * @param executor the executor through which the callback should be invoked
      */
+    // This is a synchronous call.
     public abstract void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull MediaPlayer2EventCallback eventCallback);
 
     /**
      * Clears the {@link MediaPlayer2EventCallback}.
      */
+    // This is a synchronous call.
     public abstract void clearMediaPlayer2EventCallback();
 
     /**
@@ -1830,6 +1851,7 @@
      *
      * @hide
      */
+    // This is a synchronous call.
     public void setOnSubtitleDataListener(OnSubtitleDataListener listener) { }
 
 
@@ -1996,136 +2018,128 @@
     public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
 
     //--------------------------------------------------------------------------
-    /** The player just completed a call {@code attachAuxEffect}.
+    /** The player just completed a call {@link #attachAuxEffect}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_ATTACH_AUX_EFFECT = 1;
 
-    /** The player just completed a call {@code deselectTrack}.
+    /** The player just completed a call {@link #deselectTrack}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_DESELECT_TRACK = 2;
 
-    /** The player just completed a call {@code loopCurrent}.
+    /** The player just completed a call {@link #loopCurrent}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_LOOP_CURRENT = 3;
 
-    /** The player just completed a call {@code pause}.
+    /** The player just completed a call {@link #pause}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_PAUSE = 4;
 
-    /** The player just completed a call {@code play}.
+    /** The player just completed a call {@link #play}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_PLAY = 5;
 
-    /** The player just completed a call {@code prepare}.
+    /** The player just completed a call {@link #prepare}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_PREPARE = 6;
 
-    /** The player just completed a call {@code prepareDrm}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
-     */
-    public static final int MEDIA_CALL_PREPARE_DRM = 7;
-
-    /** The player just completed a call {@code provideDrmKeyResponse}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
-     */
-    public static final int MEDIA_CALL_PROVIDE_DRM_KEY_RESPONSE = 8;
-
-    /** The player just completed a call {@code releaseDrm}.
+    /** The player just completed a call {@link #releaseDrm}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_RELEASE_DRM = 12;
 
-    /** The player just completed a call {@code restoreDrmKeys}.
+    /** The player just completed a call {@link #restoreDrmKeys}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13;
 
-    /** The player just completed a call {@code seekTo}.
+    /** The player just completed a call {@link #seekTo}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SEEK_TO = 14;
 
-    /** The player just completed a call {@code selectTrack}.
+    /** The player just completed a call {@link #selectTrack}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SELECT_TRACK = 15;
 
-    /** The player just completed a call {@code setAudioAttributes}.
+    /** The player just completed a call {@link #setAudioAttributes}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_AUDIO_ATTRIBUTES = 16;
 
-    /** The player just completed a call {@code setAudioSessionId}.
+    /** The player just completed a call {@link #setAudioSessionId}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17;
 
-    /** The player just completed a call {@code setAuxEffectSendLevel}.
+    /** The player just completed a call {@link #setAuxEffectSendLevel}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18;
 
-    /** The player just completed a call {@code setDataSource}.
+    /** The player just completed a call {@link #setDataSource}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_DATA_SOURCE = 19;
 
-    /** The player just completed a call {@code setOnDrmConfigHelper}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
-     */
-    public static final int MEDIA_CALL_SET_DRM_CONFIG_HELPER = 20;
-
-    /** The player just completed a call {@code setDrmPropertyString}.
-     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
-     */
-    public static final int MEDIA_CALL_SET_DRM_PROPERTY_STRING = 21;
-
-    /** The player just completed a call {@code setNextDataSource}.
+    /** The player just completed a call {@link #setNextDataSource}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22;
 
-    /** The player just completed a call {@code setNextDataSources}.
+    /** The player just completed a call {@link #setNextDataSources}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23;
 
-    /** The player just completed a call {@code setPlaybackParams}.
+    /** The player just completed a call {@link #setPlaybackParams}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24;
 
-    /** The player just completed a call {@code setPlaybackSpeed}.
+    /** The player just completed a call {@link #setPlaybackSpeed}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_PLAYBACK_SPEED = 25;
 
-    /** The player just completed a call {@code setPlayerVolume}.
+    /** The player just completed a call {@link #setPlayerVolume}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_PLAYER_VOLUME = 26;
 
-    /** The player just completed a call {@code setSurface}.
+    /** The player just completed a call {@link #setSurface}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_SURFACE = 27;
 
-    /** The player just completed a call {@code setSyncParams}.
+    /** The player just completed a call {@link #setSyncParams}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SET_SYNC_PARAMS = 28;
 
-    /** The player just completed a call {@code skipToNext}.
+    /** The player just completed a call {@link #skipToNext}.
      * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
      */
     public static final int MEDIA_CALL_SKIP_TO_NEXT = 29;
 
+    /** The player just completed a call {@link #setBufferingParams}.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @hide
+     */
+    public static final int MEDIA_CALL_SET_BUFFERING_PARAMS = 1001;
+
+    /** The player just completed a call {@link #setPreferredDevice}.
+     * @see android.media.MediaPlayer2.MediaPlayer2EventCallback#onCallComplete
+     * @hide
+     */
+    public static final int MEDIA_CALL_SET_PREFERRED_DEVICE = 1002;
+
 
     // Modular DRM begin
 
@@ -2136,8 +2150,8 @@
      * 'securityLevel', which has to be set after DRM scheme creation but
      * before the DRM session is opened.
      *
-     * The only allowed DRM calls in this listener are {@code getDrmPropertyString}
-     * and {@code setDrmPropertyString}.
+     * The only allowed DRM calls in this listener are {@link #getDrmPropertyString}
+     * and {@link #setDrmPropertyString}.
      */
     public interface OnDrmConfigHelper
     {
@@ -2158,6 +2172,7 @@
      *
      * @param listener the callback that will be run
      */
+    // This is a synchronous call.
     public abstract void setOnDrmConfigHelper(OnDrmConfigHelper listener);
 
     /**
@@ -2176,7 +2191,7 @@
         public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { }
 
         /**
-         * Called to notify the client that {@code prepareDrm} is finished and ready for
+         * Called to notify the client that {@link #prepareDrm} is finished and ready for
          * key request/response.
          *
          * @param mp the {@code MediaPlayer2} associated with this callback
@@ -2196,12 +2211,14 @@
      * @param eventCallback the callback that will be run
      * @param executor the executor through which the callback should be invoked
      */
+    // This is a synchronous call.
     public abstract void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull DrmEventCallback eventCallback);
 
     /**
      * Clears the {@link DrmEventCallback}.
      */
+    // This is a synchronous call.
     public abstract void clearDrmEventCallback();
 
     /**
@@ -2248,10 +2265,10 @@
     /**
      * Prepares the DRM for the current source
      * <p>
-     * If {@code OnDrmConfigHelper} is registered, it will be called during
+     * If {@link OnDrmConfigHelper} is registered, it will be called during
      * preparation to allow configuration of the DRM properties before opening the
      * DRM session. Note that the callback is called synchronously in the thread that called
-     * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
+     * {@link #prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
      * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
      * <p>
      * If the device has not been provisioned before, this call also provisions the device
@@ -2281,6 +2298,7 @@
      * @throws ProvisioningServerErrorException   if provisioning is required but failed due to
      *                                            the request denied by the provisioning server
      */
+    // This is a synchronous call.
     public abstract void prepareDrm(@NonNull UUID uuid)
             throws UnsupportedSchemeException, ResourceBusyException,
                    ProvisioningNetworkErrorException, ProvisioningServerErrorException;
@@ -2294,6 +2312,7 @@
      *
      * @throws NoDrmSchemeException if there is no active DRM session to release
      */
+    // This is an asynchronous call.
     public abstract void releaseDrm() throws NoDrmSchemeException;
 
     /**
@@ -2359,6 +2378,7 @@
      * @throws DeniedByServerException if the response indicates that the
      * server rejected the request
      */
+    // This is a synchronous call.
     public abstract byte[] provideDrmKeyResponse(
             @Nullable byte[] keySetId, @NonNull byte[] response)
             throws NoDrmSchemeException, DeniedByServerException;
@@ -2369,6 +2389,7 @@
      *
      * @param keySetId identifies the saved key set to restore
      */
+    // This is an asynchronous call.
     public abstract void restoreDrmKeys(@NonNull byte[] keySetId)
             throws NoDrmSchemeException;
 
@@ -2396,6 +2417,7 @@
      * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
      * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
      */
+    // This is a synchronous call.
     public abstract void setDrmPropertyString(
             @NonNull @MediaDrm.StringProperty String propertyName, @NonNull String value)
             throws NoDrmSchemeException;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 127361a..d9359a4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -21,6 +21,7 @@
 
 import android.annotation.TargetApi;
 import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -65,6 +66,8 @@
     private static final long SHOW_HIDE_DURATION_MS = 300;
     // Don't show the onboarding until the user has launched this number of apps.
     private static final int SHOW_ON_APP_LAUNCH = 2;
+    // After explicitly dismissing, show again after launching this number of apps.
+    private static final int SHOW_ON_APP_LAUNCH_AFTER_DISMISS = 5;
 
     private final Context mContext;
     private final WindowManager mWindowManager;
@@ -84,6 +87,9 @@
     private boolean mTaskListenerRegistered;
     private boolean mLayoutAttachedToWindow;
     private boolean mBackgroundIsLight;
+    private int mLastTaskId;
+    private boolean mHasDismissed;
+    private int mNumAppsLaunchedSinceDismiss;
 
     private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() {
         @Override
@@ -94,14 +100,26 @@
                 hide(true);
                 return;
             }
+            if (info.id == mLastTaskId) {
+                // We only count launches that go to a new task.
+                return;
+            }
             int activityType = info.configuration.windowConfiguration.getActivityType();
-            int numAppsLaunched = Prefs.getInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, 0);
             if (activityType == ACTIVITY_TYPE_STANDARD) {
+                mLastTaskId = info.id;
+                int numAppsLaunched = mHasDismissed ? mNumAppsLaunchedSinceDismiss
+                        : Prefs.getInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, 0);
+                int showOnAppLaunch = mHasDismissed ? SHOW_ON_APP_LAUNCH_AFTER_DISMISS
+                        : SHOW_ON_APP_LAUNCH;
                 numAppsLaunched++;
-                if (numAppsLaunched >= SHOW_ON_APP_LAUNCH) {
+                if (numAppsLaunched >= showOnAppLaunch) {
                     show();
                 } else {
-                    Prefs.putInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, numAppsLaunched);
+                    if (mHasDismissed) {
+                        mNumAppsLaunchedSinceDismiss = numAppsLaunched;
+                    } else {
+                        Prefs.putInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, numAppsLaunched);
+                    }
                 }
             } else {
                 hide(false);
@@ -115,6 +133,7 @@
         public void onViewAttachedToWindow(View view) {
             if (view == mLayout) {
                 mLayoutAttachedToWindow = true;
+                mHasDismissed = false;
             }
         }
 
@@ -149,7 +168,11 @@
 
         mLayout.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
         mLayout.setBackground(mBackgroundDrawable);
-        mDismissView.setOnClickListener(v -> hide(true));
+        mDismissView.setOnClickListener(v -> {
+            hide(true);
+            mHasDismissed = true;
+            mNumAppsLaunchedSinceDismiss = 0;
+        });
 
         if (RESET_PREFS_FOR_DEBUG) {
             Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
@@ -180,6 +203,8 @@
             ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener);
             mTaskListenerRegistered = false;
         }
+        mHasDismissed = false;
+        mNumAppsLaunchedSinceDismiss = 0;
         hide(false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 407be62..11e57e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -665,7 +665,7 @@
     }
 
     private void notifyNavigationBarScreenOn() {
-        mNavigationBarView.notifyScreenOn();
+        mNavigationBarView.updateNavButtonIcons();
     }
 
     private void prepareNavigationBarView() {
@@ -813,7 +813,7 @@
                 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
                     activityManager.stopSystemLockTaskMode();
                     // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
+                    mNavigationBarView.updateNavButtonIcons();
                     return true;
                 } else if (v.getId() == btnId1) {
                     ButtonDispatcher button = btnId2 == R.id.recent_apps
@@ -835,7 +835,7 @@
                     // should stop lock task.
                     activityManager.stopSystemLockTaskMode();
                     // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
+                    mNavigationBarView.updateNavButtonIcons();
                     return true;
                 } else if (v.getId() == btnId2) {
                     return btnId2 == R.id.recent_apps
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 74fbed1..3b080cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -244,7 +244,7 @@
 
         mConfiguration = new Configuration();
         mConfiguration.updateFrom(context.getResources().getConfiguration());
-        updateIcons(context, Configuration.EMPTY, mConfiguration);
+        reloadNavIcons();
 
         mBarTransitions = new NavigationBarTransitions(this);
 
@@ -291,7 +291,7 @@
 
     public void onConnectionChanged(boolean isConnected) {
         updateSlippery();
-        setDisabledFlags(mDisabledFlags, true);
+        updateNavButtonIcons();
         setUpSwipeUpOnboarding(isConnected);
     }
 
@@ -403,6 +403,10 @@
                 R.drawable.ic_sysbar_home_carmode, R.drawable.ic_sysbar_home_carmode);
     }
 
+    private void reloadNavIcons() {
+        updateIcons(mContext, Configuration.EMPTY, mConfiguration);
+    }
+
     private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
         if (oldConfig.orientation != newConfig.orientation
                 || oldConfig.densityDpi != newConfig.densityDpi) {
@@ -482,20 +486,11 @@
 
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        // Reload all the icons
-        updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
+        reloadNavIcons();
 
         super.setLayoutDirection(layoutDirection);
     }
 
-    public void notifyScreenOn() {
-        setDisabledFlags(mDisabledFlags, true);
-    }
-
-    public void setNavigationIconHints(int hints) {
-        setNavigationIconHints(hints, false);
-    }
-
     private KeyButtonDrawable getBackIconWithAlt(boolean carMode, boolean landscape) {
         return landscape
                 ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon
@@ -508,8 +503,8 @@
                 : carMode ? mBackCarModeIcon : mBackIcon;
     }
 
-    public void setNavigationIconHints(int hints, boolean force) {
-        if (!force && hints == mNavigationIconHints) return;
+    public void setNavigationIconHints(int hints) {
+        if (hints == mNavigationIconHints) return;
         final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
         if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
             mTransitionListener.onBackAltCleared();
@@ -519,16 +514,32 @@
                 "Navigation icon hints = " + hints,
                 500).show();
         }
-
         mNavigationIconHints = hints;
+        updateNavButtonIcons();
+    }
 
+    public void setDisabledFlags(int disabledFlags) {
+        if (mDisabledFlags == disabledFlags) return;
+
+        final boolean overviewEnabledBefore = isOverviewEnabled();
+        mDisabledFlags = disabledFlags;
+
+        // Update icons if overview was just enabled to ensure the correct icons are present
+        if (!overviewEnabledBefore && isOverviewEnabled()) {
+            reloadNavIcons();
+        }
+
+        updateNavButtonIcons();
+    }
+
+    public void updateNavButtonIcons() {
         // We have to replace or restore the back and home button icons when exiting or entering
         // carmode, respectively. Recents are not available in CarMode in nav bar so change
         // to recent icon is not required.
-        KeyButtonDrawable backIcon = (backAlt)
-                ? getBackIconWithAlt(mUseCarModeUi, mVertical)
-                : getBackIcon(mUseCarModeUi, mVertical);
-
+        KeyButtonDrawable backIcon
+                = ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0)
+                        ? getBackIconWithAlt(mUseCarModeUi, mVertical)
+                        : getBackIcon(mUseCarModeUi, mVertical);
         getBackButton().setImageDrawable(backIcon);
 
         updateRecentsIcon();
@@ -542,8 +553,8 @@
         // Update IME button visibility, a11y and rotate button always overrides the appearance
         final boolean showImeButton =
                 !mShowAccessibilityButton &&
-                !mShowRotateButton &&
-                ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
+                        !mShowRotateButton &&
+                        ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
         getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
         getImeSwitchButton().setImageDrawable(mImeIcon);
 
@@ -558,26 +569,14 @@
         setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
         getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
 
-        setDisabledFlags(mDisabledFlags, true);
-
         mBarTransitions.reapplyDarkIntensity();
-    }
 
-    public void setDisabledFlags(int disabledFlags) {
-        setDisabledFlags(disabledFlags, false);
-    }
-
-    public void setDisabledFlags(int disabledFlags, boolean force) {
-        if (!force && mDisabledFlags == disabledFlags) return;
-
-        mDisabledFlags = disabledFlags;
-
-        boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
+        boolean disableHome = ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
 
         // Always disable recents when alternate car mode UI is active.
         boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
 
-        boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
+        boolean disableBack = ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
 
         // When screen pinning, don't hide back and home when connected service or back and
@@ -670,7 +669,7 @@
 
     public void updateStates() {
         updateSlippery();
-        setDisabledFlags(mDisabledFlags, true);
+        updateNavButtonIcons();
     }
 
     private void updateSlippery() {
@@ -773,7 +772,7 @@
         }
 
         // Hide/restore other button visibility, if necessary
-        setNavigationIconHints(mNavigationIconHints, true);
+        updateNavButtonIcons();
     }
 
     public boolean isRotateButtonVisible() { return mShowRotateButton; }
@@ -802,8 +801,8 @@
     public void onOverviewProxyConnectionChanged(boolean isConnected) {
         updateStates();
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-        updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
-        setNavigationIconHints(mNavigationIconHints, true);
+        reloadNavIcons();
+        updateNavButtonIcons();
     }
 
     @Override
@@ -879,7 +878,6 @@
 
         // force the low profile & disabled states into compliance
         mBarTransitions.init();
-        setDisabledFlags(mDisabledFlags, true /* force */);
         setMenuVisibility(mShowMenu, true /* force */);
 
         if (DEBUG) {
@@ -892,7 +890,7 @@
             resolveLayoutDirection();
         }
         updateTaskSwitchHelper();
-        setNavigationIconHints(mNavigationIconHints, true);
+        updateNavButtonIcons();
 
         getHomeButton().setVertical(mVertical);
     }
@@ -937,7 +935,7 @@
         if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi
                 || mConfiguration.getLayoutDirection() != newConfig.getLayoutDirection()) {
             // If car mode or density changes, we need to reset the icons.
-            setNavigationIconHints(mNavigationIconHints, true);
+            updateNavButtonIcons();
         }
         mConfiguration.updateFrom(newConfig);
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index bcfe1b6..5eee9ed 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -52,6 +52,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
 import android.os.Parcelable;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -87,7 +88,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.os.HandlerCaller;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.autofill.ui.PendingUi;
@@ -158,6 +158,9 @@
     @GuardedBy("mLock")
     private IAutoFillManagerClient mClient;
 
+    @GuardedBy("mLock")
+    private DeathRecipient mClientVulture;
+
     private final RemoteFillService mRemoteFillService;
 
     @GuardedBy("mLock")
@@ -509,7 +512,7 @@
         mWtfHistory = wtfHistory;
         mComponentName = componentName;
         mCompatMode = compatMode;
-        mClient = IAutoFillManagerClient.Stub.asInterface(client);
+        setClientLocked(client);
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
                 .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
@@ -539,13 +542,44 @@
                 return;
             }
             mActivityToken = newActivity;
-            mClient = IAutoFillManagerClient.Stub.asInterface(newClient);
+            setClientLocked(newClient);
 
             // The tracked id are not persisted in the client, hence update them
             updateTrackedIdsLocked();
         }
     }
 
+    @GuardedBy("mLock")
+    private void setClientLocked(@NonNull IBinder client) {
+        unlinkClientVultureLocked();
+        mClient = IAutoFillManagerClient.Stub.asInterface(client);
+        mClientVulture = () -> {
+            Slog.d(TAG, "handling death of " + mActivityToken + " when saving=" + mIsSaving);
+            synchronized (mLock) {
+                if (mIsSaving) {
+                    mUi.hideFillUi(this);
+                } else {
+                    mUi.destroyAll(mPendingSaveUi, this, false);
+                }
+            }
+        };
+        try {
+            mClient.asBinder().linkToDeath(mClientVulture, 0);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "could not set binder death listener on autofill client: " + e);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void unlinkClientVultureLocked() {
+        if (mClient != null && mClientVulture != null) {
+            final boolean unlinked = mClient.asBinder().unlinkToDeath(mClientVulture, 0);
+            if (!unlinked) {
+                Slog.w(TAG, "unlinking vulture from death failed for " + mActivityToken);
+            }
+        }
+    }
+
     // FillServiceCallbacks
     @Override
     public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
@@ -2443,6 +2477,7 @@
         if (mDestroyed) {
             return null;
         }
+        unlinkClientVultureLocked();
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index e28a204..21a39e4 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -136,7 +136,7 @@
      * Hides the fill UI.
      */
     public void hideFillUi(@NonNull AutoFillUiCallback callback) {
-        mHandler.post(() -> hideFillUiUiThread(callback));
+        mHandler.post(() -> hideFillUiUiThread(callback, true));
     }
 
     /**
@@ -189,7 +189,7 @@
                 @Override
                 public void onResponsePicked(FillResponse response) {
                     log.setType(MetricsEvent.TYPE_DETAIL);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                     if (mCallback != null) {
                         mCallback.authenticate(response.getRequestId(),
                                 AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED,
@@ -200,7 +200,7 @@
                 @Override
                 public void onDatasetPicked(Dataset dataset) {
                     log.setType(MetricsEvent.TYPE_ACTION);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                     if (mCallback != null) {
                         final int datasetIndex = response.getDatasets().indexOf(dataset);
                         mCallback.fill(response.getRequestId(), datasetIndex, dataset);
@@ -210,7 +210,7 @@
                 @Override
                 public void onCanceled() {
                     log.setType(MetricsEvent.TYPE_DISMISS);
-                    hideFillUiUiThread(callback);
+                    hideFillUiUiThread(callback, true);
                 }
 
                 @Override
@@ -367,9 +367,9 @@
     }
 
     @android.annotation.UiThread
-    private void hideFillUiUiThread(@Nullable AutoFillUiCallback callback) {
+    private void hideFillUiUiThread(@Nullable AutoFillUiCallback callback, boolean notifyClient) {
         if (mFillUi != null && (callback == null || callback == mCallback)) {
-            mFillUi.destroy();
+            mFillUi.destroy(notifyClient);
             mFillUi = null;
         }
     }
@@ -413,13 +413,13 @@
     @android.annotation.UiThread
     private void destroyAllUiThread(@Nullable PendingUi pendingSaveUi,
             @Nullable AutoFillUiCallback callback, boolean notifyClient) {
-        hideFillUiUiThread(callback);
+        hideFillUiUiThread(callback, notifyClient);
         destroySaveUiUiThread(pendingSaveUi, notifyClient);
     }
 
     @android.annotation.UiThread
     private void hideAllUiThread(@Nullable AutoFillUiCallback callback) {
-        hideFillUiUiThread(callback);
+        hideFillUiUiThread(callback, true);
         final PendingUi pendingSaveUi = hideSaveUiUiThread(callback);
         if (pendingSaveUi != null && pendingSaveUi.getState() == PendingUi.STATE_FINISHED) {
             if (sDebug) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index a32078c..ef4656b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -415,10 +415,15 @@
         applyNewFilterText();
     }
 
-    public void destroy() {
+    public void destroy(boolean notifyClient) {
         throwIfDestroyed();
+        if (mWindow != null) {
+            mWindow.hide(false);
+        }
         mCallback.onDestroy();
-        mCallback.requestHideFillUi();
+        if (notifyClient) {
+            mCallback.requestHideFillUi();
+        }
         mDestroyed = true;
     }
 
@@ -644,6 +649,10 @@
          * Hides the window.
          */
         void hide() {
+            hide(true);
+        }
+
+        void hide(boolean destroyCallbackOnError) {
             try {
                 if (mShowing) {
                     mWm.removeView(mContentView);
@@ -654,7 +663,9 @@
                 // happen - since show() and hide() are always called in the UIThread - but if it
                 // does, it should not crash the system.
                 Slog.e(TAG, "Exception hiding window ", e);
-                mCallback.onDestroy();
+                if (destroyCallbackOnError) {
+                    mCallback.onDestroy();
+                }
             } finally {
                 mOverlayControl.showOverlays();
             }