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();
}