Merge "Add runtime_native_boot namespace"
diff --git a/api/current.txt b/api/current.txt
index ab18d72..9dec22e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24142,8 +24142,10 @@
field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
field public static final String PARAMETER_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
+ field public static final String PARAMETER_KEY_OFFSET_TIME = "time-offset-us";
field public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
field public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+ field public static final String PARAMETER_KEY_SUSPEND_TIME = "drop-start-time-us";
field public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
@@ -24988,6 +24990,7 @@
field public static final String KEY_COLOR_STANDARD = "color-standard";
field public static final String KEY_COLOR_TRANSFER = "color-transfer";
field public static final String KEY_COMPLEXITY = "complexity";
+ field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
field public static final String KEY_DURATION = "durationUs";
field public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
field public static final String KEY_FRAME_RATE = "frame-rate";
diff --git a/api/system-current.txt b/api/system-current.txt
index 45d5f63..4cb5eb0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6309,8 +6309,6 @@
public abstract class ContentCaptureService extends android.app.Service {
ctor public ContentCaptureService();
- method @NonNull public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
- method @NonNull public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
method public void onConnected();
method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
@@ -6319,9 +6317,7 @@
method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
method public void onDisconnected();
method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
- method public final void setActivityContentCaptureEnabled(@NonNull android.content.ComponentName, boolean);
method public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
- method public final void setPackageContentCaptureEnabled(@NonNull String, boolean);
field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 5f47e06..63f9b59 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2144,30 +2144,24 @@
}
optional HardwareType hardware_type = 1;
- /* hardware_location allows vendors to differentiate between multiple instances of
+ /**
+ * hardware_location allows vendors to differentiate between multiple instances of
* the same hardware_type. The specific locations are vendor defined integers,
* referring to board-specific numbering schemes.
*/
optional int32 hardware_location = 2;
- /* failure_code is specific to the HardwareType of the failed hardware.
- * It should use the enum values defined below.
+ /**
+ * failure_code is specific to the HardwareType of the failed hardware.
+ * It should use one of the enum values defined below.
*/
- enum MicrophoneFailureCode {
- MICROPHONE_FAILURE_COMPLETE = 0;
- }
- enum CodecFailureCode {
- CODEC_FAILURE_COMPLETE = 0;
- }
- enum SpeakerFailureCode {
- SPEAKER_FAILURE_COMPLETE = 0;
- SPEAKER_FAILURE_HIGH_Z = 1;
- SPEAKER_FAILURE_SHORT = 2;
- }
- enum FingerprintFailureCode {
- FINGERPRINT_FAILURE_COMPLETE = 0;
- FINGERPRINT_SENSOR_BROKEN = 1;
- FINGERPRINT_TOO_MANY_DEAD_PIXELS = 2;
+ enum HardwareErrorCode {
+ UNKNOWN = 0;
+ COMPLETE = 1;
+ SPEAKER_HIGH_Z = 2;
+ SPEAKER_SHORT = 3;
+ FINGERPRINT_SENSOR_BROKEN = 4;
+ FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
}
optional int32 failure_code = 3;
}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 020de7f..cc2e59a 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -48,9 +48,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Collections;
import java.util.List;
-import java.util.Set;
/**
* A service used to capture the content of the screen to provide contextual data in other areas of
@@ -166,10 +164,6 @@
/**
* Explicitly limits content capture to the given packages and activities.
*
- * <p>When the whitelist is set, it overrides the values passed to
- * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}
- * and {@link #setPackageContentCaptureEnabled(String, boolean)}.
- *
* <p>To reset the whitelist, call it passing {@code null} to both arguments.
*
* <p>Useful when the service wants to restrict content capture to a category of apps, like
@@ -194,76 +188,6 @@
}
/**
- * Defines whether content capture should be enabled for activities with such
- * {@link android.content.ComponentName}.
- *
- * <p>Useful to blacklist a particular activity.
- */
- public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
- boolean enabled) {
- final IContentCaptureServiceCallback callback = mCallback;
- if (callback == null) {
- Log.w(TAG, "setActivityContentCaptureEnabled(): no server callback");
- return;
- }
- try {
- callback.setActivityContentCaptureEnabled(activity, enabled);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Defines whether content capture should be enabled for activities of the app with such
- * {@code packageName}.
- *
- * <p>Useful to blacklist any activity from a particular app.
- */
- public final void setPackageContentCaptureEnabled(@NonNull String packageName,
- boolean enabled) {
- final IContentCaptureServiceCallback callback = mCallback;
- if (callback == null) {
- Log.w(TAG, "setPackageContentCaptureEnabled(): no server callback");
- return;
- }
- try {
- callback.setPackageContentCaptureEnabled(packageName, enabled);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Gets the activities where content capture was disabled by
- * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}.
- */
- @NonNull
- public final Set<ComponentName> getContentCaptureDisabledActivities() {
- final IContentCaptureServiceCallback callback = mCallback;
- if (callback == null) {
- Log.w(TAG, "getContentCaptureDisabledActivities(): no server callback");
- return Collections.emptySet();
- }
- //TODO(b/122595322): implement (using SyncResultReceiver)
- return null;
- }
-
- /**
- * Gets the apps where content capture was disabled by
- * {@link #setPackageContentCaptureEnabled(String, boolean)}.
- */
- @NonNull
- public final Set<String> getContentCaptureDisabledPackages() {
- final IContentCaptureServiceCallback callback = mCallback;
- if (callback == null) {
- Log.w(TAG, "getContentCaptureDisabledPackages(): no server callback");
- return Collections.emptySet();
- }
- //TODO(b/122595322): implement (using SyncResultReceiver)
- return null;
- }
-
- /**
* Called when the Android system connects to service.
*
* <p>You should generally do initialization here rather than in {@link #onCreate}.
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
index e84bd6f..2a729b6 100644
--- a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -28,8 +28,4 @@
*/
oneway interface IContentCaptureServiceCallback {
void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
- void setActivityContentCaptureEnabled(in ComponentName activity, boolean enabled);
- void setPackageContentCaptureEnabled(in String packageName, boolean enabled);
- void getContentCaptureDisabledActivities(in IResultReceiver receiver);
- void getContentCaptureDisabledPackages(in IResultReceiver receiver);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ecbec65..cd5207c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -492,7 +492,7 @@
if (mBackgroundControl == null) {
return;
}
- if ((mSurfaceFlags & PixelFormat.OPAQUE) != 0) {
+ if ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) {
mBackgroundControl.show();
mBackgroundControl.setLayer(Integer.MIN_VALUE);
} else {
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index c256d57..eef40e1 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -341,10 +341,10 @@
// the proper ordering of these system-wide.
// =======================================================================================
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static INotificationManager sService;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
static private INotificationManager getService() {
if (sService != null) {
return sService;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e7a1c49..345058b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -276,6 +276,7 @@
"libmediametrics",
"libmeminfo",
"libaudioclient",
+ "libaudiopolicy",
"libjpeg",
"libusbhost",
"libharfbuzz_ng",
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 080c5d5..18f0cae 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -25,6 +25,7 @@
import android.annotation.WorkerThread;
import android.content.res.ResourcesImpl;
import android.hardware.HardwareBuffer;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -77,7 +78,7 @@
*/
private boolean mRequestPremultiplied;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769491)
private byte[] mNinePatchChunk; // may be null
@UnsupportedAppUsage
private NinePatch.InsetStruct mNinePatchInsets; // may be null
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index d945635..b67aea2 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -142,8 +142,10 @@
void SkiaRecordingCanvas::drawWebViewFunctor(int functor) {
FunctorDrawable* functorDrawable;
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
+ // interop is disabled.
functorDrawable =
- mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas());
+ mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, asSkCanvas());
} else {
functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas());
}
diff --git a/media/Android.bp b/media/Android.bp
index 1aefebe..141d415c 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -102,7 +102,8 @@
"--hide MissingPermission --hide BroadcastBehavior " +
"--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
"--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
- "--hide HiddenTypedefConstant "
+ "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " +
+ " --show-annotation android.annotation.TestApi "
droidstubs {
name: "updatable-media-stubs",
@@ -110,8 +111,7 @@
":updatable-media-srcs-without-aidls",
":framework-media-annotation-srcs",
],
- args: metalava_updatable_media_args + " --show-annotation android.annotation.SystemApi " +
- " --show-annotation android.annotation.TestApi ",
+ args: metalava_updatable_media_args,
// Ideally, sdk_version here should be "current_system", but "current - 1" is used
// to avoid dependency cycle with framework.
sdk_version: "28",
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index 1d763ce..0af47e8 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -402,7 +402,7 @@
&& (mClientPortId == that.mClientPortId)
&& (mClientSilenced == that.mClientSilenced)
&& (mDeviceSource == that.mDeviceSource)
- && (mClientEffects.equals(that.mClientEffects))
- && (mDeviceEffects.equals(that.mDeviceEffects)));
+ && (Arrays.equals(mClientEffects, that.mClientEffects))
+ && (Arrays.equals(mDeviceEffects, that.mDeviceEffects)));
}
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0c3d625..c6c2fdd 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3373,6 +3373,8 @@
/**
* Change a video encoder's target bitrate on the fly. The value is an
* Integer object containing the new bitrate in bps.
+ *
+ * @see #setParameters(Bundle)
*/
public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
@@ -3384,12 +3386,43 @@
* input-side of the encoder in that case.
* The value is an Integer object containing the value 1 to suspend
* or the value 0 to resume.
+ *
+ * @see #setParameters(Bundle)
*/
public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
/**
+ * When {@link #PARAMETER_KEY_SUSPEND} is present, the client can also
+ * optionally use this key to specify the timestamp (in micro-second)
+ * at which the suspend/resume operation takes effect.
+ *
+ * Note that the specified timestamp must be greater than or equal to the
+ * timestamp of any previously queued suspend/resume operations.
+ *
+ * The value is a long int, indicating the timestamp to suspend/resume.
+ *
+ * @see #setParameters(Bundle)
+ */
+ public static final String PARAMETER_KEY_SUSPEND_TIME = "drop-start-time-us";
+
+ /**
+ * Specify an offset (in micro-second) to be added on top of the timestamps
+ * onward. A typical use case is to apply an adjust to the timestamps after
+ * a period of pause by the user.
+ *
+ * This parameter can only be used on an encoder in "surface-input" mode.
+ *
+ * The value is a long int, indicating the timestamp offset to be applied.
+ *
+ * @see #setParameters(Bundle)
+ */
+ public static final String PARAMETER_KEY_OFFSET_TIME = "time-offset-us";
+
+ /**
* Request that the encoder produce a sync frame "soon".
* Provide an Integer with the value 0.
+ *
+ * @see #setParameters(Bundle)
*/
public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index c82b5f6..4ca0216 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -463,6 +463,63 @@
= "repeat-previous-frame-after";
/**
+ * Instruct the video encoder in "surface-input" mode to drop excessive
+ * frames from the source, so that the input frame rate to the encoder
+ * does not exceed the specified fps.
+ *
+ * The associated value is a float, representing the max frame rate to
+ * feed the encoder at.
+ *
+ * @hide
+ */
+ public static final String KEY_MAX_FPS_TO_ENCODER
+ = "max-fps-to-encoder";
+
+ /**
+ * Instruct the video encoder in "surface-input" mode to limit the gap of
+ * timestamp between any two adjacent frames fed to the encoder to the
+ * specified amount (in micro-second).
+ *
+ * The associated value is a long int. When positive, it represents the max
+ * timestamp gap between two adjacent frames fed to the encoder. When negative,
+ * the absolute value represents a fixed timestamp gap between any two adjacent
+ * frames fed to the encoder. Note that this will also apply even when the
+ * original timestamp goes backward in time. Under normal conditions, such frames
+ * would be dropped and not sent to the encoder.
+ *
+ * The output timestamp will be restored to the original timestamp and will
+ * not be affected.
+ *
+ * This is used in some special scenarios where input frames arrive sparingly
+ * but it's undesirable to allocate more bits to any single frame, or when it's
+ * important to ensure all frames are captured (rather than captured in the
+ * correct order).
+ *
+ * @hide
+ */
+ public static final String KEY_MAX_PTS_GAP_TO_ENCODER
+ = "max-pts-gap-to-encoder";
+
+ /**
+ * If specified when configuring a video encoder that's in "surface-input"
+ * mode, it will instruct the encoder to put the surface source in suspended
+ * state when it's connected. No video frames will be accepted until a resume
+ * operation (see {@link MediaCodec#PARAMETER_KEY_SUSPEND}), optionally with
+ * timestamp specified via {@link MediaCodec#PARAMETER_KEY_SUSPEND_TIME}, is
+ * received.
+ *
+ * The value is an integer, with 1 indicating to create with the surface
+ * source suspended, or 0 otherwise. The default value is 0.
+ *
+ * If this key is not set or set to 0, the surface source will accept buffers
+ * as soon as it's connected to the encoder (although they may not be encoded
+ * immediately). This key can be used when the client wants to prepare the
+ * encoder session in advance, but do not want to accept buffers immediately.
+ */
+ public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED
+ = "create-input-buffers-suspended";
+
+ /**
* If specified when configuring a video decoder rendering to a surface,
* causes the decoder to output "blank", i.e. black frames to the surface
* when stopped to clear out any previously displayed contents.
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 5f51320..e08dab4 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -26,7 +26,6 @@
#include <media/AudioTrack.h>
#include "SoundPool.h"
#include "SoundPoolThread.h"
-#include <media/AudioPolicyHelper.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaExtractor.h>
#include <media/NdkMediaFormat.h>
@@ -746,7 +745,8 @@
// initialize track
size_t afFrameCount;
uint32_t afSampleRate;
- audio_stream_type_t streamType = audio_attributes_to_stream_type(mSoundPool->attributes());
+ audio_stream_type_t streamType =
+ AudioSystem::attributesToStreamType(*mSoundPool->attributes());
if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
afFrameCount = kDefaultFrameCount;
}
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
index e43a60c..6deb47f 100644
--- a/native/webview/plat_support/draw_functor.cpp
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -177,6 +177,9 @@
webview_functor_callbacks.vk.initialize = &initializeVk;
webview_functor_callbacks.vk.draw = &drawVk;
webview_functor_callbacks.vk.postDraw = &postDrawVk;
+ // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor
+ // no longer uses GL interop.
+ webview_functor_callbacks.gles.draw = &draw_gl;
break;
}
callbacks_initialized = true;
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index b7d8492..b6b229c 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -105,6 +105,7 @@
protected AssistantSettings.Factory mSettingsFactory = AssistantSettings.FACTORY;
@VisibleForTesting
protected AssistantSettings mSettings;
+ private SmsHelper mSmsHelper;
public Assistant() {
}
@@ -122,6 +123,18 @@
mAgingHelper = new AgingHelper(getContext(),
mNotificationCategorizer,
new AgingCallback());
+ mSmsHelper = new SmsHelper(this);
+ mSmsHelper.initialize();
+ }
+
+ @Override
+ public void onDestroy() {
+ // This null check is only for the unit tests as ServiceTestCase.tearDown calls onDestroy
+ // without having first called onCreate.
+ if (mSmsHelper != null) {
+ mSmsHelper.destroy();
+ }
+ super.onDestroy();
}
private void loadFile() {
@@ -215,7 +228,7 @@
return null;
}
NotificationEntry entry =
- new NotificationEntry(mPackageManager, sbn, channel, SmsHelper.getInstance(this));
+ new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
return createEnqueuedNotificationAdjustment(
entry, suggestions.actions, suggestions.replies);
@@ -262,7 +275,7 @@
Ranking ranking = getRanking(sbn.getKey(), rankingMap);
if (ranking != null && ranking.getChannel() != null) {
NotificationEntry entry = new NotificationEntry(mPackageManager,
- sbn, ranking.getChannel(), SmsHelper.getInstance(this));
+ sbn, ranking.getChannel(), mSmsHelper);
String key = getKey(
sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
@@ -398,7 +411,6 @@
@Override
public void onListenerConnected() {
if (DEBUG) Log.i(TAG, "CONNECTED");
- SmsHelper.getInstance(this).initialize();
try {
mFile = new AtomicFile(new File(new File(
Environment.getDataUserCePackageDirectory(
@@ -415,7 +427,6 @@
@Override
public void onListenerDisconnected() {
- SmsHelper.getInstance(this).destroy();
if (mAgingHelper != null) {
mAgingHelper.onDestroy();
}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java
index b077138..07be0b8 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java
@@ -33,23 +33,11 @@
public class SmsHelper {
private static final String TAG = "SmsHelper";
- private static SmsHelper sSmsHelper;
- private static final Object sLock = new Object();
-
private final Context mContext;
private ComponentName mDefaultSmsApplication;
private BroadcastReceiver mBroadcastReceiver;
- static SmsHelper getInstance(Context context) {
- synchronized (sLock) {
- if (sSmsHelper == null) {
- sSmsHelper = new SmsHelper(context);
- }
- return sSmsHelper;
- }
- }
-
- private SmsHelper(Context context) {
+ SmsHelper(Context context) {
mContext = context.getApplicationContext();
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1060211..81c00bc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -23,8 +23,9 @@
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
<!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
<dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
- <!-- The distance from a side of device of the navigation bar to start an edge swipe -->
- <dimen name="navigation_bar_edge_swipe_threshold">48dp</dimen>
+ <!-- The default distance from a side of the device to start an edge swipe from -->
+ <dimen name="navigation_bar_default_edge_width">48dp</dimen>
+ <dimen name="navigation_bar_default_edge_height">500dp</dimen>
<!-- thickness (height) of the dead zone at the top of the navigation bar,
reducing false presses on navbar buttons; approx 2mm -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 56d9bf4c..5365dcf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1829,6 +1829,9 @@
<!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
<string name="nav_bar">Navigation bar</string>
+ <!-- Label for navigation edge panel for gestures [CHAR LIMIT=60] -->
+ <string name="nav_bar_edge_panel" translatable="false">Navigation bar Edge Panel</string>
+
<!-- SysUI Tuner: Button that controls layout of navigation bar [CHAR LIMIT=60] -->
<string name="nav_bar_layout">Layout</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 2ce6965..d5bd2b2 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -21,12 +21,15 @@
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
+import android.os.Handler;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
@@ -206,6 +209,7 @@
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
+ boolean missingSimsWithSubs = false;
CharSequence displayText = null;
List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
@@ -252,6 +256,7 @@
// described above.
displayText = makeCarrierStringOnEmergencyCapable(
getMissingSimMessage(), subs.get(0).getCarrierName());
+ missingSimsWithSubs = true;
} else {
// We don't have a SubscriptionInfo to get the emergency calls only from.
// Grab it from the old sticky broadcast if possible instead. We can use it
@@ -288,12 +293,14 @@
displayText = getAirplaneModeMessage();
}
+ Handler handler = Dependency.get(Dependency.MAIN_HANDLER);
+ final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
+ displayText,
+ displayText.toString().split(mSeparator.toString()),
+ anySimReadyAndInService && !missingSimsWithSubs,
+ subsIds);
if (mCarrierTextCallback != null) {
- mCarrierTextCallback.updateCarrierInfo(new CarrierTextCallbackInfo(
- displayText,
- displayText.toString().split(mSeparator.toString()),
- anySimReadyAndInService,
- subsIds));
+ handler.post(() -> mCarrierTextCallback.updateCarrierInfo(info));
}
}
@@ -487,7 +494,8 @@
public final boolean anySimReady;
public final int[] subscriptionIds;
- CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
+ @VisibleForTesting
+ public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
boolean anySimReady, int[] subscriptionIds) {
this.carrierText = carrierText;
this.listOfCarriers = listOfCarriers;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index c0ed4b9..b865ce8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -54,6 +54,7 @@
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.R.dimen;
import com.android.systemui.plugins.ActivityStarter;
@@ -134,6 +135,15 @@
mDeviceProvisionedController = deviceProvisionedController;
}
+ @VisibleForTesting
+ public QSFooterImpl(Context context, AttributeSet attrs) {
+ this(context, attrs,
+ Dependency.get(ActivityStarter.class),
+ Dependency.get(UserInfoController.class),
+ Dependency.get(NetworkController.class),
+ Dependency.get(DeviceProvisionedController.class));
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -476,32 +486,62 @@
mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
}
+ @VisibleForTesting
+ protected int getSlotIndex(int subscriptionId) {
+ return SubscriptionManager.getSlotIndex(subscriptionId);
+ }
+
@Override
public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
if (info.anySimReady) {
boolean[] slotSeen = new boolean[SIM_SLOTS];
- for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
- int slot = SubscriptionManager.getSlotIndex(info.subscriptionIds[i]);
- mInfos[slot].visible = true;
- slotSeen[slot] = true;
- mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
- mCarrierGroups[slot].setVisibility(View.VISIBLE);
- }
- for (int i = 0; i < SIM_SLOTS; i++) {
- if (!slotSeen[i]) {
+ if (info.listOfCarriers.length == info.subscriptionIds.length) {
+ for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
+ int slot = getSlotIndex(info.subscriptionIds[i]);
+ if (slot >= SIM_SLOTS) {
+ Log.w(TAG, "updateInfoCarrier - slot: " + slot);
+ continue;
+ }
+ if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ Log.e(TAG,
+ "Invalid SIM slot index for subscription: "
+ + info.subscriptionIds[i]);
+ continue;
+ }
+ mInfos[slot].visible = true;
+ slotSeen[slot] = true;
+ mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
+ mCarrierGroups[slot].setVisibility(View.VISIBLE);
+ }
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ if (!slotSeen[i]) {
+ mInfos[i].visible = false;
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
+ }
+ } else {
+ // If there are sims ready but there are not the same number of carrier names as
+ // subscription ids, just show the full text in the first slot
+ mInfos[0].visible = true;
+ mCarrierTexts[0].setText(info.carrierText);
+ mCarrierGroups[0].setVisibility(View.VISIBLE);
+ for (int i = 1; i < SIM_SLOTS; i++) {
mInfos[i].visible = false;
+ mCarrierTexts[i].setText("");
mCarrierGroups[i].setVisibility(View.GONE);
}
}
- handleUpdateState();
} else {
mInfos[0].visible = false;
- mInfos[1].visible = false;
mCarrierTexts[0].setText(info.carrierText);
mCarrierGroups[0].setVisibility(View.VISIBLE);
- mCarrierGroups[1].setVisibility(View.GONE);
- handleUpdateState();
+ for (int i = 1; i < SIM_SLOTS; i++) {
+ mInfos[i].visible = false;
+ mCarrierTexts[i].setText("");
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
}
+ handleUpdateState();
}
@Override
@@ -510,9 +550,14 @@
int qsType, boolean activityIn, boolean activityOut,
String typeContentDescription,
String description, boolean isWide, int subId, boolean roaming) {
- int slotIndex = SubscriptionManager.getSlotIndex(subId);
+ int slotIndex = getSlotIndex(subId);
if (slotIndex >= SIM_SLOTS) {
- Log.e(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ return;
+ }
+ if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+ return;
}
mInfos[slotIndex].visible = statusIcon.visible;
mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
@@ -539,7 +584,6 @@
boolean roaming;
}
-
/**
* TextView that changes its ellipsize value with its visibility.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
new file mode 100644
index 0000000..dae4da7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+public class NavigationBarEdgePanel extends View {
+ private static final String TAG = "NavigationBarEdgePanel";
+
+ public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height,
+ int gravity) {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = gravity;
+ lp.setTitle(TAG + context.getDisplayId());
+ lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel);
+ lp.windowAnimations = 0;
+ NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context);
+ panel.setLayoutParams(lp);
+ return panel;
+ }
+
+ private NavigationBarEdgePanel(Context context) {
+ super(context);
+ }
+
+ public void setWindowFlag(int flags, boolean enable) {
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+ if (lp == null || enable == ((lp.flags & flags) != 0)) {
+ return;
+ }
+ if (enable) {
+ lp.flags |= flags;
+ } else {
+ lp.flags &= ~flags;
+ }
+ updateLayout(lp);
+ }
+
+ public void setDimensions(int width, int height) {
+ final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+ if (lp.width != width || lp.height != height) {
+ lp.width = width;
+ lp.height = height;
+ updateLayout(lp);
+ }
+ }
+
+ private void updateLayout(WindowManager.LayoutParams lp) {
+ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ wm.updateViewLayout(this, lp);
+ }
+}
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 02683c1..651670c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,8 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
@@ -35,6 +37,8 @@
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.SuppressLint;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -51,6 +55,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
@@ -87,12 +92,21 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
final static String TAG = "StatusBar/NavBarView";
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({WINDOW_TARGET_BOTTOM, WINDOW_TARGET_LEFT, WINDOW_TARGET_RIGHT})
+ public @interface WindowTarget{}
+ public static final int WINDOW_TARGET_BOTTOM = 0;
+ public static final int WINDOW_TARGET_LEFT = 1;
+ public static final int WINDOW_TARGET_RIGHT = 2;
+
// slippery nav bar when everything is disabled, e.g. during setup
final static boolean SLIPPERY_WHEN_DISABLED = true;
@@ -109,6 +123,7 @@
int mNavigationIconHints = 0;
private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
+ private @WindowTarget int mWindowHitTarget = WINDOW_TARGET_BOTTOM;
private Rect mHomeButtonBounds = new Rect();
private Rect mBackButtonBounds = new Rect();
private Rect mRecentsButtonBounds = new Rect();
@@ -160,6 +175,9 @@
private NavigationAssistantAction mAssistantAction;
private NavigationNotificationPanelAction mNotificationPanelAction;
+ private NavigationBarEdgePanel mLeftEdgePanel;
+ private NavigationBarEdgePanel mRightEdgePanel;
+
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
* occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
@@ -222,6 +240,18 @@
}
};
+ private final OnTouchListener mEdgePanelTouchListener = new OnTouchListener() {
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getActionMasked() == ACTION_DOWN) {
+ mWindowHitTarget = v == mLeftEdgePanel ? WINDOW_TARGET_LEFT : WINDOW_TARGET_RIGHT;
+ mDownHitTarget = HIT_TARGET_NONE;
+ }
+ return mGestureHelper.onTouchEvent(event);
+ }
+ };
+
private class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -297,6 +327,16 @@
mColorAdaptionController.end();
}
}
+
+ @Override
+ public void onEdgeSensitivityChanged(int width, int height) {
+ if (mLeftEdgePanel != null) {
+ mLeftEdgePanel.setDimensions(width, height);
+ }
+ if (mRightEdgePanel != null) {
+ mRightEdgePanel.setDimensions(width, height);
+ }
+ }
};
public NavigationBarView(Context context, AttributeSet attrs) {
@@ -433,6 +473,7 @@
int x = (int) event.getX();
int y = (int) event.getY();
mDownHitTarget = HIT_TARGET_NONE;
+ mWindowHitTarget = WINDOW_TARGET_BOTTOM;
if (deadZoneConsumed) {
mDownHitTarget = HIT_TARGET_DEAD_ZONE;
} else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
@@ -483,6 +524,10 @@
return mDownHitTarget;
}
+ public @WindowTarget int getWindowTarget() {
+ return mWindowHitTarget;
+ }
+
public void abortCurrentGesture() {
getHomeButton().abortCurrentGesture();
}
@@ -837,24 +882,32 @@
}
private void setSlippery(boolean slippery) {
- boolean changed = false;
+ setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
+ }
+
+ public void setWindowTouchable(boolean flag) {
+ setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+ if (mLeftEdgePanel != null) {
+ mLeftEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+ }
+ if (mRightEdgePanel != null) {
+ mRightEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+ }
+ }
+
+ private void setWindowFlag(int flags, boolean enable) {
final ViewGroup navbarView = ((ViewGroup) getParent());
- final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
- .getLayoutParams();
- if (lp == null) {
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
+ if (lp == null || enable == ((lp.flags & flags) != 0)) {
return;
}
- if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
- lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
- changed = true;
- } else if (!slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0) {
- lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
- changed = true;
+ if (enable) {
+ lp.flags |= flags;
+ } else {
+ lp.flags &= ~flags;
}
- if (changed) {
- WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
- wm.updateViewLayout(navbarView, lp);
- }
+ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ wm.updateViewLayout(navbarView, lp);
}
public void setMenuVisibility(final boolean show) {
@@ -1016,6 +1069,17 @@
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get nav bar position.", e);
}
+
+ // For landscape, hide the panel that would interfere with navigation bar layout
+ if (mLeftEdgePanel != null && mRightEdgePanel != null) {
+ mLeftEdgePanel.setVisibility(VISIBLE);
+ mRightEdgePanel.setVisibility(VISIBLE);
+ if (navBarPos == NAV_BAR_LEFT) {
+ mLeftEdgePanel.setVisibility(GONE);
+ } else if (navBarPos == NAV_BAR_RIGHT) {
+ mRightEdgePanel.setVisibility(GONE);
+ }
+ }
mGestureHelper.setBarState(isRtl, navBarPos);
}
@@ -1142,6 +1206,21 @@
NavGesture.class, false /* Only one */);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
mColorAdaptionController.start();
+
+ if (mPrototypeController.isEnabled()) {
+ WindowManager wm = (WindowManager) getContext()
+ .getSystemService(Context.WINDOW_SERVICE);
+ int width = mPrototypeController.getEdgeSensitivityWidth();
+ int height = mPrototypeController.getEdgeSensitivityHeight();
+ mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
+ Gravity.START | Gravity.BOTTOM);
+ mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
+ Gravity.END | Gravity.BOTTOM);
+ mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
+ mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
+ wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams());
+ wm.addView(mRightEdgePanel, mRightEdgePanel.getLayoutParams());
+ }
}
@Override
@@ -1157,6 +1236,17 @@
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
}
+
+ if (mPrototypeController.isEnabled()) {
+ WindowManager wm = (WindowManager) getContext()
+ .getSystemService(Context.WINDOW_SERVICE);
+ if (mLeftEdgePanel != null) {
+ wm.removeView(mLeftEdgePanel);
+ }
+ if (mRightEdgePanel != null) {
+ wm.removeView(mRightEdgePanel);
+ }
+ }
}
private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index b4feb25..8421e23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -34,7 +35,12 @@
public class NavigationPrototypeController extends ContentObserver {
private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
+ private static final String PROTOTYPE_ENABLED = "prototype_enabled";
+ private static final String EDGE_SENSITIVITY_HEIGHT_SETTING =
+ "quickstepcontroller_edge_height_sensitivity";
+ public static final String EDGE_SENSITIVITY_WIDTH_SETTING =
+ "quickstepcontroller_edge_width_sensitivity";
private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
@@ -79,6 +85,8 @@
registerObserver(HIDE_HOME_BUTTON_SETTING);
registerObserver(GESTURE_MATCH_SETTING);
registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
+ registerObserver(EDGE_SENSITIVITY_WIDTH_SETTING);
+ registerObserver(EDGE_SENSITIVITY_HEIGHT_SETTING);
}
/**
@@ -106,10 +114,26 @@
} else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
mListener.onColorAdaptChanged(
NavBarTintController.isEnabled(mContext));
+ } else if (path.endsWith(EDGE_SENSITIVITY_WIDTH_SETTING)
+ || path.endsWith(EDGE_SENSITIVITY_HEIGHT_SETTING)) {
+ mListener.onEdgeSensitivityChanged(getEdgeSensitivityWidth(),
+ getEdgeSensitivityHeight());
}
}
}
+ public int getEdgeSensitivityWidth() {
+ return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_WIDTH_SETTING, 0));
+ }
+
+ public int getEdgeSensitivityHeight() {
+ return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_HEIGHT_SETTING, 0));
+ }
+
+ public boolean isEnabled() {
+ return getGlobalBool(PROTOTYPE_ENABLED, false);
+ }
+
/**
* Retrieve the action map to apply to the quick step controller
* @return an action map
@@ -144,15 +168,24 @@
return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
}
+ private int getGlobalInt(String name, int defaultVal) {
+ return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal);
+ }
+
private void registerObserver(String name) {
mContext.getContentResolver()
.registerContentObserver(Settings.Global.getUriFor(name), false, this);
}
+ private static int convertDpToPixel(float dp) {
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
+
public interface OnPrototypeChangedListener {
void onGestureRemap(@GestureAction int[] actions);
void onBackButtonVisibilityChanged(boolean visible);
void onHomeButtonVisibilityChanged(boolean visible);
void onColorAdaptChanged(boolean enabled);
+ void onEdgeSensitivityChanged(int width, int height);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index d5d283c..84f1cef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -28,9 +28,12 @@
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import static com.android.systemui.statusbar.phone.NavigationBarView.WINDOW_TARGET_BOTTOM;
+import static com.android.systemui.statusbar.phone.NavigationPrototypeController.EDGE_SENSITIVITY_WIDTH_SETTING;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -42,12 +45,9 @@
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -72,6 +72,7 @@
/** Experiment to swipe home button left to execute a back key press */
private static final String HIDE_BACK_BUTTON_PROP = "quickstepcontroller_hideback";
private static final String ENABLE_CLICK_THROUGH_NAV_PROP = "quickstepcontroller_clickthrough";
+ private static final String GESTURE_REGION_THRESHOLD_SETTING = "gesture_region_threshold";
private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
private static final long CLICK_THROUGH_TAP_DELAY = 70;
private static final long CLICK_THROUGH_TAP_RESET_DELAY = 100;
@@ -109,10 +110,10 @@
private float mMaxDragLimit;
private float mMinDragLimit;
private float mDragDampeningFactor;
- private float mEdgeSwipeThreshold;
private boolean mClickThroughPressed;
private float mClickThroughPressX;
private float mClickThroughPressY;
+ private int mGestureRegionThreshold;
private NavigationGestureAction mCurrentAction;
private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -139,7 +140,7 @@
};
private final Runnable mClickThroughResetTap = () -> {
- setWindowTouchable(true);
+ mNavigationBarView.setWindowTouchable(true);
mClickThroughPressed = false;
};
@@ -210,7 +211,8 @@
// The same down event was just sent on intercept and therefore can be ignored here
final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
- && mOverviewEventSender.getProxy() != null;
+ && mOverviewEventSender.getProxy() != null
+ && mNavigationBarView.getWindowTarget() == WINDOW_TARGET_BOTTOM;
return ignoreProxyDownEvent || handleTouchEvent(event);
}
@@ -268,12 +270,15 @@
mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
mAllowGestureDetection = true;
mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
- mEdgeSwipeThreshold = mContext.getResources()
- .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
+ final int defaultRegionThreshold = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.navigation_bar_default_edge_width);
+ mGestureRegionThreshold = convertDpToPixel(getIntGlobalSetting(mContext,
+ EDGE_SENSITIVITY_WIDTH_SETTING, defaultRegionThreshold));
break;
}
case MotionEvent.ACTION_MOVE: {
- if (!mAllowGestureDetection) {
+ if (!mAllowGestureDetection
+ || mNavigationBarView.getWindowTarget() != WINDOW_TARGET_BOTTOM) {
break;
}
int x = (int) event.getX();
@@ -330,18 +335,12 @@
} else if (exceededSwipeHorizontalTouchSlop) {
if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
// Swiping left (rtl) gesture
- int index = mGestureActions[ACTION_SWIPE_LEFT_FROM_EDGE_INDEX] != null
- && isEdgeSwipeAlongNavBar(touchDownH, !mDragHPositive)
- ? ACTION_SWIPE_LEFT_FROM_EDGE_INDEX : ACTION_SWIPE_LEFT_INDEX;
- tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
- event);
+ tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
+ true /* alignedWithNavBar */, event);
} else {
// Swiping right (ltr) gesture
- int index = mGestureActions[ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX] != null
- && isEdgeSwipeAlongNavBar(touchDownH, mDragHPositive)
- ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX : ACTION_SWIPE_RIGHT_INDEX;
- tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
- event);
+ tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
+ true /* alignedWithNavBar */, event);
}
}
}
@@ -354,24 +353,34 @@
case MotionEvent.ACTION_UP:
if (mCurrentAction != null) {
mCurrentAction.endGesture();
- } else if (action == MotionEvent.ACTION_UP
- && getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
- && !mClickThroughPressed) {
- // Enable click through functionality where no gesture has been detected and not
- // passed the drag slop so inject a touch event at the same location
- // after making the navigation bar window untouchable. After a some time, the
- // navigation bar will be able to take input events again
- float diffX = Math.abs(event.getX() - mTouchDownX);
- float diffY = Math.abs(event.getY() - mTouchDownY);
+ } else if (action == MotionEvent.ACTION_UP) {
+ if (canTriggerEdgeSwipe(event)) {
+ int index = mNavigationBarView.getWindowTarget() == NAV_BAR_LEFT
+ ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX
+ : ACTION_SWIPE_LEFT_FROM_EDGE_INDEX;
+ tryToStartGesture(mGestureActions[index], false /* alignedWithNavBar */,
+ event);
+ if (mCurrentAction != null) {
+ mCurrentAction.endGesture();
+ }
+ } else if (getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
+ && !mClickThroughPressed) {
+ // Enable click through functionality where no gesture has been detected and
+ // not passed the drag slop so inject a touch event at the same location
+ // after making the navigation bar window untouchable. After a some time,
+ // the navigation bar will be able to take input events again
+ float diffX = Math.abs(event.getX() - mTouchDownX);
+ float diffY = Math.abs(event.getY() - mTouchDownY);
- if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
- && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
- setWindowTouchable(false);
- mClickThroughPressX = event.getRawX();
- mClickThroughPressY = event.getRawY();
- mClickThroughPressed = true;
- mNavigationBarView.postDelayed(mClickThroughSendTap,
- CLICK_THROUGH_TAP_DELAY);
+ if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
+ && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
+ mNavigationBarView.setWindowTouchable(false);
+ mClickThroughPressX = event.getRawX();
+ mClickThroughPressY = event.getRawY();
+ mClickThroughPressed = true;
+ mNavigationBarView.postDelayed(mClickThroughSendTap,
+ CLICK_THROUGH_TAP_DELAY);
+ }
}
}
@@ -403,30 +412,6 @@
return mCurrentAction != null || deadZoneConsumed;
}
- private void setWindowTouchable(boolean flag) {
- final WindowManager.LayoutParams lp = (WindowManager.LayoutParams)
- ((ViewGroup) mNavigationBarView.getParent()).getLayoutParams();
- if (flag) {
- lp.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
- } else {
- lp.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
- }
- final WindowManager wm = (WindowManager) mNavigationBarView.getContext()
- .getSystemService(Context.WINDOW_SERVICE);
- wm.updateViewLayout((View) mNavigationBarView.getParent(), lp);
- }
-
- private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
- // Detect edge swipe from side of 0 -> threshold
- if (dragPositiveDirection) {
- return touchDown < mEdgeSwipeThreshold;
- }
- // Detect edge swipe from side of size -> (size - threshold)
- final int largeSide = isNavBarVertical()
- ? mNavigationBarView.getHeight() : mNavigationBarView.getWidth();
- return touchDown > largeSide - mEdgeSwipeThreshold;
- }
-
private void handleDragHitTarget(int position, int touchDown) {
// Drag the hit target if gesture action requires it
if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
@@ -448,6 +433,10 @@
}
private boolean shouldProxyEvents(int action) {
+ // Do not send events for side navigation bar panels
+ if (mNavigationBarView.getWindowTarget() != WINDOW_TARGET_BOTTOM) {
+ return false;
+ }
final boolean actionValid = (mCurrentAction == null
|| !mCurrentAction.disableProxyEvents());
if (actionValid && !mIsInScreenPinning) {
@@ -619,6 +608,32 @@
}
}
+ /**
+ * To trigger an edge swipe, the user must start from the left or right edges of certain height
+ * from the bottom then past the drag slope towards the center of the screen, followed by either
+ * a timed trigger for fast swipes or distance if held on the screen longer.
+ * For time, user must swipe up quickly before the Tap Timeout (typically 100ms) and for
+ * distance, the user can drag back to cancel if the touch up has not past the threshold.
+ * @param event Touch up event
+ * @return whether or not edge swipe gesture occurs
+ */
+ private boolean canTriggerEdgeSwipe(MotionEvent event) {
+ if (mNavigationBarView.getWindowTarget() == WINDOW_TARGET_BOTTOM) {
+ return false;
+ }
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ int xDiff = Math.abs(x - mTouchDownX);
+ int yDiff = Math.abs(y - mTouchDownY);
+ final boolean exceededSwipeTouchSlop = xDiff > NavigationBarCompat.getQuickStepDragSlopPx()
+ && xDiff > yDiff;
+ if (exceededSwipeTouchSlop) {
+ long timeDiff = event.getEventTime() - event.getDownTime();
+ return xDiff > mGestureRegionThreshold || timeDiff < ViewConfiguration.getTapTimeout();
+ }
+ return false;
+ }
+
private boolean canPerformAnyAction() {
for (NavigationGestureAction action: mGestureActions) {
if (action != null && action.isEnabled()) {
@@ -684,10 +699,18 @@
return mNavBarPosition == NAV_BAR_LEFT || mNavBarPosition == NAV_BAR_RIGHT;
}
+ private static int convertDpToPixel(float dp) {
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
+
static boolean getBoolGlobalSetting(Context context, String key) {
return Settings.Global.getInt(context.getContentResolver(), key, 0) != 0;
}
+ static int getIntGlobalSetting(Context context, String key, int defaultValue) {
+ return Settings.Global.getInt(context.getContentResolver(), key, defaultValue);
+ }
+
public static boolean shouldhideBackButton(Context context) {
return getBoolGlobalSetting(context, HIDE_BACK_BUTTON_PROP);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
index 8503962..374a73c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
@@ -16,27 +16,35 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
+import android.telephony.SubscriptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;
+import com.android.keyguard.CarrierTextController.CarrierTextCallbackInfo;
import com.android.systemui.R;
import com.android.systemui.R.id;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -68,4 +76,117 @@
// Verify Settings wasn't launched.
verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
}
+
+ @Test // throws no Exception
+ public void testUpdateCarrierText_sameLengts() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
+ new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
+ return invocationOnMock.getArgument(0);
+ }
+ });
+
+ // listOfCarriers length 1, subscriptionIds length 1, anySims false
+ CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ false,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c1);
+
+ // listOfCarriers length 1, subscriptionIds length 1, anySims true
+ CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c2);
+
+ // listOfCarriers length 2, subscriptionIds length 2, anySims false
+ CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ false,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c3);
+
+ // listOfCarriers length 2, subscriptionIds length 2, anySims true
+ CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c4);
+ }
+
+ @Test // throws no Exception
+ public void testUpdateCarrierText_differentLength() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
+ new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
+ return invocationOnMock.getArgument(0);
+ }
+ });
+
+ // listOfCarriers length 2, subscriptionIds length 1, anySims false
+ CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ false,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c1);
+
+ // listOfCarriers length 2, subscriptionIds length 1, anySims true
+ CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c2);
+
+ // listOfCarriers length 1, subscriptionIds length 2, anySims false
+ CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ false,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c3);
+
+ // listOfCarriers length 1, subscriptionIds length 2, anySims true
+ CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c4);
+ }
+
+ @Test // throws no Exception
+ public void testUpdateCarrierText_invalidSim() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c4);
+ }
+
+ @Test // throws no Exception
+ public void testSetMobileDataIndicators_invalidSim() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ spiedFooter.setMobileDataIndicators(
+ mock(NetworkController.IconState.class),
+ mock(NetworkController.IconState.class),
+ 0, 0, true, true, "", "", true, 0, true);
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 382dde9..dbf00a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -23,6 +23,7 @@
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.statusbar.phone.NavigationBarView.WINDOW_TARGET_BOTTOM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -63,7 +64,6 @@
public class QuickStepControllerTest extends SysuiTestCase {
private static final int NAVBAR_WIDTH = 1000;
private static final int NAVBAR_HEIGHT = 300;
- private static final int EDGE_THRESHOLD = 100;
private QuickStepController mController;
private NavigationBarView mNavigationBarView;
@@ -77,8 +77,6 @@
MockitoAnnotations.initMocks(this);
final ButtonDispatcher backButton = mock(ButtonDispatcher.class);
mResources = mock(Resources.class);
- doReturn(EDGE_THRESHOLD).when(mResources)
- .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
mProxyService = mock(OverviewProxyService.class);
mProxy = mock(IOverviewProxy.Stub.class);
@@ -95,6 +93,7 @@
doReturn(true).when(mNavigationBarView).isNotificationsFullyCollapsed();
doReturn(true).when(mNavigationBarView).isQuickScrubEnabled();
doReturn(HIT_TARGET_NONE).when(mNavigationBarView).getDownHitTarget();
+ doReturn(WINDOW_TARGET_BOTTOM).when(mNavigationBarView).getWindowTarget();
doReturn(backButton).when(mNavigationBarView).getBackButton();
doReturn(mResources).when(mNavigationBarView).getResources();
doReturn(mContext).when(mNavigationBarView).getContext();
@@ -196,10 +195,8 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
@@ -209,10 +206,6 @@
assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 5);
- // Swipe Left from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, NAVBAR_WIDTH, 1, 5, 1);
- // Swipe Right from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
@@ -224,10 +217,8 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// In landscape
mController.setBarState(false /* isRTL */, NAV_BAR_RIGHT);
@@ -240,10 +231,6 @@
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -256,10 +243,8 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -269,10 +254,6 @@
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -286,10 +267,8 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up in RTL
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
@@ -299,10 +278,6 @@
assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right in RTL
assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 0);
- // Swipe Left from Edge
- assertGestureTriggersAction(swipeRightFromEdge, NAVBAR_WIDTH, 1, 5, 1);
- // Swipe Right from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
@@ -316,10 +291,8 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -329,10 +302,6 @@
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -346,10 +315,8 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -359,10 +326,6 @@
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -602,25 +565,6 @@
assertGestureDragsHitTargetAllDirections(buttonView, true /* isRTL */, NAV_BAR_LEFT);
}
- @Test
- public void testNoEdgeActionsTriggerNormalActions() {
- doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
- doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
-
- NavigationGestureAction swipeUp = mockAction(true);
- NavigationGestureAction swipeDown = mockAction(true);
- NavigationGestureAction swipeLeft = mockAction(true);
- NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
- null /* swipeLeftFromEdgeAction */,
- null /* swipeLeftFromEdgeAction */);
-
- // Swipe Left from Edge
- assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH, 1, 5, 1);
- // Swipe Right from Edge
- assertGestureTriggersAction(swipeRight, 0, 1, NAVBAR_WIDTH, 5);
- }
-
private void assertGestureDragsHitTargetAllDirections(View buttonView, boolean isRTL,
int navPos) {
mController.setBarState(isRTL, navPos);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index c8a27f1..7102b82 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -416,36 +416,5 @@
// TODO(b/122595322): implement
// TODO(b/119613670): log metrics
}
-
- @Override
- public void setActivityContentCaptureEnabled(ComponentName activity, boolean enabled) {
- if (mMaster.verbose) {
- Log.v(TAG, "setActivityContentCaptureEnabled(activity=" + activity + ", enabled="
- + enabled + ")");
- }
- // TODO(b/122595322): implement
- // TODO(b/119613670): log metrics
- }
-
- @Override
- public void setPackageContentCaptureEnabled(String packageName, boolean enabled) {
- if (mMaster.verbose) {
- Log.v(TAG,
- "setPackageContentCaptureEnabled(packageName=" + packageName + ", enabled="
- + enabled + ")");
- }
- // TODO(b/122595322): implement
- // TODO(b/119613670): log metrics
- }
-
- @Override
- public void getContentCaptureDisabledActivities(IResultReceiver receiver) {
- // TODO(b/122595322): implement
- }
-
- @Override
- public void getContentCaptureDisabledPackages(IResultReceiver receiver) {
- // TODO(b/122595322): implement
- }
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index deaa931..a3bae52 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -15,6 +15,9 @@
*/
package com.android.server.audio;
+import static com.android.server.audio.AudioService.CONNECTION_STATE_CONNECTED;
+import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTED;
+
import android.annotation.NonNull;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
@@ -43,7 +46,7 @@
/** @hide */
/*package*/ final class AudioDeviceBroker {
- private static final String TAG = "AudioDeviceBroker";
+ private static final String TAG = "AS.AudioDeviceBroker";
private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s
@@ -62,27 +65,27 @@
private int mForcedUseForCommExt;
// Manages all connected devices, only ever accessed on the message loop
- //### or make it synchronized
private final AudioDeviceInventory mDeviceInventory;
// Manages notifications to BT service
private final BtHelper mBtHelper;
//-------------------------------------------------------------------
+ // we use a different lock than mDeviceStateLock so as not to create
+ // lock contention between enqueueing a message and handling them
private static final Object sLastDeviceConnectionMsgTimeLock = new Object();
+ @GuardedBy("sLastDeviceConnectionMsgTimeLock")
private static long sLastDeviceConnectMsgTime = 0;
- private final Object mBluetoothA2dpEnabledLock = new Object();
+ // General lock to be taken whenever the state of the audio devices is to be checked or changed
+ private final Object mDeviceStateLock = new Object();
+
// Request to override default use of A2DP for media.
- @GuardedBy("mBluetoothA2dpEnabledLock")
+ @GuardedBy("mDeviceStateLock")
private boolean mBluetoothA2dpEnabled;
- // lock always taken synchronized on mConnectedDevices
- /*package*/ final Object mA2dpAvrcpLock = new Object();
- // lock always taken synchronized on mConnectedDevices
- /*package*/ final Object mHearingAidLock = new Object();
-
// lock always taken when accessing AudioService.mSetModeDeathHandlers
+ // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
/*package*/ final Object mSetModeLock = new Object();
//-------------------------------------------------------------------
@@ -109,13 +112,17 @@
// All post* methods are asynchronous
/*package*/ void onSystemReady() {
- mBtHelper.onSystemReady();
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onSystemReady();
+ }
}
/*package*/ void onAudioServerDied() {
// Restore forced usage for communications and record
- onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
- onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
+ synchronized (mDeviceStateLock) {
+ onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
+ onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
+ }
// restore devices
sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE);
}
@@ -130,7 +137,9 @@
}
/*package*/ void disconnectAllBluetoothProfiles() {
- mBtHelper.disconnectAllBluetoothProfiles();
+ synchronized (mDeviceStateLock) {
+ mBtHelper.disconnectAllBluetoothProfiles();
+ }
}
/**
@@ -140,11 +149,13 @@
* @param intent
*/
/*package*/ void receiveBtEvent(@NonNull Intent intent) {
- mBtHelper.receiveBtEvent(intent);
+ synchronized (mDeviceStateLock) {
+ mBtHelper.receiveBtEvent(intent);
+ }
}
/*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
- synchronized (mBluetoothA2dpEnabledLock) {
+ synchronized (mDeviceStateLock) {
if (mBluetoothA2dpEnabled == on) {
return;
}
@@ -158,28 +169,34 @@
}
/*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
- if (on) {
- if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
- setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
+ synchronized (mDeviceStateLock) {
+ if (on) {
+ if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+ setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
+ }
+ mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+ } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
}
- mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
- } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
- mForcedUseForComm = AudioSystem.FORCE_NONE;
- }
- mForcedUseForCommExt = mForcedUseForComm;
- setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ mForcedUseForCommExt = mForcedUseForComm;
+ setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ }
}
/*package*/ boolean isSpeakerphoneOn() {
- return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
+ synchronized (mDeviceStateLock) {
+ return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
+ }
}
/*package*/ void setWiredDeviceConnectionState(int type,
@AudioService.ConnectionState int state, String address, String name,
String caller) {
//TODO move logging here just like in setBluetooth* methods
- mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+ }
}
/*package*/ int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
@@ -192,22 +209,27 @@
+ " addr=" + device.getAddress()
+ " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
+ " vol=" + a2dpVolume)).printLog(TAG));
- if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
- new BtHelper.BluetoothA2dpDeviceInfo(device))) {
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "A2DP connection state ignored"));
- return 0;
+ synchronized (mDeviceStateLock) {
+ if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
+ new BtHelper.BluetoothA2dpDeviceInfo(device))) {
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "A2DP connection state ignored"));
+ return 0;
+ }
+ return mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
+ device, state, profile, suppressNoisyIntent,
+ AudioSystem.DEVICE_NONE, a2dpVolume);
}
- return mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
- device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
}
/*package*/ int handleBluetoothA2dpActiveDeviceChange(
@NonNull BluetoothDevice device,
@AudioService.BtProfileConnectionState int state, int profile,
boolean suppressNoisyIntent, int a2dpVolume) {
- return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
- suppressNoisyIntent, a2dpVolume);
+ synchronized (mDeviceStateLock) {
+ return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
+ suppressNoisyIntent, a2dpVolume);
+ }
}
/*package*/ int setBluetoothHearingAidDeviceConnectionState(
@@ -218,57 +240,69 @@
+ " addr=" + device.getAddress()
+ " supprNoisy=" + suppressNoisyIntent
+ " src=" + eventSource)).printLog(TAG));
- return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
- device, state, suppressNoisyIntent, musicDevice);
+ synchronized (mDeviceStateLock) {
+ return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
+ device, state, suppressNoisyIntent, musicDevice);
+ }
}
// never called by system components
/*package*/ void setBluetoothScoOnByApp(boolean on) {
- mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+ synchronized (mDeviceStateLock) {
+ mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+ }
}
/*package*/ boolean isBluetoothScoOnForApp() {
- return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
+ synchronized (mDeviceStateLock) {
+ return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
+ }
}
/*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
//Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
- if (on) {
- // do not accept SCO ON if SCO audio is not connected
- if (!mBtHelper.isBluetoothScoOn()) {
- mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
- return;
+ synchronized (mDeviceStateLock) {
+ if (on) {
+ // do not accept SCO ON if SCO audio is not connected
+ if (!mBtHelper.isBluetoothScoOn()) {
+ mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
+ return;
+ }
+ mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+ } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
}
- mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
- } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
- mForcedUseForComm = AudioSystem.FORCE_NONE;
+ mForcedUseForCommExt = mForcedUseForComm;
+ AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
+ sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
+ AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
+ AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
+ // Un-mute ringtone stream volume
+ mAudioService.setUpdateRingerModeServiceInt();
}
- mForcedUseForCommExt = mForcedUseForComm;
- AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
- sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
- AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
- sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
- AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
- // Un-mute ringtone stream volume
- mAudioService.setUpdateRingerModeServiceInt();
}
/*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
- return mDeviceInventory.startWatchingRoutes(observer);
+ synchronized (mDeviceStateLock) {
+ return mDeviceInventory.startWatchingRoutes(observer);
+ }
}
/*package*/ AudioRoutesInfo getCurAudioRoutes() {
- return mDeviceInventory.getCurAudioRoutes();
+ synchronized (mDeviceStateLock) {
+ return mDeviceInventory.getCurAudioRoutes();
+ }
}
/*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
- synchronized (mA2dpAvrcpLock) {
+ synchronized (mDeviceStateLock) {
return mBtHelper.isAvrcpAbsoluteVolumeSupported();
}
}
/*package*/ boolean isBluetoothA2dpOn() {
- synchronized (mBluetoothA2dpEnabledLock) {
+ synchronized (mDeviceStateLock) {
return mBluetoothA2dpEnabled;
}
}
@@ -355,14 +389,12 @@
sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
}
- //###TODO unify with handleSetA2dpSinkConnectionState
/*package*/ void postA2dpSinkConnection(int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
state, btDeviceInfo, delay);
}
- //###TODO unify with handleSetA2dpSourceConnectionState
/*package*/ void postA2dpSourceConnection(int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
@@ -395,7 +427,7 @@
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
.append(Binder.getCallingPid()).append(" src:").append(source).toString();
- synchronized (mBluetoothA2dpEnabledLock) {
+ synchronized (mDeviceStateLock) {
mBluetoothA2dpEnabled = on;
mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
onSetForceUse(
@@ -407,25 +439,38 @@
/*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName) {
- return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
+ synchronized (mDeviceStateLock) {
+ return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
+ }
}
/*package*/ void handleDisconnectA2dp() {
- mDeviceInventory.disconnectA2dp();
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.disconnectA2dp();
+ }
}
/*package*/ void handleDisconnectA2dpSink() {
- mDeviceInventory.disconnectA2dpSink();
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.disconnectA2dpSink();
+ }
+ }
+
+ /*package*/ void handleDisconnectHearingAid() {
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.disconnectHearingAid();
+ }
}
/*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
- final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
- //### DOESN'T HONOR SYNC ON DEVICES -> make a synchronized version?
- // might be ok here because called on BT thread? + sync happening in
- // checkSendBecomingNoisyIntent
- final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
- AudioSystem.DEVICE_NONE);
+ final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
+ ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
+ final int delay;
+ synchronized (mDeviceStateLock) {
+ delay = mDeviceInventory.checkSendBecomingNoisyIntent(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
+ AudioSystem.DEVICE_NONE);
+ }
final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();
if (AudioService.DEBUG_DEVICES) {
@@ -437,10 +482,6 @@
state, btDeviceInfo, delay);
}
- /*package*/ void handleDisconnectHearingAid() {
- mDeviceInventory.disconnectHearingAid();
- }
-
/*package*/ void handleSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
@@ -468,8 +509,6 @@
sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
}
- //###
- // must be called synchronized on mConnectedDevices
/*package*/ boolean hasScheduledA2dpDockTimeout() {
return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT);
}
@@ -486,19 +525,19 @@
}
/*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
- synchronized (mA2dpAvrcpLock) {
+ synchronized (mDeviceStateLock) {
mBtHelper.setAvrcpAbsoluteVolumeSupported(supported);
}
}
/*package*/ boolean getBluetoothA2dpEnabled() {
- synchronized (mBluetoothA2dpEnabledLock) {
+ synchronized (mDeviceStateLock) {
return mBluetoothA2dpEnabled;
}
}
/*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
- synchronized (mA2dpAvrcpLock) {
+ synchronized (mDeviceStateLock) {
return mBtHelper.getA2dpCodec(device);
}
}
@@ -579,71 +618,97 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RESTORE_DEVICES:
- mDeviceInventory.onRestoreDevices();
- synchronized (mBluetoothA2dpEnabledLock) {
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onRestoreDevices();
mBtHelper.onAudioServerDiedRestoreA2dp();
}
break;
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
- mDeviceInventory.onSetWiredDeviceConnectionState(
- (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSetWiredDeviceConnectionState(
+ (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
+ }
break;
case MSG_I_BROADCAST_BT_CONNECTION_STATE:
- mBtHelper.onBroadcastScoConnectionState(msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onBroadcastScoConnectionState(msg.arg1);
+ }
break;
- case MSG_IIL_SET_FORCE_USE: // intented fall-through
+ case MSG_IIL_SET_FORCE_USE: // intended fall-through
case MSG_IIL_SET_FORCE_BT_A2DP_USE:
onSetForceUse(msg.arg1, msg.arg2, (String) msg.obj);
break;
case MSG_REPORT_NEW_ROUTES:
- mDeviceInventory.onReportNewRoutes();
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onReportNewRoutes();
+ }
break;
case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
- mDeviceInventory.onSetA2dpSinkConnectionState(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSetA2dpSinkConnectionState(
+ (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+ }
break;
case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- mDeviceInventory.onSetA2dpSourceConnectionState(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSetA2dpSourceConnectionState(
+ (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+ }
break;
case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
- mDeviceInventory.onSetHearingAidConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSetHearingAidConnectionState(
+ (BluetoothDevice) msg.obj, msg.arg1);
+ }
break;
case MSG_BT_HEADSET_CNCT_FAILED:
- mBtHelper.resetBluetoothSco();
+ synchronized (mDeviceStateLock) {
+ mBtHelper.resetBluetoothSco();
+ }
break;
case MSG_IL_BTA2DP_DOCK_TIMEOUT:
// msg.obj == address of BTA2DP device
- mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
+ }
break;
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
final int a2dpCodec;
final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
- synchronized (mA2dpAvrcpLock) {
+ synchronized (mDeviceStateLock) {
a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
+ mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
+ new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec));
}
- mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
- new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec));
break;
case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
onSendBecomingNoisyIntent();
break;
case MSG_II_SET_HEARING_AID_VOLUME:
- mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
+ synchronized (mDeviceStateLock) {
+ mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
+ }
break;
case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
- mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
+ }
break;
case MSG_I_DISCONNECT_BT_SCO:
- mBtHelper.disconnectBluetoothSco(msg.arg1);
+ synchronized (mDeviceStateLock) {
+ mBtHelper.disconnectBluetoothSco(msg.arg1);
+ }
break;
case MSG_TOGGLE_HDMI:
- mDeviceInventory.onToggleHdmi();
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onToggleHdmi();
+ }
break;
case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
- mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
+ (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
+ }
break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 97649a7..11fdc8f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -162,10 +162,7 @@
"A2DP sink connected: device addr=" + address + " state=" + state
+ " vol=" + a2dpVolume));
- final int a2dpCodec;
- synchronized (mDeviceBroker.mA2dpAvrcpLock) {
- a2dpCodec = btInfo.getCodec();
- }
+ final int a2dpCodec = btInfo.getCodec();
synchronized (mConnectedDevices) {
final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
@@ -508,22 +505,20 @@
/*package*/ void disconnectA2dp() {
synchronized (mConnectedDevices) {
- synchronized (mDeviceBroker.mA2dpAvrcpLock) {
- final ArraySet<String> toRemove = new ArraySet<>();
- // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
- mConnectedDevices.values().forEach(deviceInfo -> {
- if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
- toRemove.add(deviceInfo.mDeviceAddress);
- }
- });
- if (toRemove.size() > 0) {
- final int delay = checkSendBecomingNoisyIntentInt(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- 0, AudioSystem.DEVICE_NONE);
- toRemove.stream().forEach(deviceAddress ->
- makeA2dpDeviceUnavailableLater(deviceAddress, delay)
- );
+ final ArraySet<String> toRemove = new ArraySet<>();
+ // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+ mConnectedDevices.values().forEach(deviceInfo -> {
+ if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+ toRemove.add(deviceInfo.mDeviceAddress);
}
+ });
+ if (toRemove.size() > 0) {
+ final int delay = checkSendBecomingNoisyIntentInt(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE);
+ toRemove.stream().forEach(deviceAddress ->
+ makeA2dpDeviceUnavailableLater(deviceAddress, delay)
+ );
}
}
}
@@ -543,22 +538,20 @@
/*package*/ void disconnectHearingAid() {
synchronized (mConnectedDevices) {
- synchronized (mDeviceBroker.mHearingAidLock) {
- final ArraySet<String> toRemove = new ArraySet<>();
- // Disconnect ALL DEVICE_OUT_HEARING_AID devices
- mConnectedDevices.values().forEach(deviceInfo -> {
- if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
- toRemove.add(deviceInfo.mDeviceAddress);
- }
- });
- if (toRemove.size() > 0) {
- final int delay = checkSendBecomingNoisyIntentInt(
- AudioSystem.DEVICE_OUT_HEARING_AID, 0, AudioSystem.DEVICE_NONE);
- toRemove.stream().forEach(deviceAddress ->
- // TODO delay not used?
- makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/)
- );
+ final ArraySet<String> toRemove = new ArraySet<>();
+ // Disconnect ALL DEVICE_OUT_HEARING_AID devices
+ mConnectedDevices.values().forEach(deviceInfo -> {
+ if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ toRemove.add(deviceInfo.mDeviceAddress);
}
+ });
+ if (toRemove.size() > 0) {
+ final int delay = checkSendBecomingNoisyIntentInt(
+ AudioSystem.DEVICE_OUT_HEARING_AID, 0, AudioSystem.DEVICE_NONE);
+ toRemove.stream().forEach(deviceAddress ->
+ // TODO delay not used?
+ makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/)
+ );
}
}
}
@@ -566,7 +559,8 @@
// must be called before removing the device from mConnectedDevices
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
// from AudioSystem
- /*package*/ int checkSendBecomingNoisyIntent(int device, int state, int musicDevice) {
+ /*package*/ int checkSendBecomingNoisyIntent(int device,
+ @AudioService.ConnectionState int state, int musicDevice) {
synchronized (mConnectedDevices) {
return checkSendBecomingNoisyIntentInt(device, state, musicDevice);
}
@@ -840,8 +834,9 @@
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
// from AudioSystem
@GuardedBy("mConnectedDevices")
- private int checkSendBecomingNoisyIntentInt(int device, int state, int musicDevice) {
- if (state != 0) {
+ private int checkSendBecomingNoisyIntentInt(int device,
+ @AudioService.ConnectionState int state, int musicDevice) {
+ if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
return 0;
}
if ((device & mBecomingNoisyIntentDevices) == 0) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9457fe3..251cb61 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -786,7 +786,6 @@
mPrescaleAbsoluteVolume[i] = preScale[i];
}
}
-
}
public void systemReady() {
@@ -3821,7 +3820,6 @@
private static void sendMsg(Handler handler, int msg,
int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
-
if (existingMsgPolicy == SENDMSG_REPLACE) {
handler.removeMessages(msg);
} else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index bf325013..95df21e 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -16,6 +16,7 @@
package com.android.server.audio;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -35,8 +36,6 @@
import android.provider.Settings;
import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
-
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
@@ -57,21 +56,40 @@
}
// List of clients having issued a SCO start request
- private final ArrayList<ScoClient> mScoClients = new ArrayList<ScoClient>();
+ private final @NonNull ArrayList<ScoClient> mScoClients = new ArrayList<ScoClient>();
// BluetoothHeadset API to control SCO connection
- private BluetoothHeadset mBluetoothHeadset;
+ private @Nullable BluetoothHeadset mBluetoothHeadset;
// Bluetooth headset device
- private BluetoothDevice mBluetoothHeadsetDevice;
+ private @Nullable BluetoothDevice mBluetoothHeadsetDevice;
+
+ private @Nullable BluetoothHearingAid mHearingAid;
+
+ // Reference to BluetoothA2dp to query for AbsoluteVolume.
+ private @Nullable BluetoothA2dp mA2dp;
+
+ // If absolute volume is supported in AVRCP device
+ private boolean mAvrcpAbsVolSupported = false;
+
+ // Current connection state indicated by bluetooth headset
+ private int mScoConnectionState;
// Indicate if SCO audio connection is currently active and if the initiator is
// audio service (internal) or bluetooth headset (external)
private int mScoAudioState;
+
+ // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
+ // originated from an app targeting an API version before JB MR2 and raw audio after that.
+ private int mScoAudioMode;
+
// SCO audio state is not active
private static final int SCO_STATE_INACTIVE = 0;
// SCO audio activation request waiting for headset service to connect
private static final int SCO_STATE_ACTIVATE_REQ = 1;
+ // SCO audio state is active due to an action in BT handsfree (either voice recognition or
+ // in call audio)
+ private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
// SCO audio state is active or starting due to a request from AudioManager API
private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
// SCO audio deactivation request waiting for headset service to connect
@@ -79,39 +97,19 @@
// SCO audio deactivation in progress, waiting for Bluetooth audio intent
private static final int SCO_STATE_DEACTIVATING = 5;
- // SCO audio state is active due to an action in BT handsfree (either voice recognition or
- // in call audio)
- private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
-
- // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
- // originated from an app targeting an API version before JB MR2 and raw audio after that.
- private int mScoAudioMode;
// SCO audio mode is undefined
- /*package*/ static final int SCO_MODE_UNDEFINED = -1;
+ /*package*/ static final int SCO_MODE_UNDEFINED = -1;
// SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
/*package*/ static final int SCO_MODE_VIRTUAL_CALL = 0;
// SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
private static final int SCO_MODE_RAW = 1;
// SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
private static final int SCO_MODE_VR = 2;
-
+ // max valid SCO audio mode values
private static final int SCO_MODE_MAX = 2;
- // Current connection state indicated by bluetooth headset
- private int mScoConnectionState;
-
private static final int BT_HEARING_AID_GAIN_MIN = -128;
- @GuardedBy("mDeviceBroker.mHearingAidLock")
- private BluetoothHearingAid mHearingAid;
-
- // Reference to BluetoothA2dp to query for AbsoluteVolume.
- @GuardedBy("mDeviceBroker.mA2dpAvrcpLock")
- private BluetoothA2dp mA2dp;
- // If absolute volume is supported in AVRCP device
- @GuardedBy("mDeviceBroker.mA2dpAvrcpLock")
- private boolean mAvrcpAbsVolSupported = false;
-
//----------------------------------------------------------------------
/*package*/ static class BluetoothA2dpDeviceInfo {
private final @NonNull BluetoothDevice mBtDevice;
@@ -144,7 +142,7 @@
//----------------------------------------------------------------------
// Interface for AudioDeviceBroker
- /*package*/ void onSystemReady() {
+ /*package*/ synchronized void onSystemReady() {
mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR;
resetBluetoothSco();
getBluetoothHeadset();
@@ -165,45 +163,39 @@
}
}
- @GuardedBy("mBluetoothA2dpEnabledLock")
- /*package*/ void onAudioServerDiedRestoreA2dp() {
+ /*package*/ synchronized void onAudioServerDiedRestoreA2dp() {
final int forMed = mDeviceBroker.getBluetoothA2dpEnabled()
? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, forMed, "onAudioServerDied()");
}
- @GuardedBy("mA2dpAvrcpLock")
- /*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
+ /*package*/ synchronized boolean isAvrcpAbsoluteVolumeSupported() {
return (mA2dp != null && mAvrcpAbsVolSupported);
}
- @GuardedBy("mA2dpAvrcpLock")
- /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
+ /*package*/ synchronized void setAvrcpAbsoluteVolumeSupported(boolean supported) {
mAvrcpAbsVolSupported = supported;
}
- /*package*/ void setAvrcpAbsoluteVolumeIndex(int index) {
- synchronized (mDeviceBroker.mA2dpAvrcpLock) {
- if (mA2dp == null) {
- if (AudioService.DEBUG_VOL) {
- Log.d(TAG, "setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp");
- return;
- }
- }
- if (!mAvrcpAbsVolSupported) {
+ /*package*/ synchronized void setAvrcpAbsoluteVolumeIndex(int index) {
+ if (mA2dp == null) {
+ if (AudioService.DEBUG_VOL) {
+ Log.d(TAG, "setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp");
return;
}
- if (AudioService.DEBUG_VOL) {
- Log.i(TAG, "setAvrcpAbsoluteVolumeIndex index=" + index);
- }
- AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
- AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index / 10));
- mA2dp.setAvrcpAbsoluteVolume(index / 10);
}
+ if (!mAvrcpAbsVolSupported) {
+ return;
+ }
+ if (AudioService.DEBUG_VOL) {
+ Log.i(TAG, "setAvrcpAbsoluteVolumeIndex index=" + index);
+ }
+ AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
+ AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index / 10));
+ mA2dp.setAvrcpAbsoluteVolume(index / 10);
}
- @GuardedBy("mA2dpAvrcpLock")
- /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
+ /*package*/ synchronized int getA2dpCodec(@NonNull BluetoothDevice device) {
if (mA2dp == null) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
@@ -218,7 +210,7 @@
return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
}
- /*package*/ void receiveBtEvent(Intent intent) {
+ /*package*/ synchronized void receiveBtEvent(Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -226,53 +218,51 @@
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
boolean broadcast = false;
int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
- synchronized (mScoClients) {
- int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
- // broadcast intent if the connection was initated by AudioService
- if (!mScoClients.isEmpty()
- && (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL
- || mScoAudioState == SCO_STATE_ACTIVATE_REQ
- || mScoAudioState == SCO_STATE_DEACTIVATE_REQ
- || mScoAudioState == SCO_STATE_DEACTIVATING)) {
- broadcast = true;
- }
- switch (btState) {
- case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
- if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
- && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+ // broadcast intent if the connection was initated by AudioService
+ if (!mScoClients.isEmpty()
+ && (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL
+ || mScoAudioState == SCO_STATE_ACTIVATE_REQ
+ || mScoAudioState == SCO_STATE_DEACTIVATE_REQ
+ || mScoAudioState == SCO_STATE_DEACTIVATING)) {
+ broadcast = true;
+ }
+ switch (btState) {
+ case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+ && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ }
+ mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
+ break;
+ case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+ mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+ // startBluetoothSco called after stopBluetoothSco
+ if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+ if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
+ && connectBluetoothScoAudioHelper(mBluetoothHeadset,
+ mBluetoothHeadsetDevice, mScoAudioMode)) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ broadcast = false;
+ break;
}
- mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
- break;
- case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
- scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
- // startBluetoothSco called after stopBluetoothSco
- if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
- if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
- && connectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, mScoAudioMode)) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- broadcast = false;
- break;
- }
- }
- // Tear down SCO if disconnected from external
- clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
- mScoAudioState = SCO_STATE_INACTIVE;
- break;
- case BluetoothHeadset.STATE_AUDIO_CONNECTING:
- if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
- && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
- }
- break;
- default:
- // do not broadcast CONNECTING or invalid state
- broadcast = false;
- break;
- }
+ }
+ // Tear down SCO if disconnected from external
+ clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
+ mScoAudioState = SCO_STATE_INACTIVE;
+ break;
+ case BluetoothHeadset.STATE_AUDIO_CONNECTING:
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+ && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ }
+ break;
+ default:
+ // do not broadcast CONNECTING or invalid state
+ broadcast = false;
+ break;
}
if (broadcast) {
broadcastScoConnectionState(scoAudioState);
@@ -289,15 +279,13 @@
*
* @return false if SCO isn't connected
*/
- /*package*/ boolean isBluetoothScoOn() {
- synchronized (mScoClients) {
- if ((mBluetoothHeadset != null)
- && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
- Log.w(TAG, "isBluetoothScoOn(true) returning false because "
- + mBluetoothHeadsetDevice + " is not in audio connected mode");
- return false;
- }
+ /*package*/ synchronized boolean isBluetoothScoOn() {
+ if ((mBluetoothHeadset != null)
+ && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
+ Log.w(TAG, "isBluetoothScoOn(true) returning false because "
+ + mBluetoothHeadsetDevice + " is not in audio connected mode");
+ return false;
}
return true;
}
@@ -308,17 +296,15 @@
*
* @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept
*/
- /*package*/ void disconnectBluetoothSco(int exceptPid) {
- synchronized (mScoClients) {
- checkScoAudioState();
- if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
- return;
- }
- clearAllScoClients(exceptPid, true);
+ /*package*/ synchronized void disconnectBluetoothSco(int exceptPid) {
+ checkScoAudioState();
+ if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
+ return;
}
+ clearAllScoClients(exceptPid, true);
}
- /*package*/ void startBluetoothScoForClient(IBinder cb, int scoAudioMode,
+ /*package*/ synchronized void startBluetoothScoForClient(IBinder cb, int scoAudioMode,
@NonNull String eventSource) {
ScoClient client = getScoClient(cb, true);
// The calling identity must be cleared before calling ScoClient.incCount().
@@ -337,7 +323,8 @@
Binder.restoreCallingIdentity(ident);
}
- /*package*/ void stopBluetoothScoForClient(IBinder cb, @NonNull String eventSource) {
+ /*package*/ synchronized void stopBluetoothScoForClient(IBinder cb,
+ @NonNull String eventSource) {
ScoClient client = getScoClient(cb, false);
// The calling identity must be cleared before calling ScoClient.decCount().
// decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
@@ -352,36 +339,29 @@
}
- /*package*/ void setHearingAidVolume(int index, int streamType) {
- synchronized (mDeviceBroker.mHearingAidLock) {
- if (mHearingAid == null) {
- if (AudioService.DEBUG_VOL) {
- Log.i(TAG, "setHearingAidVolume: null mHearingAid");
- }
- return;
- }
- //hearing aid expect volume value in range -128dB to 0dB
- int gainDB = (int) AudioSystem.getStreamVolumeDB(streamType, index / 10,
- AudioSystem.DEVICE_OUT_HEARING_AID);
- if (gainDB < BT_HEARING_AID_GAIN_MIN) {
- gainDB = BT_HEARING_AID_GAIN_MIN;
- }
+ /*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
+ if (mHearingAid == null) {
if (AudioService.DEBUG_VOL) {
- Log.i(TAG, "setHearingAidVolume: calling mHearingAid.setVolume idx="
- + index + " gain=" + gainDB);
+ Log.i(TAG, "setHearingAidVolume: null mHearingAid");
}
- AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
- AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
- mHearingAid.setVolume(gainDB);
+ return;
}
+ //hearing aid expect volume value in range -128dB to 0dB
+ int gainDB = (int) AudioSystem.getStreamVolumeDB(streamType, index / 10,
+ AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (gainDB < BT_HEARING_AID_GAIN_MIN) {
+ gainDB = BT_HEARING_AID_GAIN_MIN;
+ }
+ if (AudioService.DEBUG_VOL) {
+ Log.i(TAG, "setHearingAidVolume: calling mHearingAid.setVolume idx="
+ + index + " gain=" + gainDB);
+ }
+ AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
+ AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
+ mHearingAid.setVolume(gainDB);
}
- //----------------------------------------------------------------------
- private void broadcastScoConnectionState(int state) {
- mDeviceBroker.broadcastScoConnectionState(state);
- }
-
- /*package*/ void onBroadcastScoConnectionState(int state) {
+ /*package*/ synchronized void onBroadcastScoConnectionState(int state) {
if (state == mScoConnectionState) {
return;
}
@@ -393,6 +373,26 @@
mScoConnectionState = state;
}
+ /*package*/ synchronized void disconnectAllBluetoothProfiles() {
+ mDeviceBroker.handleDisconnectA2dp();
+ mDeviceBroker.handleDisconnectA2dpSink();
+ disconnectHeadset();
+ mDeviceBroker.handleDisconnectHearingAid();
+ }
+
+ /*package*/ synchronized void resetBluetoothSco() {
+ clearAllScoClients(0, false);
+ mScoAudioState = SCO_STATE_INACTIVE;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ AudioSystem.setParameters("A2dpSuspended=false");
+ mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
+ }
+
+ //----------------------------------------------------------------------
+ private void broadcastScoConnectionState(int state) {
+ mDeviceBroker.broadcastScoConnectionState(state);
+ }
+
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
if (btDevice == null) {
return true;
@@ -437,25 +437,23 @@
}
private void setBtScoActiveDevice(BluetoothDevice btDevice) {
- synchronized (mScoClients) {
- Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
- final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
- if (Objects.equals(btDevice, previousActiveDevice)) {
- return;
- }
- if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
- Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
- + previousActiveDevice);
- }
- if (!handleBtScoActiveDeviceChange(btDevice, true)) {
- Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
- // set mBluetoothHeadsetDevice to null when failing to add new device
- btDevice = null;
- }
- mBluetoothHeadsetDevice = btDevice;
- if (mBluetoothHeadsetDevice == null) {
- resetBluetoothSco();
- }
+ Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
+ final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
+ if (Objects.equals(btDevice, previousActiveDevice)) {
+ return;
+ }
+ if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
+ Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
+ + previousActiveDevice);
+ }
+ if (!handleBtScoActiveDeviceChange(btDevice, true)) {
+ Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
+ // set mBluetoothHeadsetDevice to null when failing to add new device
+ btDevice = null;
+ }
+ mBluetoothHeadsetDevice = btDevice;
+ if (mBluetoothHeadsetDevice == null) {
+ resetBluetoothSco();
}
}
@@ -466,7 +464,7 @@
List<BluetoothDevice> deviceList;
switch(profile) {
case BluetoothProfile.A2DP:
- synchronized (mDeviceBroker.mA2dpAvrcpLock) {
+ synchronized (BtHelper.this) {
mA2dp = (BluetoothA2dp) proxy;
deviceList = mA2dp.getConnectedDevices();
if (deviceList.size() > 0) {
@@ -495,7 +493,7 @@
break;
case BluetoothProfile.HEADSET:
- synchronized (mScoClients) {
+ synchronized (BtHelper.this) {
// Discard timeout message
mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
mBluetoothHeadset = (BluetoothHeadset) proxy;
@@ -536,17 +534,19 @@
break;
case BluetoothProfile.HEARING_AID:
- mHearingAid = (BluetoothHearingAid) proxy;
- deviceList = mHearingAid.getConnectedDevices();
- if (deviceList.size() > 0) {
- btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- mHearingAid.getConnectionState(btDevice);
- mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
- btDevice, state,
- /*suppressNoisyIntent*/ false,
- /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
- /*eventSource*/ "mBluetoothProfileServiceListener");
+ synchronized (BtHelper.this) {
+ mHearingAid = (BluetoothHearingAid) proxy;
+ deviceList = mHearingAid.getConnectedDevices();
+ if (deviceList.size() > 0) {
+ btDevice = deviceList.get(0);
+ final @BluetoothProfile.BtProfileState int state =
+ mHearingAid.getConnectionState(btDevice);
+ mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
+ btDevice, state,
+ /*suppressNoisyIntent*/ false,
+ /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
+ /*eventSource*/ "mBluetoothProfileServiceListener");
+ }
}
break;
@@ -579,18 +579,9 @@
}
};
- void disconnectAllBluetoothProfiles() {
- mDeviceBroker.handleDisconnectA2dp();
- mDeviceBroker.handleDisconnectA2dpSink();
- disconnectHeadset();
- mDeviceBroker.handleDisconnectHearingAid();
- }
-
private void disconnectHeadset() {
- synchronized (mScoClients) {
- setBtScoActiveDevice(null);
- mBluetoothHeadset = null;
- }
+ setBtScoActiveDevice(null);
+ mBluetoothHeadset = null;
}
//----------------------------------------------------------------------
@@ -605,8 +596,12 @@
mStartcount = 0;
}
+ @Override
public void binderDied() {
- synchronized (mScoClients) {
+ // this is the only place the implementation of ScoClient needs to be synchronized
+ // on the instance, as all other methods are directly or indirectly called from
+ // package-private methods, which are synchronized
+ synchronized (BtHelper.this) {
Log.w(TAG, "SCO client died");
int index = mScoClients.indexOf(this);
if (index < 0) {
@@ -618,77 +613,69 @@
}
}
- public void incCount(int scoAudioMode) {
- synchronized (mScoClients) {
- requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
- if (mStartcount == 0) {
- try {
- mCb.linkToDeath(this, 0);
- } catch (RemoteException e) {
- // client has already died!
- Log.w(TAG, "ScoClient incCount() could not link to "
- + mCb + " binder death");
- }
- }
- mStartcount++;
- }
- }
-
- public void decCount() {
- synchronized (mScoClients) {
- if (mStartcount == 0) {
- Log.w(TAG, "ScoClient.decCount() already 0");
- } else {
- mStartcount--;
- if (mStartcount == 0) {
- try {
- mCb.unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- Log.w(TAG, "decCount() going to 0 but not registered to binder");
- }
- }
- requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+ void incCount(int scoAudioMode) {
+ requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
+ if (mStartcount == 0) {
+ try {
+ mCb.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ // client has already died!
+ Log.w(TAG, "ScoClient incCount() could not link to "
+ + mCb + " binder death");
}
}
+ mStartcount++;
}
- public void clearCount(boolean stopSco) {
- synchronized (mScoClients) {
- if (mStartcount != 0) {
+ void decCount() {
+ if (mStartcount == 0) {
+ Log.w(TAG, "ScoClient.decCount() already 0");
+ } else {
+ mStartcount--;
+ if (mStartcount == 0) {
try {
mCb.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
- Log.w(TAG, "clearCount() mStartcount: "
- + mStartcount + " != 0 but not registered to binder");
+ Log.w(TAG, "decCount() going to 0 but not registered to binder");
}
}
- mStartcount = 0;
- if (stopSco) {
- requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
- }
+ requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
}
}
- public int getCount() {
+ void clearCount(boolean stopSco) {
+ if (mStartcount != 0) {
+ try {
+ mCb.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "clearCount() mStartcount: "
+ + mStartcount + " != 0 but not registered to binder");
+ }
+ }
+ mStartcount = 0;
+ if (stopSco) {
+ requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+ }
+ }
+
+ int getCount() {
return mStartcount;
}
- public IBinder getBinder() {
+ IBinder getBinder() {
return mCb;
}
- public int getPid() {
+ int getPid() {
return mCreatorPid;
}
- public int totalCount() {
- synchronized (mScoClients) {
- int count = 0;
- for (ScoClient mScoClient : mScoClients) {
- count += mScoClient.getCount();
- }
- return count;
+ private int totalCount() {
+ int count = 0;
+ for (ScoClient mScoClient : mScoClients) {
+ count += mScoClient.getCount();
}
+ return count;
}
private void requestScoState(int state, int scoAudioMode) {
@@ -705,6 +692,7 @@
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
// Accept SCO audio activation only in NORMAL audio mode or if the mode is
// currently controlled by the same client process.
+ // TODO do not sync that way, see b/123769055
synchronized (mDeviceBroker.mSetModeLock) {
int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty()
? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid();
@@ -857,60 +845,43 @@
}
}
- /*package*/ void resetBluetoothSco() {
- synchronized (mScoClients) {
- clearAllScoClients(0, false);
- mScoAudioState = SCO_STATE_INACTIVE;
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
- }
- AudioSystem.setParameters("A2dpSuspended=false");
- mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
- }
-
-
private void checkScoAudioState() {
- synchronized (mScoClients) {
- if (mBluetoothHeadset != null
- && mBluetoothHeadsetDevice != null
- && mScoAudioState == SCO_STATE_INACTIVE
- && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
- }
+ if (mBluetoothHeadset != null
+ && mBluetoothHeadsetDevice != null
+ && mScoAudioState == SCO_STATE_INACTIVE
+ && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
}
private ScoClient getScoClient(IBinder cb, boolean create) {
- synchronized (mScoClients) {
- for (ScoClient existingClient : mScoClients) {
- if (existingClient.getBinder() == cb) {
- return existingClient;
- }
+ for (ScoClient existingClient : mScoClients) {
+ if (existingClient.getBinder() == cb) {
+ return existingClient;
}
- if (create) {
- ScoClient newClient = new ScoClient(cb);
- mScoClients.add(newClient);
- return newClient;
- }
- return null;
}
+ if (create) {
+ ScoClient newClient = new ScoClient(cb);
+ mScoClients.add(newClient);
+ return newClient;
+ }
+ return null;
}
private void clearAllScoClients(int exceptPid, boolean stopSco) {
- synchronized (mScoClients) {
- ScoClient savedClient = null;
- for (ScoClient cl : mScoClients) {
- if (cl.getPid() != exceptPid) {
- cl.clearCount(stopSco);
- } else {
- savedClient = cl;
- }
+ ScoClient savedClient = null;
+ for (ScoClient cl : mScoClients) {
+ if (cl.getPid() != exceptPid) {
+ cl.clearCount(stopSco);
+ } else {
+ savedClient = cl;
}
- mScoClients.clear();
- if (savedClient != null) {
- mScoClients.add(savedClient);
- }
+ }
+ mScoClients.clear();
+ if (savedClient != null) {
+ mScoClients.add(savedClient);
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index cefe583..19d10ec 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -509,7 +509,7 @@
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_USE_HEARTBEATS = false;
- private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
10 * 60 * 1000L; // 10 minutes
private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 09bacd6..0892b32 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,6 +18,14 @@
"include-filter": "android.permission.cts.SplitPermissionTest"
}
]
+ },
+ {
+ "name": "CtsStatsdHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.cts.statsd.atom.UidAtomTests#testDangerousPermissionState"
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/role/TEST_MAPPING b/services/core/java/com/android/server/role/TEST_MAPPING
new file mode 100644
index 0000000..9efd292
--- /dev/null
+++ b/services/core/java/com/android/server/role/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsStatsdHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.cts.statsd.atom.UidAtomTests#testRoleHolder"
+ }
+ ]
+ },
+ {
+ "name": "CtsRoleTestCases"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 146a8ed..3bb6608 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4433,7 +4433,8 @@
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing focus: " + lastFocus);
lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
}
- } break;
+ break;
+ }
case REPORT_LOSING_FOCUS: {
final DisplayContent displayContent = (DisplayContent) msg.obj;
@@ -4450,7 +4451,8 @@
losers.get(i));
losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
}
- } break;
+ break;
+ }
case WINDOW_FREEZE_TIMEOUT: {
final DisplayContent displayContent = (DisplayContent) msg.obj;
@@ -4614,12 +4616,13 @@
break;
}
- case NOTIFY_ACTIVITY_DRAWN:
+ case NOTIFY_ACTIVITY_DRAWN: {
try {
mActivityTaskManager.notifyActivityDrawn((IBinder) msg.obj);
} catch (RemoteException e) {
}
break;
+ }
case ALL_WINDOWS_DRAWN: {
Runnable callback;
synchronized (mGlobalLock) {
@@ -4656,8 +4659,8 @@
}
}
}
+ break;
}
- break;
case CHECK_IF_BOOT_ANIMATION_FINISHED: {
final boolean bootAnimationComplete;
synchronized (mGlobalLock) {
@@ -4667,15 +4670,15 @@
if (bootAnimationComplete) {
performEnableScreen();
}
+ break;
}
- break;
case RESET_ANR_MESSAGE: {
synchronized (mGlobalLock) {
mLastANRState = null;
}
mAtmInternal.clearSavedANRState();
+ break;
}
- break;
case WALLPAPER_DRAW_PENDING_TIMEOUT: {
synchronized (mGlobalLock) {
final WallpaperController wallpaperController =
@@ -4685,16 +4688,16 @@
mWindowPlacerLocked.performSurfacePlacement();
}
}
+ break;
}
- break;
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mGlobalLock) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
displayContent.getDockedDividerController().reevaluateVisibility(false);
displayContent.adjustForImeIfNeeded();
}
+ break;
}
- break;
case WINDOW_REPLACEMENT_TIMEOUT: {
synchronized (mGlobalLock) {
for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
@@ -4703,8 +4706,8 @@
}
mWindowReplacementTimeouts.clear();
}
+ break;
}
- break;
case WINDOW_HIDE_TIMEOUT: {
final WindowState window = (WindowState) msg.obj;
synchronized (mGlobalLock) {
@@ -4724,44 +4727,44 @@
window.setDisplayLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement();
}
+ break;
}
- break;
case RESTORE_POINTER_ICON: {
synchronized (mGlobalLock) {
restorePointerIconLocked((DisplayContent)msg.obj, msg.arg1, msg.arg2);
}
+ break;
}
- break;
case SEAMLESS_ROTATION_TIMEOUT: {
final DisplayContent displayContent = (DisplayContent) msg.obj;
synchronized (mGlobalLock) {
displayContent.onSeamlessRotationTimeout();
}
+ break;
}
- break;
case SET_HAS_OVERLAY_UI: {
mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
+ break;
}
- break;
case SET_RUNNING_REMOTE_ANIMATION: {
mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
+ break;
}
- break;
case ANIMATION_FAILSAFE: {
synchronized (mGlobalLock) {
if (mRecentsAnimationController != null) {
mRecentsAnimationController.scheduleFailsafe();
}
}
+ break;
}
- break;
case RECOMPUTE_FOCUS: {
synchronized (mGlobalLock) {
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
true /* updateInputWindows */);
}
+ break;
}
- break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index c50e6a7..c5b9cf1 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1099,9 +1099,13 @@
*/
public static final int DISABLED_BY_WRONG_PASSWORD = 13;
/**
+ * This network is disabled because service is not subscribed
+ */
+ public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14;
+ /**
* This Maximum disable reason value
*/
- public static final int NETWORK_SELECTION_DISABLED_MAX = 14;
+ public static final int NETWORK_SELECTION_DISABLED_MAX = 15;
/**
* Quality network selection disable reason String (for debug purpose)
@@ -1120,7 +1124,8 @@
"NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
"NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
"NETWORK_SELECTION_DISABLED_BY_USER_SWITCH",
- "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD"
+ "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
+ "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION"
};
/**