Merge "Fix issue #65259946: APR: runtime restart: at com.android.server.am.ActivityManagerService" into oc-mr1-dev
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 5dd47ac..9f1e983 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -232,8 +232,8 @@
private class SurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ mSurface = mSurfaceView.getHolder().getSurface();
if (mVirtualDisplay == null) {
- mSurface = mSurfaceView.getHolder().getSurface();
initVirtualDisplay();
if (mVirtualDisplay != null && mActivityViewCallback != null) {
mActivityViewCallback.onActivityViewReady(ActivityView.this);
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 59fb269..df0e262 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -79,8 +79,9 @@
private static final int EVENT_DB_CORRUPT = 75004;
+ // By default idle connections are not closed
private static final boolean DEBUG_CLOSE_IDLE_CONNECTIONS = SystemProperties
- .getBoolean("persist.debug.sqlite.close_idle_connections", true);
+ .getBoolean("persist.debug.sqlite.close_idle_connections", false);
// Stores reference to all databases opened in the current process.
// (The referent Object is not used at this time.)
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index fe9e8c6..da0ed54 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -149,14 +149,43 @@
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
+ * This will fallback to a generic pattern if one exists and there does not exist a
+ * hardware-specific implementation of the effect.
+ *
* @param effectId The ID of the effect to perform:
- * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}.
+ * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
*
* @return The desired effect.
* @hide
*/
public static VibrationEffect get(int effectId) {
- VibrationEffect effect = new Prebaked(effectId);
+ return get(effectId, true);
+ }
+
+ /**
+ * Get a predefined vibration effect.
+ *
+ * Predefined effects are a set of common vibration effects that should be identical, regardless
+ * of the app they come from, in order to provide a cohesive experience for users across
+ * the entire device. They also may be custom tailored to the device hardware in order to
+ * provide a better experience than you could otherwise build using the generic building
+ * blocks.
+ *
+ * Some effects you may only want to play if there's a hardware specific implementation because
+ * they may, for example, be too disruptive to the user without tuning. The {@code fallback}
+ * parameter allows you to decide whether you want to fallback to the generic implementation or
+ * only play if there's a tuned, hardware specific one available.
+ *
+ * @param effectId The ID of the effect to perform:
+ * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
+ * @param fallback Whether to fallback to a generic pattern if a hardware specific
+ * implementation doesn't exist.
+ *
+ * @return The desired effect.
+ * @hide
+ */
+ public static VibrationEffect get(int effectId, boolean fallback) {
+ VibrationEffect effect = new Prebaked(effectId, fallback);
effect.validate();
return effect;
}
@@ -374,19 +403,29 @@
/** @hide */
public static class Prebaked extends VibrationEffect implements Parcelable {
private int mEffectId;
+ private boolean mFallback;
public Prebaked(Parcel in) {
- this(in.readInt());
+ this(in.readInt(), in.readByte() != 0);
}
- public Prebaked(int effectId) {
+ public Prebaked(int effectId, boolean fallback) {
mEffectId = effectId;
+ mFallback = fallback;
}
public int getId() {
return mEffectId;
}
+ /**
+ * Whether the effect should fall back to a generic pattern if there's no hardware specific
+ * implementation of it.
+ */
+ public boolean shouldFallback() {
+ return mFallback;
+ }
+
@Override
public void validate() {
switch (mEffectId) {
@@ -406,7 +445,7 @@
return false;
}
VibrationEffect.Prebaked other = (VibrationEffect.Prebaked) o;
- return mEffectId == other.mEffectId;
+ return mEffectId == other.mEffectId && mFallback == other.mFallback;
}
@Override
@@ -416,7 +455,7 @@
@Override
public String toString() {
- return "Prebaked{mEffectId=" + mEffectId + "}";
+ return "Prebaked{mEffectId=" + mEffectId + ", mFallback=" + mFallback + "}";
}
@@ -424,6 +463,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(PARCEL_TOKEN_EFFECT);
out.writeInt(mEffectId);
+ out.writeByte((byte) (mFallback ? 1 : 0));
}
public static final Parcelable.Creator<Prebaked> CREATOR =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ada7b2b..86c9246 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9332,6 +9332,25 @@
public static final String ANOMALY_DETECTION_CONSTANTS = "anomaly_detection_constants";
/**
+ * Always on display(AOD) specific settings
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "prox_screen_off_delay=10000,screen_brightness_array=0:1:2:3:4"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * screen_brightness_array (string)
+ * dimming_scrim_array (string)
+ * prox_screen_off_delay (long)
+ * prox_cooldown_trigger (long)
+ * prox_cooldown_period (long)
+ * </pre>
+ * @hide
+ */
+ public static final String ALWAYS_ON_DISPLAY_CONSTANTS = "always_on_display_constants";
+
+ /**
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index b6a9a26..3b09c67 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -302,7 +302,7 @@
// TODO: create a dump() method instead
return new StringBuilder(
"FillResponse : [mRequestId=" + mRequestId)
- .append(", datasets=").append(mDatasets)
+ .append(", datasets=").append(mDatasets == null ? "N/A" : mDatasets.getList())
.append(", saveInfo=").append(mSaveInfo)
.append(", clientState=").append(mClientState != null)
.append(", hasPresentation=").append(mPresentation != null)
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 80f4b99..ceb06f5 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1941,7 +1941,8 @@
final int checkedPos = mAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (!useLayoutWithDefault()
- && (!hasValidSelection || mLastSelected != checkedPos)) {
+ && (!hasValidSelection || mLastSelected != checkedPos)
+ && mAlwaysButton != null) {
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 17a598a..4b80a5f 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -28,7 +28,6 @@
import android.graphics.Point;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileObserver;
@@ -74,7 +73,6 @@
private Handler mHandler;
- private static final String MIMETYPE_PDF = "application/pdf";
private static final String MIMETYPE_JPEG = "image/jpeg";
@@ -425,13 +423,6 @@
String documentId, Point sizeHint, CancellationSignal signal)
throws FileNotFoundException {
final File file = getFileForDocId(documentId);
- if (getTypeForFile(file).equals(MIMETYPE_PDF)) {
- try {
- return PdfUtils.openPdfThumbnail(file, sizeHint);
- } catch (Exception e) {
- Log.v(TAG, "Could not load PDF's thumbnail", e);
- }
- }
return DocumentsContract.openImageThumbnail(file);
}
@@ -461,10 +452,7 @@
final String mimeType = getTypeForFile(file);
final String displayName = file.getName();
- // As of right now, we aren't sure on the performance affect of loading all PDF Thumbnails
- // Until a solution is found, it will be behind a debuggable flag.
- if (mimeType.startsWith("image/")
- || (mimeType.equals(MIMETYPE_PDF) && Build.IS_DEBUGGABLE)) {
+ if (mimeType.startsWith("image/")) {
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 60fbbe9..0d962eb 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1812,7 +1812,7 @@
mFloatingActionMode.finish();
}
cleanupFloatingActionModeViews();
- mFloatingToolbar = new FloatingToolbar(mContext, mWindow);
+ mFloatingToolbar = new FloatingToolbar(mWindow);
final FloatingActionMode mode =
new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
mFloatingActionModeOriginatingView = originatingView;
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 1d56e1a..f63b5a2 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -120,8 +120,10 @@
/**
* Initializes a floating toolbar.
*/
- public FloatingToolbar(Context context, Window window) {
- mContext = applyDefaultTheme(Preconditions.checkNotNull(context));
+ public FloatingToolbar(Window window) {
+ // TODO(b/65172902): Pass context in constructor when DecorView (and other callers)
+ // supports multi-display.
+ mContext = applyDefaultTheme(window.getContext());
mWindow = Preconditions.checkNotNull(window);
mPopup = new FloatingToolbarPopup(mContext, window.getDecorView());
}
diff --git a/core/res/res/values-mcc505-mnc01/config.xml b/core/res/res/values-mcc505-mnc01/config.xml
index ff06585..5a5b8f7 100644
--- a/core/res/res/values-mcc505-mnc01/config.xml
+++ b/core/res/res/values-mcc505-mnc01/config.xml
@@ -31,15 +31,6 @@
<item>9</item>
</integer-array>
- <!-- String containing the apn value for tethering. May be overriden by secure settings
- TETHER_DUN_APN. Value is a comma separated series of strings:
- "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type",
- Or string format of ApnSettingV3.
- note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
- <string-array translatable="false" name="config_tether_apndata">
- <item>Telstra Tethering,telstra.internet,,,,,,,,,505,01,,DUN</item>
- </string-array>
-
<!--Thresholds for LTE dbm in status bar-->
<integer-array translatable="false" name="config_lteDbmThresholds">
<item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 24a4bae..6756e34 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -99,6 +99,7 @@
Settings.Global.ALARM_MANAGER_CONSTANTS,
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
Settings.Global.ALWAYS_FINISH_ACTIVITIES,
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS,
Settings.Global.ANIMATOR_DURATION_SCALE,
Settings.Global.ANOMALY_DETECTION_CONSTANTS,
Settings.Global.APN_DB_UPDATE_CONTENT_URL,
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 4e59baa..3c3b317 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -216,10 +216,7 @@
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewIdentityEmptyBounds()
.build();
- // Disable blending if this is the first draw to the main framebuffer, in case app has defined
- // transparency where it doesn't make sense - as first draw in opaque window.
- bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId;
- mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
+ mRenderState.render(glop, mRenderTarget.orthoMatrix, false);
mHasDrawn = true;
}
@@ -350,8 +347,14 @@
const Glop& glop) {
prepareRender(dirtyBounds, clip);
// Disable blending if this is the first draw to the main framebuffer, in case app has defined
- // transparency where it doesn't make sense - as first draw in opaque window.
- bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId;
+ // transparency where it doesn't make sense - as first draw in opaque window. Note that we only
+ // apply this improvement when the blend mode is SRC_OVER - other modes (e.g. CLEAR) can be
+ // valid draws that affect other content (e.g. draw CLEAR, then draw DST_OVER)
+ bool overrideDisableBlending = !mHasDrawn
+ && mOpaque
+ && !mRenderTarget.frameBufferId
+ && glop.blend.src == GL_ONE
+ && glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
index ec0e114..a9de246 100644
--- a/libs/hwui/renderstate/Blend.h
+++ b/libs/hwui/renderstate/Blend.h
@@ -40,6 +40,14 @@
GLenum* outSrc, GLenum* outDst);
void setFactors(GLenum src, GLenum dst);
+ bool getEnabled() {
+ return mEnabled;
+ }
+ void getFactors(GLenum* src, GLenum* dst) {
+ *src = mSrcMode;
+ *dst = mDstMode;
+ }
+
void dump();
private:
Blend();
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
index 603599c..38e106a 100644
--- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <BakedOpRenderer.h>
+#include <GlopBuilder.h>
#include <tests/common/TestUtils.h>
using namespace android::uirenderer;
@@ -53,3 +54,53 @@
renderer.endLayer();
}
}
+
+static void drawFirstOp(RenderState& renderState, int color, SkBlendMode mode) {
+ BakedOpRenderer renderer(Caches::getInstance(), renderState, true, false, sLightInfo);
+
+ renderer.startFrame(100, 100, Rect(100, 100));
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setBlendMode(mode);
+
+ Rect dest(0, 0, 100, 100);
+ Glop glop;
+ GlopBuilder(renderState, Caches::getInstance(), &glop)
+ .setRoundRectClipState(nullptr)
+ .setMeshUnitQuad()
+ .setFillPaint(paint, 1.0f)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewMapUnitToRectSnap(dest)
+ .build();
+ renderer.renderGlop(nullptr, nullptr, glop);
+ renderer.endFrame(Rect(100, 100));
+}
+
+static void verifyBlend(RenderState& renderState, GLenum expectedSrc, GLenum expectedDst) {
+ EXPECT_TRUE(renderState.blend().getEnabled());
+ GLenum src;
+ GLenum dst;
+ renderState.blend().getFactors(&src, &dst);
+ EXPECT_EQ(expectedSrc, src);
+ EXPECT_EQ(expectedDst, dst);
+}
+
+static void verifyBlendDisabled(RenderState& renderState) {
+ EXPECT_FALSE(renderState.blend().getEnabled());
+}
+
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, firstDrawBlend_clear) {
+ // initialize blend state to nonsense value
+ renderThread.renderState().blend().setFactors(GL_ONE, GL_ONE);
+
+ drawFirstOp(renderThread.renderState(), 0xfeff0000, SkBlendMode::kClear);
+ verifyBlend(renderThread.renderState(), GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, firstDrawBlend_srcover) {
+ // initialize blend state to nonsense value
+ renderThread.renderState().blend().setFactors(GL_ONE, GL_ONE);
+
+ drawFirstOp(renderThread.renderState(), 0xfeff0000, SkBlendMode::kSrcOver);
+ verifyBlendDisabled(renderThread.renderState());
+}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 3308fc9..dc7fa8c 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -28,6 +28,7 @@
MediaRouterClientState getState(IMediaRouterClient client);
boolean isPlaybackActive(IMediaRouterClient client);
+ boolean isGlobalBluetoothA2doOn();
void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 29b88a2..2894e89 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -88,7 +88,6 @@
RouteInfo mBluetoothA2dpRoute;
RouteInfo mSelectedRoute;
- RouteInfo mSystemAudioRoute;
final boolean mCanConfigureWifiDisplays;
boolean mActivelyScanningWifiDisplays;
@@ -150,7 +149,6 @@
}
addRouteStatic(mDefaultAudioVideo);
- mSystemAudioRoute = mDefaultAudioVideo;
// This will select the active wifi display route if there is one.
updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus());
@@ -185,7 +183,7 @@
}
void updateAudioRoutes(AudioRoutesInfo newRoutes) {
- boolean updated = false;
+ boolean audioRoutesChanged = false;
if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
mCurAudioRoutesInfo.mainType = newRoutes.mainType;
int name;
@@ -201,11 +199,10 @@
}
mDefaultAudioVideo.mNameResId = name;
dispatchRouteChanged(mDefaultAudioVideo);
- updated = true;
+ audioRoutesChanged = true;
}
final int mainType = mCurAudioRoutesInfo.mainType;
-
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
if (mCurAudioRoutesInfo.bluetoothName != null) {
@@ -219,8 +216,6 @@
info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH;
mBluetoothA2dpRoute = info;
addRouteStatic(mBluetoothA2dpRoute);
- mSystemAudioRoute = mBluetoothA2dpRoute;
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false);
} else {
mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
dispatchRouteChanged(mBluetoothA2dpRoute);
@@ -229,30 +224,32 @@
// BT disconnected
removeRouteStatic(mBluetoothA2dpRoute);
mBluetoothA2dpRoute = null;
- mSystemAudioRoute = mDefaultAudioVideo;
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false);
}
- updated = true;
+ audioRoutesChanged = true;
}
- if (mBluetoothA2dpRoute != null) {
- final boolean a2dpEnabled = isBluetoothA2dpOn();
- if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
- // A2DP off
- mSystemAudioRoute = mDefaultAudioVideo;
- updated = true;
- } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
- a2dpEnabled) {
- // A2DP on or BT connected
- mSystemAudioRoute = mBluetoothA2dpRoute;
- updated = true;
- }
- }
- if (updated) {
+ if (audioRoutesChanged) {
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
}
}
+ RouteInfo getDefaultSystemAudioRoute() {
+ boolean globalBluetoothA2doOn = false;
+ try {
+ globalBluetoothA2doOn = mMediaRouterService.isGlobalBluetoothA2doOn();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to call isSystemBluetoothA2doOn.", ex);
+ }
+ return (globalBluetoothA2doOn && mBluetoothA2dpRoute != null)
+ ? mBluetoothA2dpRoute : mDefaultAudioVideo;
+ }
+
+ RouteInfo getCurrentSystemAudioRoute() {
+ return (isBluetoothA2dpOn() && mBluetoothA2dpRoute != null)
+ ? mBluetoothA2dpRoute : mDefaultAudioVideo;
+ }
+
boolean isBluetoothA2dpOn() {
try {
return mAudioService.isBluetoothA2dpOn();
@@ -603,15 +600,13 @@
@Override
public void onRestoreRoute() {
+ // Skip restoring route if the selected route is not a system audio route, or
+ // MediaRouter is initializing.
if ((mSelectedRoute != mDefaultAudioVideo && mSelectedRoute != mBluetoothA2dpRoute)
- || mSelectedRoute == mSystemAudioRoute) {
+ || mSelectedRoute == null) {
return;
}
- try {
- sStatic.mAudioService.setBluetoothA2dpOn(mSelectedRoute == mBluetoothA2dpRoute);
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing Bluetooth A2DP state", e);
- }
+ mSelectedRoute.select();
}
}
}
@@ -946,7 +941,7 @@
boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
|| oldRoute == sStatic.mBluetoothA2dpRoute);
if (oldRoute == route
- && (!wasDefaultOrBluetoothRoute || oldRoute == sStatic.mSystemAudioRoute)) {
+ && (!wasDefaultOrBluetoothRoute || route == sStatic.getCurrentSystemAudioRoute())) {
return;
}
if (!route.matchesTypes(types)) {
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index b0052cc..a61881f 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -82,6 +82,7 @@
private MyWebViewClient mWebViewClient;
private boolean mLaunchBrowser = false;
private Thread mTestingThread = null;
+ private boolean mReload = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -290,9 +291,13 @@
mCm.bindProcessToNetwork(network);
mNetwork = network;
runOnUiThreadIfNotFinishing(() -> {
- // Start initial page load so WebView finishes loading proxy settings.
- // Actual load of mUrl is initiated by MyWebViewClient.
- mWebView.loadData("", "text/html", null);
+ if (mReload) {
+ mWebView.reload();
+ } else {
+ // Start initial page load so WebView finishes loading proxy settings.
+ // Actual load of mUrl is initiated by MyWebViewClient.
+ mWebView.loadData("", "text/html", null);
+ }
});
}
@@ -305,6 +310,12 @@
mWebView.loadUrl(mUrl.toString());
});
}
+
+ @Override
+ public void onLost(Network lostNetwork) {
+ if (DBG) logd("Network lost");
+ mReload = true;
+ }
};
logd("request Network for captive portal");
mCm.requestNetwork(request, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MS);
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index a2bf964..33cb5964 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.PhoneConstants;
import com.android.carrierdefaultapp.R;
@@ -199,13 +200,19 @@
PendingIntent pendingIntent) {
final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
final Resources resources = context.getResources();
+ String spn = telephonyMgr.getSimOperatorName();
+ if (TextUtils.isEmpty(spn)) {
+ // There is no consistent way to get the current carrier name as MNOs didn't
+ // bother to set EF_SPN. in the long term, we should display a generic wording if
+ // spn from subscription is not set.
+ spn = telephonyMgr.getNetworkOperatorName();
+ }
final Bundle extras = Bundle.forPair(Notification.EXTRA_SUBSTITUTE_APP_NAME,
resources.getString(R.string.android_system_label));
createNotificationChannels(context);
Notification.Builder builder = new Notification.Builder(context)
.setContentTitle(resources.getString(titleId))
- .setContentText(String.format(resources.getString(textId),
- telephonyMgr.getNetworkOperatorName()))
+ .setContentText(String.format(resources.getString(textId), spn))
.setSmallIcon(R.drawable.ic_sim_card)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 0bf2eda..77df02b 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -105,6 +105,7 @@
<!-- Titles for Bluetooth AVRCP Versions -->
<string-array name="bluetooth_avrcp_versions">
<item>AVRCP 1.4 (Default)</item>
+ <item>AVRCP 1.3</item>
<item>AVRCP 1.5</item>
<item>AVRCP 1.6</item>
</string-array>
@@ -112,6 +113,7 @@
<!-- Values for Bluetooth AVRCP Versions -->
<string-array name="bluetooth_avrcp_version_values">
<item>avrcp14</item>
+ <item>avrcp13</item>
<item>avrcp15</item>
<item>avrcp16</item>
</string-array>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 2c4f9c4..c24cdae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -76,10 +76,10 @@
public static String generatePreferenceKey(AccessPoint accessPoint) {
StringBuilder builder = new StringBuilder();
- if (TextUtils.isEmpty(accessPoint.getBssid())) {
- builder.append(accessPoint.getSsidStr());
- } else {
+ if (TextUtils.isEmpty(accessPoint.getSsidStr())) {
builder.append(accessPoint.getBssid());
+ } else {
+ builder.append(accessPoint.getSsidStr());
}
builder.append(',').append(accessPoint.getSecurity());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
index 7fe69a7..6cfdc28 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
@@ -36,26 +36,28 @@
private Context mContext = RuntimeEnvironment.application;
@Test
- public void generatePreferenceKey_shouldReturnSsidPlusSecurity() {
+ public void generatePreferenceKey_returnsSsidPlusSecurity() {
String ssid = "ssid";
+ String bssid = "00:00:00:00:00:00";
int security = AccessPoint.SECURITY_WEP;
String expectedKey = ssid + ',' + security;
TestAccessPointBuilder builder = new TestAccessPointBuilder(mContext);
- builder.setSsid(ssid).setSecurity(security);
+ builder.setBssid(bssid).setSsid(ssid).setSecurity(security);
assertThat(AccessPointPreference.generatePreferenceKey(builder.build()))
.isEqualTo(expectedKey);
}
@Test
- public void generatePreferenceKey_shouldReturnBssidPlusSecurity() {
- String bssid = "bssid";
+ public void generatePreferenceKey_emptySsidReturnsBssidPlusSecurity() {
+ String ssid = "";
+ String bssid = "00:00:00:00:00:00";
int security = AccessPoint.SECURITY_WEP;
String expectedKey = bssid + ',' + security;
TestAccessPointBuilder builder = new TestAccessPointBuilder(mContext);
- builder.setBssid(bssid).setSecurity(security);
+ builder.setBssid(bssid).setSsid(ssid).setSecurity(security);
assertThat(AccessPointPreference.generatePreferenceKey(builder.build()))
.isEqualTo(expectedKey);
diff --git a/packages/SystemUI/res/drawable/car_qs_background_primary.xml b/packages/SystemUI/res/drawable/car_qs_background_primary.xml
deleted file mode 100644
index 0f77987..0000000
--- a/packages/SystemUI/res/drawable/car_qs_background_primary.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android">
- <shape>
- <solid android:color="?android:attr/colorPrimaryDark"/>
- </shape>
-</inset>
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index deb494f..59c0957 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -26,4 +26,5 @@
android:textColor="?android:attr/textColorPrimary"
android:gravity="center_vertical|start"
android:paddingEnd="@dimen/battery_level_padding_start"
+ android:importantForAccessibility="no"
/>
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index 0b46b0b..4cb0fd5 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -18,12 +18,13 @@
android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/car_qs_background_primary"
+ android:background="@color/car_qs_background_primary"
android:orientation="vertical"
- android:elevation="4dp">
+ android:elevation="4dp"
+ android:theme="@android:style/Theme">
- <include layout="@layout/car_status_bar_header" />
- <include layout="@layout/car_qs_footer" />
+ <include layout="@layout/car_status_bar_header"/>
+ <include layout="@layout/car_qs_footer"/>
<com.android.systemui.statusbar.car.UserGridView
android:id="@+id/user_grid"
diff --git a/packages/SystemUI/res/layout/home.xml b/packages/SystemUI/res/layout/home.xml
index 53ef2ab..7b67b79 100644
--- a/packages/SystemUI/res/layout/home.xml
+++ b/packages/SystemUI/res/layout/home.xml
@@ -23,8 +23,8 @@
systemui:keyCode="3"
android:scaleType="fitCenter"
android:contentDescription="@string/accessibility_home"
- android:paddingTop="13dp"
- android:paddingBottom="13dp"
+ android:paddingTop="@dimen/home_padding"
+ android:paddingBottom="@dimen/home_padding"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
diff --git a/packages/SystemUI/res/values/colors_car.xml b/packages/SystemUI/res/values/colors_car.xml
index 9593fe5..1b8c2fa 100644
--- a/packages/SystemUI/res/values/colors_car.xml
+++ b/packages/SystemUI/res/values/colors_car.xml
@@ -17,6 +17,7 @@
*/
-->
<resources>
+ <color name="car_qs_background_primary">#263238</color> <!-- Blue Gray 900 -->
<color name="car_user_switcher_progress_bgcolor">#00000000</color> <!-- Transparent -->
<color name="car_user_switcher_progress_fgcolor">#80CBC4</color> <!-- Teal 200 -->
<color name="car_user_switcher_no_user_image_bgcolor">#FAFAFA</color> <!-- Grey 50 -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 54421f74..bcaafcc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -854,4 +854,7 @@
<!-- How far to inset the rounded edges -->
<dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen>
+ <!-- Home button padding for sizing -->
+ <dimen name="home_padding">15dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
new file mode 100644
index 0000000..d1d1808
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 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.doze;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.KeyValueListParser;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+import java.util.Arrays;
+
+/**
+ * Class to store the policy for AOD, which comes from
+ * {@link android.provider.Settings.Global}
+ */
+public class AlwaysOnDisplayPolicy {
+ public static final String TAG = "AlwaysOnDisplayPolicy";
+
+ static final String KEY_SCREEN_BRIGHTNESS_ARRAY = "screen_brightness_array";
+ static final String KEY_DIMMING_SCRIM_ARRAY = "dimming_scrim_array";
+ static final String KEY_PROX_SCREEN_OFF_DELAY_MS = "prox_screen_off_delay";
+ static final String KEY_PROX_COOLDOWN_TRIGGER_MS = "prox_cooldown_trigger";
+ static final String KEY_PROX_COOLDOWN_PERIOD_MS = "prox_cooldown_period";
+
+ /**
+ * Integer array to map ambient brightness type to real screen brightness.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_SCREEN_BRIGHTNESS_ARRAY
+ */
+ public final int[] screenBrightnessArray;
+
+ /**
+ * Integer array to map ambient brightness type to dimming scrim.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_DIMMING_SCRIM_ARRAY
+ */
+ public final int[] dimmingScrimArray;
+
+ /**
+ * Delay time(ms) from covering the prox to turning off the screen.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_PROX_SCREEN_OFF_DELAY_MS
+ */
+ public final long proxScreenOffDelayMs;
+
+ /**
+ * The threshold time(ms) to trigger the cooldown timer, which will
+ * turn off prox sensor for a period.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_PROX_COOLDOWN_TRIGGER_MS
+ */
+ public final long proxCooldownTriggerMs;
+
+ /**
+ * The period(ms) to turning off the prox sensor if
+ * {@link #KEY_PROX_COOLDOWN_TRIGGER_MS} is triggered.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_PROX_COOLDOWN_PERIOD_MS
+ */
+ public final long proxCooldownPeriodMs;
+
+ private final KeyValueListParser mParser;
+
+ public AlwaysOnDisplayPolicy(Context context) {
+ final Resources resources = context.getResources();
+ mParser = new KeyValueListParser(',');
+
+ final String value = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
+
+ try {
+ mParser.setString(value);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Bad AOD constants");
+ }
+
+ proxScreenOffDelayMs = mParser.getLong(KEY_PROX_SCREEN_OFF_DELAY_MS,
+ 10 * DateUtils.MINUTE_IN_MILLIS);
+ proxCooldownTriggerMs = mParser.getLong(KEY_PROX_COOLDOWN_TRIGGER_MS,
+ 2 * DateUtils.MINUTE_IN_MILLIS);
+ proxCooldownPeriodMs = mParser.getLong(KEY_PROX_COOLDOWN_PERIOD_MS,
+ 5 * DateUtils.MINUTE_IN_MILLIS);
+ screenBrightnessArray = parseIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
+ resources.getIntArray(R.array.config_doze_brightness_sensor_to_brightness));
+ dimmingScrimArray = parseIntArray(KEY_DIMMING_SCRIM_ARRAY,
+ resources.getIntArray(R.array.config_doze_brightness_sensor_to_scrim_opacity));
+ }
+
+ private int[] parseIntArray(final String key, final int[] defaultArray) {
+ final String value = mParser.getString(key, null);
+ if (value != null) {
+ return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
+ Integer::parseInt).toArray();
+ } else {
+ return defaultArray;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index d374d68..6f8bcff 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -59,7 +59,7 @@
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock);
machine.setParts(new DozeMachine.Part[]{
- new DozePauser(handler, machine, alarmManager),
+ new DozePauser(handler, machine, alarmManager, new AlwaysOnDisplayPolicy(context)),
new DozeFalsingManagerAdapter(FalsingManager.getInstance(context)),
createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
handler, wakeLock, machine),
@@ -76,7 +76,8 @@
Handler handler) {
Sensor sensor = DozeSensors.findSensorWithType(sensorManager,
context.getString(R.string.doze_brightness_sensor_type));
- return new DozeScreenBrightness(context, service, sensorManager, sensor, host, handler);
+ return new DozeScreenBrightness(context, service, sensorManager, sensor, host, handler,
+ new AlwaysOnDisplayPolicy(context));
}
private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
index a33b454c..76a1902 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
@@ -26,20 +26,22 @@
*/
public class DozePauser implements DozeMachine.Part {
public static final String TAG = DozePauser.class.getSimpleName();
- private static final long TIMEOUT = 10 * 1000;
private final AlarmTimeout mPauseTimeout;
private final DozeMachine mMachine;
+ private final long mTimeoutMs;
- public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager) {
+ public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager,
+ AlwaysOnDisplayPolicy policy) {
mMachine = machine;
mPauseTimeout = new AlarmTimeout(alarmManager, this::onTimeout, TAG, handler);
+ mTimeoutMs = policy.proxScreenOffDelayMs;
}
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD_PAUSING:
- mPauseTimeout.schedule(TIMEOUT, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ mPauseTimeout.schedule(mTimeoutMs, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
break;
default:
mPauseTimeout.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 30420529..11b4b0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -42,7 +42,7 @@
public DozeScreenBrightness(Context context, DozeMachine.Service service,
SensorManager sensorManager, Sensor lightSensor, DozeHost host,
- Handler handler) {
+ Handler handler, AlwaysOnDisplayPolicy policy) {
mContext = context;
mDozeService = service;
mSensorManager = sensorManager;
@@ -50,10 +50,8 @@
mDozeHost = host;
mHandler = handler;
- mSensorToBrightness = context.getResources().getIntArray(
- R.array.config_doze_brightness_sensor_to_brightness);
- mSensorToScrimOpacity = context.getResources().getIntArray(
- R.array.config_doze_brightness_sensor_to_scrim_opacity);
+ mSensorToBrightness = policy.screenBrightnessArray;
+ mSensorToScrimOpacity = policy.dimmingScrimArray;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 566353c..91cde37 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -72,7 +72,7 @@
public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
DozeParameters dozeParameters,
AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback,
- Consumer<Boolean> proxCallback) {
+ Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) {
mContext = context;
mAlarmManager = alarmManager;
mSensorManager = sensorManager;
@@ -112,7 +112,7 @@
true /* touchscreen */),
};
- mProxSensor = new ProxSensor();
+ mProxSensor = new ProxSensor(policy);
mCallback = callback;
}
@@ -206,17 +206,16 @@
private class ProxSensor implements SensorEventListener {
- static final long COOLDOWN_TRIGGER = 2 * 1000;
- static final long COOLDOWN_PERIOD = 5 * 1000;
-
boolean mRequested;
boolean mRegistered;
Boolean mCurrentlyFar;
long mLastNear;
final AlarmTimeout mCooldownTimer;
+ final AlwaysOnDisplayPolicy mPolicy;
- public ProxSensor() {
+ public ProxSensor(AlwaysOnDisplayPolicy policy) {
+ mPolicy = policy;
mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered,
"prox_cooldown", mHandler);
}
@@ -264,11 +263,12 @@
// Sensor has been unregistered by the proxCallback. Do nothing.
} else if (!mCurrentlyFar) {
mLastNear = now;
- } else if (mCurrentlyFar && now - mLastNear < COOLDOWN_TRIGGER) {
+ } else if (mCurrentlyFar && now - mLastNear < mPolicy.proxCooldownTriggerMs) {
// If the last near was very recent, we might be using more power for prox
// wakeups than we're saving from turning of the screen. Instead, turn it off
// for a while.
- mCooldownTimer.schedule(COOLDOWN_PERIOD, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ mCooldownTimer.schedule(mPolicy.proxCooldownPeriodMs,
+ AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
updateRegistered();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 4583160..f7a258a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -84,7 +84,8 @@
mWakeLock = wakeLock;
mAllowPulseTriggers = allowPulseTriggers;
mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
- config, wakeLock, this::onSensor, this::onProximityFar);
+ config, wakeLock, this::onSensor, this::onProximityFar,
+ new AlwaysOnDisplayPolicy(context));
mUiModeManager = mContext.getSystemService(UiModeManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 13ba7c1..901b0b0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -19,6 +19,7 @@
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ALLOW_TIMEOUT;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_WILL_RESIZE_MENU;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_DISMISS_FRACTION;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MOVEMENT_BOUNDS;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MENU_STATE;
@@ -132,7 +133,8 @@
showMenu(data.getInt(EXTRA_MENU_STATE),
data.getParcelable(EXTRA_STACK_BOUNDS),
data.getParcelable(EXTRA_MOVEMENT_BOUNDS),
- data.getBoolean(EXTRA_ALLOW_TIMEOUT));
+ data.getBoolean(EXTRA_ALLOW_TIMEOUT),
+ data.getBoolean(EXTRA_WILL_RESIZE_MENU));
break;
}
case MESSAGE_POKE_MENU:
@@ -307,12 +309,14 @@
}
private void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
- boolean allowMenuTimeout) {
+ boolean allowMenuTimeout, boolean resizeMenuOnShow) {
mAllowMenuTimeout = allowMenuTimeout;
if (mMenuState != menuState) {
- boolean deferTouchesUntilAnimationEnds = (mMenuState == MENU_STATE_FULL) ||
- (menuState == MENU_STATE_FULL);
- mAllowTouches = !deferTouchesUntilAnimationEnds;
+ // Disallow touches if the menu needs to resize while showing, and we are transitioning
+ // to/from a full menu state.
+ boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow &&
+ (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
+ mAllowTouches = !disallowTouchesUntilAnimationEnd;
cancelDelayedFinish();
updateActionViews(stackBounds);
if (mMenuContainerAnimator != null) {
@@ -409,7 +413,8 @@
Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
Rect movementBounds = intent.getParcelableExtra(EXTRA_MOVEMENT_BOUNDS);
boolean allowMenuTimeout = intent.getBooleanExtra(EXTRA_ALLOW_TIMEOUT, true);
- showMenu(menuState, stackBounds, movementBounds, allowMenuTimeout);
+ boolean willResizeMenu = intent.getBooleanExtra(EXTRA_WILL_RESIZE_MENU, false);
+ showMenu(menuState, stackBounds, movementBounds, allowMenuTimeout, willResizeMenu);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index c558056..e898a51 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -63,6 +63,7 @@
public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
+ public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
public static final String EXTRA_MENU_STATE = "menu_state";
@@ -268,7 +269,8 @@
// If we haven't requested the start activity, or if it previously took too long to
// start, then start it
startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
- null /* movementBounds */, false /* allowMenuTimeout */);
+ null /* movementBounds */, false /* allowMenuTimeout */,
+ false /* resizeMenuOnShow */);
}
}
@@ -276,18 +278,20 @@
* Shows the menu activity.
*/
public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
- boolean allowMenuTimeout) {
+ boolean allowMenuTimeout, boolean willResizeMenu) {
if (DEBUG) {
Log.d(TAG, "showMenu() state=" + menuState
+ " hasActivity=" + (mToActivityMessenger != null)
+ " callers=\n" + Debug.getCallers(5, " "));
}
+
if (mToActivityMessenger != null) {
Bundle data = new Bundle();
data.putInt(EXTRA_MENU_STATE, menuState);
data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
data.putParcelable(EXTRA_MOVEMENT_BOUNDS, movementBounds);
data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
+ data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
m.obj = data;
@@ -299,7 +303,8 @@
} else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
// If we haven't requested the start activity, or if it previously took too long to
// start, then start it
- startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout);
+ startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout,
+ willResizeMenu);
}
}
@@ -372,7 +377,7 @@
* Starts the menu activity on the top task of the pinned stack.
*/
private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
- boolean allowMenuTimeout) {
+ boolean allowMenuTimeout, boolean willResizeMenu) {
try {
StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
@@ -388,6 +393,7 @@
}
intent.putExtra(EXTRA_MENU_STATE, menuState);
intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
+ intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
options.setLaunchTaskId(
pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 8ddd888..3181481 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -170,7 +170,7 @@
@Override
public void onPipShowMenu() {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */);
+ mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
}
}
@@ -214,7 +214,7 @@
// Only show the menu if the user isn't currently interacting with the PiP
if (!mTouchState.isUserInteracting()) {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, false /* allowMenuTimeout */);
+ mMovementBounds, false /* allowMenuTimeout */, willResizeMenu());
}
}
@@ -236,7 +236,7 @@
if (mShowPipMenuOnAnimationEnd) {
mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */);
+ mMovementBounds, true /* allowMenuTimeout */, false /* willResizeMenu */);
mShowPipMenuOnAnimationEnd = false;
}
}
@@ -337,7 +337,7 @@
private void onAccessibilityShowMenu() {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, false /* allowMenuTimeout */);
+ mMovementBounds, false /* allowMenuTimeout */, willResizeMenu());
}
private boolean handleTouchEvent(MotionEvent ev) {
@@ -704,7 +704,7 @@
// If the menu is still visible, and we aren't minimized, then just poke the
// menu so that it will timeout after the user stops touching it
mMenuController.showMenu(mMenuState, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */);
+ mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
} else {
// If the menu is not visible, then we can still be showing the activity for the
// dismiss overlay, so just finish it after the animation completes
@@ -731,7 +731,7 @@
setMinimizedStateInternal(false);
} else if (mMenuState != MENU_STATE_FULL) {
mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
- mMovementBounds, true /* allowMenuTimeout */);
+ mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
} else {
mMenuController.hideMenu();
mMotionHelper.expandPip();
@@ -773,6 +773,14 @@
cleanUpDismissTarget();
}
+ /**
+ * @return whether the menu will resize as a part of showing the full menu.
+ */
+ private boolean willResizeMenu() {
+ return mExpandedBounds.width() != mNormalBounds.width() ||
+ mExpandedBounds.height() != mNormalBounds.height();
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index f663315..82c0128 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -136,11 +136,12 @@
return disableAny;
}
- public void disableAll() {
+ public boolean disableAll() {
ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
for (int i = 0; i < plugins.size(); i++) {
disable(plugins.get(i));
}
+ return plugins.size() != 0;
}
private void disable(PluginInfo info) {
@@ -182,6 +183,7 @@
if (DEBUG) Log.d(TAG, "onPluginConnected");
PluginPrefs.setHasPlugins(mContext);
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
+ mManager.handleWtfs();
if (!(msg.obj instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onCreate as part of the fragment lifecycle.
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 493d244..03747d5 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -36,6 +36,9 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
+import android.util.Log.TerribleFailure;
+import android.util.Log.TerribleFailureHandler;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,10 +74,11 @@
private boolean mListening;
private boolean mHasOneShot;
private Looper mLooper;
+ private boolean mWtfsSet;
public PluginManagerImpl(Context context) {
this(context, new PluginInstanceManagerFactory(),
- Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler());
+ Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler());
}
@VisibleForTesting
@@ -88,7 +92,7 @@
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
defaultHandler);
- Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
+ Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
if (isDebuggable) {
new Handler(mLooper).post(() -> {
// Plugin dependencies that don't have another good home can go here, but
@@ -290,6 +294,15 @@
return false;
}
+ public void handleWtfs() {
+ if (!mWtfsSet) {
+ mWtfsSet = true;
+ Log.setWtfHandler((tag, what, system) -> {
+ throw new CrashWhilePluginActiveException(what);
+ });
+ }
+ }
+
@VisibleForTesting
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
@@ -339,9 +352,12 @@
// disable all the plugins, so we can be sure that SysUI is running as
// best as possible.
for (PluginInstanceManager manager : mPluginMap.values()) {
- manager.disableAll();
+ disabledAny |= manager.disableAll();
}
}
+ if (disabledAny) {
+ throwable = new CrashWhilePluginActiveException(throwable);
+ }
// Run the normal exception handler so we can crash and cleanup our state.
mHandler.uncaughtException(thread, throwable);
@@ -358,4 +374,10 @@
return disabledAny | checkStack(throwable.getCause());
}
}
+
+ private class CrashWhilePluginActiveException extends RuntimeException {
+ public CrashWhilePluginActiveException(Throwable throwable) {
+ super(throwable);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index c2a7ed3..aecf95f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -132,6 +132,11 @@
// Preloads the next task
RecentsConfiguration config = Recents.getConfiguration();
if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+ Rect windowRect = getWindowRect(null /* windowRectOverride */);
+ if (windowRect.isEmpty()) {
+ return;
+ }
+
// Load the next task only if we aren't svelte
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
@@ -146,8 +151,7 @@
// This callback is made when a new activity is launched and the old one is
// paused so ignore the current activity and try and preload the thumbnail for
// the previous one.
- updateDummyStackViewLayout(mBackgroundLayoutAlgorithm, stack,
- getWindowRect(null /* windowRectOverride */));
+ updateDummyStackViewLayout(mBackgroundLayoutAlgorithm, stack, windowRect);
// Launched from app is always the worst case (in terms of how many
// thumbnails/tasks visible)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 46f9c04..afe5c91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -404,8 +404,8 @@
false /* collapseWhenFinished */);
notifyBarPanelExpansionChanged();
if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) {
- AsyncTask.execute(
- () -> mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK)));
+ AsyncTask.execute(() ->
+ mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 03f42a6..d7f11f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -422,7 +422,7 @@
mFloatingActionMode.finish();
}
cleanupFloatingActionModeViews();
- mFloatingToolbar = new FloatingToolbar(mContext, mFakeWindow);
+ mFloatingToolbar = new FloatingToolbar(mFakeWindow);
final FloatingActionMode mode =
new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
mFloatingActionModeOriginatingView = originatingView;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 5e71dd4..27c16d5 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -54,7 +54,8 @@
SystemUI-proto \
SystemUI-tags \
legacy-android-test \
- testables
+ testables \
+ truth-prebuilt \
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
new file mode 100644
index 0000000..abc2d0e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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.doze;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.format.DateUtils;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AlwaysOnDisplayPolicyTest extends SysuiTestCase {
+ private static final String ALWAYS_ON_DISPLAY_CONSTANTS_VALUE = "prox_screen_off_delay=1000"
+ + ",prox_cooldown_trigger=2000"
+ + ",prox_cooldown_period=3000"
+ + ",screen_brightness_array=1:2:3:4:5"
+ + ",dimming_scrim_array=5:4:3:2:1";
+
+ private String mPreviousConfig;
+
+ @Before
+ public void setUp() {
+ mPreviousConfig = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
+ }
+
+ @After
+ public void tearDown() {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, mPreviousConfig);
+ }
+
+ @Test
+ public void testPolicy_valueNull_containsDefaultValue() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, null);
+
+ AlwaysOnDisplayPolicy policy = new AlwaysOnDisplayPolicy(mContext);
+
+ assertThat(policy.proxScreenOffDelayMs).isEqualTo(10 * DateUtils.MINUTE_IN_MILLIS);
+ assertThat(policy.proxCooldownTriggerMs).isEqualTo(2 * DateUtils.MINUTE_IN_MILLIS);
+ assertThat(policy.proxCooldownPeriodMs).isEqualTo(5 * DateUtils.MINUTE_IN_MILLIS);
+ assertThat(policy.screenBrightnessArray).isEqualTo(mContext.getResources().getIntArray(
+ R.array.config_doze_brightness_sensor_to_brightness));
+ assertThat(policy.dimmingScrimArray).isEqualTo(mContext.getResources().getIntArray(
+ R.array.config_doze_brightness_sensor_to_scrim_opacity));
+ }
+
+ @Test
+ public void testPolicy_valueNotNull_containsValue() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, ALWAYS_ON_DISPLAY_CONSTANTS_VALUE);
+
+ AlwaysOnDisplayPolicy policy = new AlwaysOnDisplayPolicy(mContext);
+
+ assertThat(policy.proxScreenOffDelayMs).isEqualTo(1000);
+ assertThat(policy.proxCooldownTriggerMs).isEqualTo(2000);
+ assertThat(policy.proxCooldownPeriodMs).isEqualTo(3000);
+ assertThat(policy.screenBrightnessArray).isEqualTo(new int[]{1, 2, 3, 4, 5});
+ assertThat(policy.dimmingScrimArray).isEqualTo(new int[]{5, 4, 3, 2, 1});
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index c275806..46e1d55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -60,7 +60,8 @@
mSensorManager = new FakeSensorManager(mContext);
mSensor = mSensorManager.getFakeLightSensor();
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- mSensor.getSensor(), mHostFake, null /* handler */);
+ mSensor.getSensor(), mHostFake, null /* handler */,
+ new AlwaysOnDisplayPolicy(mContext));
}
@Test
@@ -135,7 +136,8 @@
@Test
public void testNullSensor() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- null /* sensor */, mHostFake, null /* handler */);
+ null /* sensor */, mHostFake, null /* handler */,
+ new AlwaysOnDisplayPolicy(mContext));
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index b8e9fcd..94dbc2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -67,7 +67,7 @@
public void setup() throws Exception {
mDependency.injectTestDependency(Dependency.BG_LOOPER,
TestableLooper.get(this).getLooper());
- mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+ mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler();
mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
mMockFactory = mock(PluginInstanceManagerFactory.class);
mMockPluginInstance = mock(PluginInstanceManager.class);
@@ -167,9 +167,9 @@
}
private void resetExceptionHandler() {
- mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+ mPluginExceptionHandler = Thread.getUncaughtExceptionPreHandler();
// Set back the real exception handler so the test can crash if it wants to.
- Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler);
+ Thread.setUncaughtExceptionPreHandler(mRealExceptionHandler);
}
@ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index c4dc506..28bf856 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -312,6 +312,9 @@
// Counts the number of AllSingleScanLister.onResult calls with a partial (channels) scan result
optional int32 partial_all_single_scan_listener_results = 75;
+
+ // Pno scan metrics
+ optional PnoScanMetrics pno_scan_metrics = 76;
}
// Information that gets logged for every WiFi connection.
@@ -927,3 +930,23 @@
// Number of scan results with num_connectable_networks
optional int32 count = 2 [default = 0];
}
+
+// Pno scan metrics
+// Here "Pno Scan" refers to the session of offloaded scans, these metrics count the result of a
+// single session, and not the individual scans within that session.
+message PnoScanMetrics {
+ // Total number of attempts to offload pno scans
+ optional int32 num_pno_scan_attempts = 1;
+
+ // Total number of pno scans failed
+ optional int32 num_pno_scan_failed = 2;
+
+ // Number of pno scans started successfully over offload
+ optional int32 num_pno_scan_started_over_offload = 3;
+
+ // Number of pno scans failed over offload
+ optional int32 num_pno_scan_failed_over_offload = 4;
+
+ // Total number of pno scans that found any network
+ optional int32 num_pno_found_network_events = 5;
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a97e16b..83dfccb 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2397,6 +2397,7 @@
public static final int MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS = 12;
public static final int MSG_SEND_ACCESSIBILITY_BUTTON_TO_INPUT_FILTER = 13;
public static final int MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER = 14;
+ public static final int MSG_INIT_SERVICE = 15;
public MainHandler(Looper looper) {
super(looper);
@@ -2495,6 +2496,11 @@
case MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER: {
showAccessibilityButtonTargetSelection();
} break;
+
+ case MSG_INIT_SERVICE: {
+ final Service service = (Service) msg.obj;
+ service.initializeService();
+ } break;
}
}
@@ -2950,20 +2956,31 @@
if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) {
userState.mBindingServices.remove(mComponentName);
mWasConnectedAndDied = false;
- try {
- mServiceInterface.init(this, mId, mOverlayWindowToken);
- onUserStateChangedLocked(userState);
- } catch (RemoteException re) {
- Slog.w(LOG_TAG, "Error while setting connection for service: "
- + service, re);
- binderDied();
- }
+ onUserStateChangedLocked(userState);
+ // Initialize the service on the main handler after we're done setting up for
+ // the new configuration (for example, initializing the input filter).
+ mMainHandler.obtainMessage(MainHandler.MSG_INIT_SERVICE, this).sendToTarget();
} else {
binderDied();
}
}
}
+ private void initializeService() {
+ final IAccessibilityServiceClient serviceInterface;
+ synchronized (mLock) {
+ serviceInterface = mServiceInterface;
+ }
+ if (serviceInterface == null) return;
+ try {
+ serviceInterface.init(this, mId, mOverlayWindowToken);
+ } catch (RemoteException re) {
+ Slog.w(LOG_TAG, "Error while setting connection for service: "
+ + serviceInterface, re);
+ binderDied();
+ }
+ }
+
private boolean isCalledForCurrentUserLocked() {
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
@@ -3313,8 +3330,8 @@
}
if (mMotionEventInjector != null) {
List<GestureDescription.GestureStep> steps = gestureSteps.getList();
- mMotionEventInjector.injectEvents(steps, mServiceInterface, sequence);
- return;
+ mMotionEventInjector.injectEvents(steps, mServiceInterface, sequence);
+ return;
} else {
Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
}
@@ -3456,18 +3473,15 @@
return region;
}
MagnificationController magnificationController = getMagnificationController();
- boolean forceRegistration = mSecurityPolicy.canControlMagnification(this);
- boolean initiallyRegistered = magnificationController.isRegisteredLocked();
- if (!initiallyRegistered && forceRegistration) {
- magnificationController.register();
- }
+ boolean registeredJustForThisCall =
+ registerMagnificationIfNeeded(magnificationController);
final long identity = Binder.clearCallingIdentity();
try {
magnificationController.getMagnificationRegion(region);
return region;
} finally {
Binder.restoreCallingIdentity(identity);
- if (!initiallyRegistered && forceRegistration) {
+ if (registeredJustForThisCall) {
magnificationController.unregister();
}
}
@@ -3481,11 +3495,17 @@
return 0.0f;
}
}
+ MagnificationController magnificationController = getMagnificationController();
+ boolean registeredJustForThisCall =
+ registerMagnificationIfNeeded(magnificationController);
final long identity = Binder.clearCallingIdentity();
try {
- return getMagnificationController().getCenterX();
+ return magnificationController.getCenterX();
} finally {
Binder.restoreCallingIdentity(identity);
+ if (registeredJustForThisCall) {
+ magnificationController.unregister();
+ }
}
}
@@ -3496,14 +3516,30 @@
return 0.0f;
}
}
+ MagnificationController magnificationController = getMagnificationController();
+ boolean registeredJustForThisCall =
+ registerMagnificationIfNeeded(magnificationController);
final long identity = Binder.clearCallingIdentity();
try {
- return getMagnificationController().getCenterY();
+ return magnificationController.getCenterY();
} finally {
Binder.restoreCallingIdentity(identity);
+ if (registeredJustForThisCall) {
+ magnificationController.unregister();
+ }
}
}
+ private boolean registerMagnificationIfNeeded(
+ MagnificationController magnificationController) {
+ if (!magnificationController.isRegisteredLocked()
+ && mSecurityPolicy.canControlMagnification(this)) {
+ magnificationController.register();
+ return true;
+ }
+ return false;
+ }
+
@Override
public boolean resetMagnification(boolean animate) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 17292b4..adf536b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2011,7 +2011,16 @@
break;
}
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
- handleUpdateLinkProperties(nai, (LinkProperties) msg.obj);
+ if (VDBG) {
+ log("Update of LinkProperties for " + nai.name() +
+ "; created=" + nai.created +
+ "; everConnected=" + nai.everConnected);
+ }
+ LinkProperties oldLp = nai.linkProperties;
+ synchronized (nai) {
+ nai.linkProperties = (LinkProperties)msg.obj;
+ }
+ if (nai.everConnected) updateLinkProperties(nai, oldLp);
break;
}
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
@@ -2260,7 +2269,7 @@
}
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
mNetworkAgentInfos.remove(msg.replyTo);
- nai.maybeStopClat();
+ maybeStopClat(nai);
synchronized (mNetworkForNetId) {
// Remove the NetworkAgent, but don't mark the netId as
// available until we've told netd to delete it below.
@@ -4374,7 +4383,7 @@
updateDnses(newLp, oldLp, netId);
// Start or stop clat accordingly to network state.
- networkAgent.updateClat(mNetd);
+ updateClat(networkAgent);
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
@@ -4389,6 +4398,32 @@
mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
}
+ private void updateClat(NetworkAgentInfo nai) {
+ if (Nat464Xlat.requiresClat(nai)) {
+ maybeStartClat(nai);
+ } else {
+ maybeStopClat(nai);
+ }
+ }
+
+ /** Ensure clat has started for this network. */
+ private void maybeStartClat(NetworkAgentInfo nai) {
+ if (nai.clatd != null && nai.clatd.isStarted()) {
+ return;
+ }
+ nai.clatd = new Nat464Xlat(mNetd, mTrackerHandler, nai);
+ nai.clatd.start();
+ }
+
+ /** Ensure clat has stopped for this network. */
+ private void maybeStopClat(NetworkAgentInfo nai) {
+ if (nai.clatd == null) {
+ return;
+ }
+ nai.clatd.stop();
+ nai.clatd = null;
+ }
+
private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
// Marks are only available on WiFi interaces. Checking for
// marks on unsupported interfaces is harmless.
@@ -4623,21 +4658,6 @@
}
}
- public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
- if (VDBG) {
- log("Update of LinkProperties for " + nai.name() +
- "; created=" + nai.created +
- "; everConnected=" + nai.everConnected);
- }
- LinkProperties oldLp = nai.linkProperties;
- synchronized (nai) {
- nai.linkProperties = newLp;
- }
- if (nai.everConnected) {
- updateLinkProperties(nai, oldLp);
- }
- }
-
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 4733840..046eb76 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -728,6 +728,9 @@
return timeout;
}
}
+ if (!prebaked.shouldFallback()) {
+ return 0;
+ }
final int id = prebaked.getId();
if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Slog.w(TAG, "Failed to play prebaked effect, no fallback");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index aca1584..810a6bf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -466,7 +466,6 @@
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
- private static final String TAG_LOCKSCREEN = TAG + POSTFIX_LOCKSCREEN;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_LRU = TAG + POSTFIX_LRU;
private static final String TAG_MU = TAG + POSTFIX_MU;
@@ -484,7 +483,6 @@
private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
- private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
// Mock "pretend we're idle now" broadcast action to the job scheduler; declared
// here so that while the job scheduler can depend on AMS, the other way around
@@ -1562,6 +1560,13 @@
final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>();
final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>();
+ OomAdjObserver mCurOomAdjObserver;
+ int mCurOomAdjUid;
+
+ interface OomAdjObserver {
+ void onOomAdjMessage(String msg);
+ }
+
/**
* Runtime CPU use collection thread. This object's lock is used to
* perform synchronization with the thread (notifying it to run).
@@ -1683,6 +1688,7 @@
static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
+ static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
static final int START_USER_SWITCH_FG_MSG = 712;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1918,6 +1924,9 @@
case DISPATCH_UIDS_CHANGED_UI_MSG: {
dispatchUidsChanged();
} break;
+ case DISPATCH_OOM_ADJ_OBSERVER_MSG: {
+ dispatchOomAdjObserver((String)msg.obj);
+ } break;
case PUSH_TEMP_WHITELIST_UI_MSG: {
pushTempWhitelist();
} break;
@@ -4456,6 +4465,38 @@
}
}
+ void dispatchOomAdjObserver(String msg) {
+ OomAdjObserver observer;
+ synchronized (this) {
+ observer = mCurOomAdjObserver;
+ }
+
+ if (observer != null) {
+ observer.onOomAdjMessage(msg);
+ }
+ }
+
+ void setOomAdjObserver(int uid, OomAdjObserver observer) {
+ synchronized (this) {
+ mCurOomAdjUid = uid;
+ mCurOomAdjObserver = observer;
+ }
+ }
+
+ void clearOomAdjObserver() {
+ synchronized (this) {
+ mCurOomAdjUid = -1;
+ mCurOomAdjObserver = null;
+ }
+ }
+
+ void reportOomAdjMessageLocked(String tag, String msg) {
+ Slog.d(tag, msg);
+ if (mCurOomAdjObserver != null) {
+ mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
+ }
+ }
+
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
@@ -21946,9 +21987,11 @@
if (app.curAdj != app.setAdj) {
ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
- + app.adjType);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.info.uid) {
+ String msg = "Set " + app.pid + " " + app.processName + " adj "
+ + app.curAdj + ": " + app.adjType;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+ }
app.setAdj = app.curAdj;
app.verifiedAdj = ProcessList.INVALID_ADJ;
}
@@ -21956,9 +21999,11 @@
if (app.setSchedGroup != app.curSchedGroup) {
int oldSchedGroup = app.setSchedGroup;
app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Setting sched group of " + app.processName
- + " to " + app.curSchedGroup);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
+ String msg = "Setting sched group of " + app.processName
+ + " to " + app.curSchedGroup;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+ }
if (app.waitingToKill != null && app.curReceivers.isEmpty()
&& app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
app.kill(app.waitingToKill, true);
@@ -22103,9 +22148,11 @@
"Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
if (app.setProcState != app.curProcState) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Proc state change of " + app.processName
- + " to " + app.curProcState);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
+ String msg = "Proc state change of " + app.processName
+ + " to " + app.curProcState;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+ }
boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
boolean curImportant = app.curProcState < ActivityManager.PROCESS_STATE_SERVICE;
if (setImportant && !curImportant) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 45357cb..8488e52 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -55,7 +55,6 @@
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.DisplayMetrics;
-import android.view.IWindowManager;
import com.android.internal.util.HexDump;
import com.android.internal.util.Preconditions;
@@ -1296,19 +1295,24 @@
return 0;
}
- static final class MyUidObserver extends IUidObserver.Stub {
+ static final class MyUidObserver extends IUidObserver.Stub
+ implements ActivityManagerService.OomAdjObserver {
final IActivityManager mInterface;
+ final ActivityManagerService mInternal;
final PrintWriter mPw;
final InputStream mInput;
+ final int mUid;
static final int STATE_NORMAL = 0;
int mState;
- MyUidObserver(IActivityManager iam, PrintWriter pw, InputStream input) {
- mInterface = iam;
+ MyUidObserver(ActivityManagerService service, PrintWriter pw, InputStream input, int uid) {
+ mInterface = service;
+ mInternal = service;
mPw = pw;
mInput = input;
+ mUid = uid;
}
@Override
@@ -1367,6 +1371,15 @@
}
}
+ @Override
+ public void onOomAdjMessage(String msg) {
+ synchronized (this) {
+ mPw.print("# ");
+ mPw.println(msg);
+ mPw.flush();
+ }
+ }
+
void printMessageForState() {
switch (mState) {
case STATE_NORMAL:
@@ -1385,6 +1398,9 @@
| ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_PROCSTATE
| ActivityManager.UID_OBSERVER_IDLE | ActivityManager.UID_OBSERVER_CACHED,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ if (mUid >= 0) {
+ mInternal.setOomAdjObserver(mUid, this);
+ }
mState = STATE_NORMAL;
InputStreamReader converter = new InputStreamReader(mInput);
@@ -1414,6 +1430,9 @@
e.printStackTrace(mPw);
mPw.flush();
} finally {
+ if (mUid >= 0) {
+ mInternal.clearOomAdjObserver();
+ }
mInterface.unregisterUidObserver(this);
}
}
@@ -1421,12 +1440,18 @@
int runWatchUids(PrintWriter pw) throws RemoteException {
String opt;
+ int uid = -1;
while ((opt=getNextOption()) != null) {
- getErrPrintWriter().println("Error: Unknown option: " + opt);
- return -1;
+ if (opt.equals("--oom")) {
+ uid = Integer.parseInt(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+
+ }
}
- MyUidObserver controller = new MyUidObserver(mInterface, pw, getRawInputStream());
+ MyUidObserver controller = new MyUidObserver(mInternal, pw, getRawInputStream(), uid);
controller.run();
return 0;
}
@@ -1858,8 +1883,12 @@
level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
break;
default:
- getErrPrintWriter().println("Error: Unknown level option: " + levelArg);
- return -1;
+ try {
+ level = Integer.parseInt(levelArg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: Unknown level option: " + levelArg);
+ return -1;
+ }
}
if (!mInterface.setProcessMemoryTrimLevel(proc, userId, level)) {
getErrPrintWriter().println("Unknown error: failed to set trim level");
@@ -2744,8 +2773,9 @@
pw.println(" monitor [--gdb <port>]");
pw.println(" Start monitoring for crashes or ANRs.");
pw.println(" --gdb: start gdbserv on the given port at crash/ANR");
- pw.println(" watch-uids [--gdb <port>]");
+ pw.println(" watch-uids [--oom <uid>");
pw.println(" Start watching for and reporting uid state changes.");
+ pw.println(" --oom: specify a uid for which to report detailed change messages.");
pw.println(" hang [--allow-restart]");
pw.println(" Hang the system.");
pw.println(" --allow-restart: allow watchdog to perform normal system restart");
@@ -2804,7 +2834,7 @@
pw.println(" Returns the inactive state of an app.");
pw.println(" send-trim-memory [--user <USER_ID>] <PROCESS>");
pw.println(" [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]");
- pw.println(" Send a memory trim event to a <PROCESS>.");
+ pw.println(" Send a memory trim event to a <PROCESS>. May also supply a raw trim int level.");
pw.println(" display [COMMAND] [...]: sub-commands for operating on displays.");
pw.println(" move-stack <STACK_ID> <DISPLAY_ID>");
pw.println(" Move <STACK_ID> from its current display to <DISPLAY_ID>.");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 871ccb9..5b27c9c 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -659,14 +659,14 @@
}
}
- void updatePictureInPictureMode(Rect targetStackBounds) {
+ void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) {
if (task == null || task.getStack() == null || app == null || app.thread == null) {
return;
}
final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) &&
(targetStackBounds != null);
- if (inPictureInPictureMode != mLastReportedPictureInPictureMode) {
+ if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
// Picture-in-picture mode changes also trigger a multi-window mode change as well, so
// update that here in order
mLastReportedPictureInPictureMode = inPictureInPictureMode;
@@ -681,8 +681,7 @@
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
app.thread.schedulePictureInPictureModeChanged(appToken,
- mLastReportedPictureInPictureMode,
- overrideConfig);
+ mLastReportedPictureInPictureMode, overrideConfig);
} catch (Exception e) {
// If process died, no one cares.
}
@@ -1592,7 +1591,12 @@
}
void notifyUnknownVisibilityLaunched() {
- mWindowContainerController.notifyUnknownVisibilityLaunched();
+
+ // No display activities never add a window, so there is no point in waiting them for
+ // relayout.
+ if (!noDisplay) {
+ mWindowContainerController.notifyUnknownVisibilityLaunched();
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d16ae185..7bbc6cc 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1336,6 +1336,10 @@
r.app = app;
+ if (mKeyguardController.isKeyguardLocked()) {
+ r.notifyUnknownVisibilityLaunched();
+ }
+
// Have the window manager re-evaluate the orientation of the screen based on the new
// activity order. Note that as a result of this, it can call back into the activity
// manager with a new orientation. We don't care about that, because the activity is
@@ -1362,9 +1366,6 @@
r.setVisibility(true);
}
- if (mKeyguardController.isKeyguardLocked()) {
- r.notifyUnknownVisibilityLaunched();
- }
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) {
@@ -4410,31 +4411,29 @@
return;
}
- scheduleUpdatePictureInPictureModeIfNeeded(task, stack.mBounds, false /* immediate */);
+ scheduleUpdatePictureInPictureModeIfNeeded(task, stack.mBounds);
}
- void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds,
- boolean immediate) {
-
- if (immediate) {
- mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
- for (int i = task.mActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
- r.updatePictureInPictureMode(targetStackBounds);
- }
+ void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
+ for (int i = task.mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = task.mActivities.get(i);
+ if (r.app != null && r.app.thread != null) {
+ mPipModeChangedActivities.add(r);
}
- } else {
- for (int i = task.mActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
- mPipModeChangedActivities.add(r);
- }
- }
- mPipModeChangedTargetStackBounds = targetStackBounds;
+ }
+ mPipModeChangedTargetStackBounds = targetStackBounds;
- if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
- mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
+ if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
+ mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
+ }
+ }
+
+ void updatePictureInPictureMode(TaskRecord task, Rect targetStackBounds, boolean forceUpdate) {
+ mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
+ for (int i = task.mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = task.mActivities.get(i);
+ if (r.app != null && r.app.thread != null) {
+ r.updatePictureInPictureMode(targetStackBounds, forceUpdate);
}
}
}
@@ -4496,7 +4495,8 @@
synchronized (mService) {
for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mPipModeChangedActivities.remove(i);
- r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds);
+ r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds,
+ false /* forceUpdate */);
}
}
} break;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 7c7eda7..d835454 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1445,20 +1445,19 @@
r.receiverTime = now;
r.anrCount++;
- // Current receiver has passed its expiration date.
- if (r.nextReceiver <= 0) {
- Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
- return;
- }
-
ProcessRecord app = null;
String anrMessage = null;
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
- Slog.w(TAG, "Receiver during timeout: " + curReceiver);
+ Object curReceiver;
+ if (r.nextReceiver > 0) {
+ curReceiver = r.receivers.get(r.nextReceiver-1);
+ r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
+ } else {
+ curReceiver = r.curReceiver;
+ }
+ Slog.w(TAG, "Receiver during timeout of " + r + " : " + curReceiver);
logBroadcastReceiverDiscardLocked(r);
- if (curReceiver instanceof BroadcastFilter) {
+ if (curReceiver != null && curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter)curReceiver;
if (bf.receiverList.pid != 0
&& bf.receiverList.pid != ActivityManagerService.MY_PID) {
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index 392fbb2..a601ee1 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -91,15 +91,16 @@
return mWindowContainerController.deferScheduleMultiWindowModeChanged();
}
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) {
+ public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {
// It is guaranteed that the activities requiring the update will be in the pinned stack at
// this point (either reparented before the animation into PiP, or before reparenting after
// the animation out of PiP)
synchronized(this) {
ArrayList<TaskRecord> tasks = getAllTasks();
for (int i = 0; i < tasks.size(); i++ ) {
- mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(tasks.get(i),
- targetStackBounds, true /* immediate */);
+ mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+ forceUpdate);
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index faf4729..91b1591 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -801,12 +801,23 @@
public void systemReady() {
sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
0, 0, null, 0);
- try {
- ActivityManager.getService().registerUidObserver(mUidObserver,
- ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
- ActivityManager.PROCESS_STATE_UNKNOWN, null);
- } catch (RemoteException e) {
- // ignored; both services live in system_server
+ if (false) {
+ // This is turned off for now, because it is racy and thus causes apps to break.
+ // Currently banning a uid means that if an app tries to start playing an audio
+ // stream, that will be preventing, and unbanning it will not allow that stream
+ // to resume. However these changes in uid state are racy with what the app is doing,
+ // so that after taking a process out of the cached state we can't guarantee that
+ // we will unban the uid before the app actually tries to start playing audio.
+ // (To do that, the activity manager would need to wait until it knows for sure
+ // that the ban has been removed, before telling the app to do whatever it is
+ // supposed to do that caused it to go out of the cached state.)
+ try {
+ ActivityManager.getService().registerUidObserver(mUidObserver,
+ ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ } catch (RemoteException e) {
+ // ignored; both services live in system_server
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 10c8b8b..f8d23d4 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -20,21 +20,22 @@
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkAgent;
import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.Message;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.util.Slog;
-import com.android.internal.util.ArrayUtils;
import com.android.server.net.BaseNetworkObserver;
+import com.android.internal.util.ArrayUtils;
import java.net.Inet4Address;
import java.util.Objects;
/**
- * Class to manage a 464xlat CLAT daemon. Nat464Xlat is not thread safe and should be manipulated
- * from a consistent and unique thread context. It is the responsability of ConnectivityService to
- * call into this class from its own Handler thread.
+ * Class to manage a 464xlat CLAT daemon.
*
* @hide
*/
@@ -54,6 +55,9 @@
private final INetworkManagementService mNMService;
+ // ConnectivityService Handler for LinkProperties updates.
+ private final Handler mHandler;
+
// The network we're running on, and its type.
private final NetworkAgentInfo mNetwork;
@@ -63,12 +67,16 @@
RUNNING; // start() called, and the stacked iface is known to be up.
}
+ // Once mIface is non-null and isStarted() is true, methods called by ConnectivityService on
+ // its handler thread must not modify any internal state variables; they are only updated by the
+ // interface observers, called on the notification threads.
private String mBaseIface;
private String mIface;
- private State mState = State.IDLE;
+ private volatile State mState = State.IDLE;
- public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
+ public Nat464Xlat(INetworkManagementService nmService, Handler handler, NetworkAgentInfo nai) {
mNMService = nmService;
+ mHandler = handler;
mNetwork = nai;
}
@@ -97,13 +105,6 @@
}
/**
- * @return true if clatd has been started but the stacked interface is not yet up.
- */
- public boolean isStarting() {
- return mState == State.STARTING;
- }
-
- /**
* @return true if clatd has been started and the stacked interface is up.
*/
public boolean isRunning() {
@@ -120,7 +121,7 @@
}
/**
- * Clears internal state.
+ * Clears internal state. Must not be called by ConnectivityService.
*/
private void enterIdleState() {
mIface = null;
@@ -129,7 +130,7 @@
}
/**
- * Starts the clat daemon.
+ * Starts the clat daemon. Called by ConnectivityService on the handler thread.
*/
public void start() {
if (isStarted()) {
@@ -166,7 +167,7 @@
}
/**
- * Stops the clat daemon.
+ * Stops the clat daemon. Called by ConnectivityService on the handler thread.
*/
public void stop() {
if (!isStarted()) {
@@ -180,8 +181,15 @@
} catch(RemoteException|IllegalStateException e) {
Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
}
- // When clatd stops and its interface is deleted, handleInterfaceRemoved() will trigger
- // ConnectivityService#handleUpdateLinkProperties and call enterIdleState().
+ // When clatd stops and its interface is deleted, interfaceRemoved() will notify
+ // ConnectivityService and call enterIdleState().
+ }
+
+ private void updateConnectivityService(LinkProperties lp) {
+ Message msg = mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, lp);
+ msg.replyTo = mNetwork.messenger;
+ Slog.i(TAG, "sending message to ConnectivityService: " + msg);
+ msg.sendToTarget();
}
/**
@@ -249,15 +257,19 @@
}
/**
- * Adds stacked link on base link and transitions to RUNNING state.
+ * Adds stacked link on base link and transitions to Running state
+ * This is called by the InterfaceObserver on its own thread, so can race with stop().
*/
- private void handleInterfaceLinkStateChanged(String iface, boolean up) {
- if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
+ @Override
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ if (!isStarted() || !up || !Objects.equals(mIface, iface)) {
+ return;
+ }
+ if (isRunning()) {
return;
}
LinkAddress clatAddress = getLinkAddress(iface);
if (clatAddress == null) {
- Slog.e(TAG, "cladAddress was null for stacked iface " + iface);
return;
}
mState = State.RUNNING;
@@ -267,14 +279,15 @@
maybeSetIpv6NdOffload(mBaseIface, false);
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
lp.addStackedLink(makeLinkProperties(clatAddress));
- mNetwork.connService.handleUpdateLinkProperties(mNetwork, lp);
+ updateConnectivityService(lp);
}
- /**
- * Removes stacked link on base link and transitions to IDLE state.
- */
- private void handleInterfaceRemoved(String iface) {
- if (!isRunning() || !Objects.equals(mIface, iface)) {
+ @Override
+ public void interfaceRemoved(String iface) {
+ if (!isStarted() || !Objects.equals(mIface, iface)) {
+ return;
+ }
+ if (!isRunning()) {
return;
}
@@ -282,28 +295,21 @@
// The interface going away likely means clatd has crashed. Ask netd to stop it,
// because otherwise when we try to start it again on the same base interface netd
// will complain that it's already started.
+ //
+ // Note that this method can be called by the interface observer at the same time
+ // that ConnectivityService calls stop(). In this case, the second call to
+ // stopClatd() will just throw IllegalStateException, which we'll ignore.
try {
mNMService.unregisterObserver(this);
- // TODO: add STOPPING state to avoid calling stopClatd twice.
mNMService.stopClatd(mBaseIface);
- } catch(RemoteException|IllegalStateException e) {
- Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
+ } catch (RemoteException|IllegalStateException e) {
+ // Well, we tried.
}
maybeSetIpv6NdOffload(mBaseIface, true);
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
lp.removeStackedLink(mIface);
enterIdleState();
- mNetwork.connService.handleUpdateLinkProperties(mNetwork, lp);
- }
-
- @Override
- public void interfaceLinkStateChanged(String iface, boolean up) {
- mNetwork.handler.post(() -> { handleInterfaceLinkStateChanged(iface, up); });
- }
-
- @Override
- public void interfaceRemoved(String iface) {
- mNetwork.handler.post(() -> { handleInterfaceRemoved(iface); });
+ updateConnectivityService(lp);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 7c4ef0f..872923a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -27,9 +27,7 @@
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.os.Handler;
-import android.os.INetworkManagementService;
import android.os.Messenger;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -249,9 +247,9 @@
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final boolean VDBG = false;
- public final ConnectivityService connService;
+ private final ConnectivityService mConnService;
private final Context mContext;
- final Handler handler;
+ private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
@@ -263,10 +261,10 @@
linkProperties = lp;
networkCapabilities = nc;
currentScore = score;
- this.connService = connService;
+ mConnService = connService;
mContext = context;
- this.handler = handler;
- networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
+ mHandler = handler;
+ networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
networkMisc = misc;
}
@@ -432,7 +430,7 @@
private boolean ignoreWifiUnvalidationPenalty() {
boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- boolean avoidBadWifi = connService.avoidBadWifi() || avoidUnvalidated;
+ boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
return isWifi && !avoidBadWifi && everValidated;
}
@@ -516,8 +514,8 @@
}
if (newExpiry > 0) {
- mLingerMessage = connService.makeWakeupMessage(
- mContext, handler,
+ mLingerMessage = mConnService.makeWakeupMessage(
+ mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.netId,
EVENT_NETWORK_LINGER_COMPLETE, this);
mLingerMessage.schedule(newExpiry);
@@ -553,32 +551,6 @@
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
}
- public void updateClat(INetworkManagementService netd) {
- if (Nat464Xlat.requiresClat(this)) {
- maybeStartClat(netd);
- } else {
- maybeStopClat();
- }
- }
-
- /** Ensure clat has started for this network. */
- public void maybeStartClat(INetworkManagementService netd) {
- if (clatd != null && clatd.isStarted()) {
- return;
- }
- clatd = new Nat464Xlat(netd, this);
- clatd.start();
- }
-
- /** Ensure clat has stopped for this network. */
- public void maybeStopClat() {
- if (clatd == null) {
- return;
- }
- clatd.stop();
- clatd = null;
- }
-
public String toString() {
return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
"network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 3fc76c0..4dab32c 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -501,11 +501,12 @@
if (DEBUG) {
Slog.d(TAG, "Receieved: " + action);
}
+ final String pkgName = getPackageName(intent);
+ final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
// Purge the app's jobs if the whole package was just disabled. When this is
// the case the component name will be a bare package name.
- final String pkgName = getPackageName(intent);
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
if (pkgName != null && pkgUid != -1) {
final String[] changedComponents = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
@@ -525,7 +526,8 @@
Slog.d(TAG, "Removing jobs for package " + pkgName
+ " in user " + userId);
}
- cancelJobsForUid(pkgUid, "app package state changed");
+ cancelJobsForPackageAndUid(pkgName, pkgUid,
+ "app disabled");
}
} catch (RemoteException|IllegalArgumentException e) {
/*
@@ -554,7 +556,7 @@
if (DEBUG) {
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
}
- cancelJobsForUid(uidRemoved, "app uninstalled");
+ cancelJobsForPackageAndUid(pkgName, uidRemoved, "app uninstalled");
}
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -565,8 +567,6 @@
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final String pkgName = intent.getData().getSchemeSpecificPart();
if (pkgUid != -1) {
List<JobStatus> jobsForUid;
synchronized (mLock) {
@@ -585,13 +585,11 @@
}
} else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
// possible force-stop
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final String pkgName = intent.getData().getSchemeSpecificPart();
if (pkgUid != -1) {
if (DEBUG) {
Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid);
}
- cancelJobsForPackageAndUid(pkgName, pkgUid);
+ cancelJobsForPackageAndUid(pkgName, pkgUid, "app force stopped");
}
}
}
@@ -762,13 +760,17 @@
}
}
- void cancelJobsForPackageAndUid(String pkgName, int uid) {
+ void cancelJobsForPackageAndUid(String pkgName, int uid, String reason) {
+ if ("android".equals(pkgName)) {
+ Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
+ return;
+ }
synchronized (mLock) {
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
final JobStatus job = jobsForUid.get(i);
if (job.getSourcePackageName().equals(pkgName)) {
- cancelJobImplLocked(job, null, "app force stopped");
+ cancelJobImplLocked(job, null, reason);
}
}
}
@@ -783,8 +785,7 @@
*/
public void cancelJobsForUid(int uid, String reason) {
if (uid == Process.SYSTEM_UID) {
- // This really shouldn't happen.
- Slog.wtfStack(TAG, "cancelJobsForUid() called for system uid");
+ Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
return;
}
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 031bdd0..d3fd3a9 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -261,6 +261,13 @@
return mRunningJob;
}
+ /**
+ * Used only for debugging. Will return <code>"<null>"</code> if there is no job running.
+ */
+ private String getRunningJobNameLocked() {
+ return mRunningJob != null ? mRunningJob.toShortString() : "<null>";
+ }
+
/** Called externally when a job that was scheduled for execution should be cancelled. */
void cancelExecutingJobLocked(int reason, String debugReason) {
doCancelLocked(reason, debugReason);
@@ -522,7 +529,7 @@
/** Start the job on the service. */
private void handleServiceBoundLocked() {
if (DEBUG) {
- Slog.d(TAG, "handleServiceBound for " + mRunningJob.toShortString());
+ Slog.d(TAG, "handleServiceBound for " + getRunningJobNameLocked());
}
if (mVerb != VERB_BINDING) {
Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
@@ -639,36 +646,34 @@
private void handleOpTimeoutLocked() {
switch (mVerb) {
case VERB_BINDING:
- Slog.w(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
- ", dropping.");
+ Slog.w(TAG, "Time-out while trying to bind " + getRunningJobNameLocked()
+ + ", dropping.");
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding");
break;
case VERB_STARTING:
// Client unresponsive - wedged or failed to respond in time. We don't really
// know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
- Slog.w(TAG, "No response from client for onStartJob " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>");
+ Slog.w(TAG, "No response from client for onStartJob "
+ + getRunningJobNameLocked());
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");
break;
case VERB_STOPPING:
// At least we got somewhere, so fail but ask the JobScheduler to reschedule.
- Slog.w(TAG, "No response from client for onStopJob " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>");
+ Slog.w(TAG, "No response from client for onStopJob "
+ + getRunningJobNameLocked());
closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping");
break;
case VERB_EXECUTING:
// Not an error - client ran out of time.
Slog.i(TAG, "Client timed out while executing (no jobFinished received), " +
- "sending onStop: " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>");
+ "sending onStop: " + getRunningJobNameLocked());
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
sendStopMessageLocked("timeout while executing");
break;
default:
- Slog.e(TAG, "Handling timeout for an invalid job state: " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>"
- + ", dropping.");
+ Slog.e(TAG, "Handling timeout for an invalid job state: "
+ + getRunningJobNameLocked() + ", dropping.");
closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 922df1e..3795b7f 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -18,9 +18,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.Watchdog;
-import com.android.server.media.AudioPlaybackMonitor.OnAudioPlayerActiveStateChangedListener;
-import android.Manifest;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -96,9 +94,10 @@
private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
new ArrayMap<IBinder, ClientRecord>();
private int mCurrentUserId = -1;
- private boolean mHasBluetoothRoute = false;
+ private boolean mGlobalBluetoothA2dpOn = false;
private final IAudioService mAudioService;
private final AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
public MediaRouterService(Context context) {
mContext = context;
@@ -137,13 +136,39 @@
audioRoutes = mAudioService.startWatchingRoutes(new IAudioRoutesObserver.Stub() {
@Override
public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
- mHasBluetoothRoute = newRoutes.bluetoothName != null;
+ synchronized (mLock) {
+ if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
+ if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET
+ | AudioRoutesInfo.MAIN_HEADPHONES
+ | AudioRoutesInfo.MAIN_USB)) == 0) {
+ // headset was plugged out.
+ mGlobalBluetoothA2dpOn = newRoutes.bluetoothName != null;
+ } else {
+ // headset was plugged in.
+ mGlobalBluetoothA2dpOn = false;
+ }
+ mCurAudioRoutesInfo.mainType = newRoutes.mainType;
+ }
+ if (!TextUtils.equals(
+ newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+ if (newRoutes.bluetoothName == null) {
+ // BT was disconnected.
+ mGlobalBluetoothA2dpOn = false;
+ } else {
+ // BT was connected or changed.
+ mGlobalBluetoothA2dpOn = true;
+ }
+ mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
+ }
+ }
}
});
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in the audio service.");
}
- mHasBluetoothRoute = (audioRoutes != null && audioRoutes.bluetoothName != null);
+ synchronized (mLock) {
+ mGlobalBluetoothA2dpOn = (audioRoutes != null && audioRoutes.bluetoothName != null);
+ }
}
public void systemRunning() {
@@ -246,6 +271,14 @@
// Binder call
@Override
+ public boolean isGlobalBluetoothA2doOn() {
+ synchronized (mLock) {
+ return mGlobalBluetoothA2dpOn;
+ }
+ }
+
+ // Binder call
+ @Override
public void setDiscoveryRequest(IMediaRouterClient client,
int routeTypes, boolean activeScan) {
if (client == null) {
@@ -346,7 +379,12 @@
void restoreBluetoothA2dp() {
try {
- mAudioService.setBluetoothA2dpOn(mHasBluetoothRoute);
+ boolean a2dpOn = false;
+ synchronized (mLock) {
+ a2dpOn = mGlobalBluetoothA2dpOn;
+ }
+ Slog.v(TAG, "restoreBluetoothA2dp( " + a2dpOn + ")");
+ mAudioService.setBluetoothA2dpOn(a2dpOn);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn.");
}
@@ -354,12 +392,14 @@
void restoreRoute(int uid) {
ClientRecord clientRecord = null;
- UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid));
- if (userRecord != null && userRecord.mClientRecords != null) {
- for (ClientRecord cr : userRecord.mClientRecords) {
- if (validatePackageName(uid, cr.mPackageName)) {
- clientRecord = cr;
- break;
+ synchronized (mLock) {
+ UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid));
+ if (userRecord != null && userRecord.mClientRecords != null) {
+ for (ClientRecord cr : userRecord.mClientRecords) {
+ if (validatePackageName(uid, cr.mPackageName)) {
+ clientRecord = cr;
+ break;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0778d09..07ab417 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -369,11 +369,14 @@
private final boolean mSuppressDefaultPolicy;
/** Defined network policies. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
/** Map from subId to subscription plans. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
final SparseArray<SubscriptionPlan[]> mSubscriptionPlans = new SparseArray<>();
/** Map from subId to package name that owns subscription plans. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
final SparseArray<String> mSubscriptionPlansOwner = new SparseArray<>();
/** Defined UID policies. */
@@ -2767,20 +2770,18 @@
return plans.toArray(new SubscriptionPlan[plans.size()]);
}
- synchronized (mUidRulesFirstLock) {
- synchronized (mNetworkPoliciesSecondLock) {
- // Only give out plan details to the package that defined them,
- // so that we don't risk leaking plans between apps. We always
- // let in core system components (like the Settings app).
- final String ownerPackage = mSubscriptionPlansOwner.get(subId);
- if (Objects.equals(ownerPackage, callingPackage)
- || (UserHandle.getCallingAppId() == android.os.Process.SYSTEM_UID)) {
- return mSubscriptionPlans.get(subId);
- } else {
- Log.w(TAG, "Not returning plans because caller " + callingPackage
- + " doesn't match owner " + ownerPackage);
- return null;
- }
+ synchronized (mNetworkPoliciesSecondLock) {
+ // Only give out plan details to the package that defined them,
+ // so that we don't risk leaking plans between apps. We always
+ // let in core system components (like the Settings app).
+ final String ownerPackage = mSubscriptionPlansOwner.get(subId);
+ if (Objects.equals(ownerPackage, callingPackage)
+ || (UserHandle.getCallingAppId() == android.os.Process.SYSTEM_UID)) {
+ return mSubscriptionPlans.get(subId);
+ } else {
+ Log.w(TAG, "Not returning plans because caller " + callingPackage
+ + " doesn't match owner " + ownerPackage);
+ return null;
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 8837c15..4ceb592 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -177,6 +177,34 @@
}
}
+ /**
+ * Safely multiple a value by a rational.
+ * <p>
+ * Internally it uses integer-based math whenever possible, but switches
+ * over to double-based math if values would overflow.
+ */
+ @VisibleForTesting
+ public static long multiplySafe(long value, long num, long den) {
+ long x = value;
+ long y = num;
+
+ // Logic shamelessly borrowed from Math.multiplyExact()
+ long r = x * y;
+ long ax = Math.abs(x);
+ long ay = Math.abs(y);
+ if (((ax | ay) >>> 31 != 0)) {
+ // Some bits greater than 2^31 that might cause overflow
+ // Check the result using the divide operator
+ // and check for the special case of Long.MIN_VALUE * -1
+ if (((y != 0) && (r / y != x)) ||
+ (x == Long.MIN_VALUE && y == -1)) {
+ // Use double math to avoid overflowing
+ return (long) (((double) num / den) * value);
+ }
+ }
+ return r / den;
+ }
+
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
return getRelevantUids(accessLevel, Binder.getCallingUid());
}
@@ -274,8 +302,8 @@
final long rawRxBytes = entry.rxBytes;
final long rawTxBytes = entry.txBytes;
final long targetBytes = augmentPlan.getDataUsageBytes();
- final long targetRxBytes = (rawRxBytes * targetBytes) / rawBytes;
- final long targetTxBytes = (rawTxBytes * targetBytes) / rawBytes;
+ final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes);
+ final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes);
// Scale all matching buckets to reach anchor target
final long beforeTotal = combined.getTotalBytes();
@@ -283,8 +311,8 @@
combined.getValues(i, entry);
if (entry.bucketStart >= augmentStart
&& entry.bucketStart + entry.bucketDuration <= augmentEnd) {
- entry.rxBytes = (entry.rxBytes * targetRxBytes) / rawRxBytes;
- entry.txBytes = (entry.txBytes * targetTxBytes) / rawTxBytes;
+ entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes);
+ entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes);
// We purposefully clear out packet counters to indicate
// that this data has been augmented.
entry.rxPackets = 0;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4bd927d..3af5265 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -124,6 +124,7 @@
import android.util.TrustedTime;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
@@ -241,12 +242,17 @@
private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
new DropBoxNonMonotonicObserver();
+ @GuardedBy("mStatsLock")
private NetworkStatsRecorder mDevRecorder;
+ @GuardedBy("mStatsLock")
private NetworkStatsRecorder mXtRecorder;
+ @GuardedBy("mStatsLock")
private NetworkStatsRecorder mUidRecorder;
+ @GuardedBy("mStatsLock")
private NetworkStatsRecorder mUidTagRecorder;
/** Cached {@link #mXtRecorder} stats. */
+ @GuardedBy("mStatsLock")
private NetworkStatsCollection mXtStatsCached;
/** Current counter sets for each UID. */
@@ -328,15 +334,15 @@
return;
}
- // create data recorders along with historical rotators
- mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
- mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false);
- mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
- mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
-
- updatePersistThresholds();
-
synchronized (mStatsLock) {
+ // create data recorders along with historical rotators
+ mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
+ mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false);
+ mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
+ mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
+
+ updatePersistThresholdsLocked();
+
// upgrade any legacy stats, migrating them to rotated files
maybeUpgradeLegacyStatsLocked();
@@ -674,9 +680,12 @@
int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getHistory(template, resolveSubscriptionPlan(template, flags),
- UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE,
- accessLevel, callingUid);
+ final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags);
+ synchronized (mStatsLock) {
+ return mXtStatsCached.getHistory(template, augmentPlan,
+ UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE,
+ accessLevel, callingUid);
+ }
}
@Override
@@ -813,7 +822,7 @@
synchronized (mStatsLock) {
if (!mSystemReady) return;
- updatePersistThresholds();
+ updatePersistThresholdsLocked();
mDevRecorder.maybePersistLocked(currentTime);
mXtRecorder.maybePersistLocked(currentTime);
@@ -869,7 +878,7 @@
* reflect current {@link #mPersistThreshold} value. Always defers to
* {@link Global} values when defined.
*/
- private void updatePersistThresholds() {
+ private void updatePersistThresholdsLocked() {
mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold));
mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold));
mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold));
@@ -1311,7 +1320,7 @@
synchronized (mStatsLock) {
if (args.length > 0 && "--proto".equals(args[0])) {
// In this case ignore all other arguments.
- dumpProto(fd);
+ dumpProtoLocked(fd);
return;
}
@@ -1387,7 +1396,7 @@
}
}
- private void dumpProto(FileDescriptor fd) {
+ private void dumpProtoLocked(FileDescriptor fd) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
// TODO Right now it writes all history. Should it limit to the "since-boot" log?
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 638523a..27159fa 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -7817,13 +7817,13 @@
case HapticFeedbackConstants.VIRTUAL_KEY:
return VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
- return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false);
case HapticFeedbackConstants.KEYBOARD_PRESS: // == HapticFeedbackConstants.KEYBOARD_TAP
return VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
case HapticFeedbackConstants.KEYBOARD_RELEASE:
- return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false);
case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
- return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false);
default:
return null;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 805250a..6484a13 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -429,6 +429,8 @@
}
public void getMagnificationRegionLocked(Region outMagnificationRegion) {
+ // Make sure we're working with the most current bounds
+ mMagnifedViewport.recomputeBoundsLocked();
mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index c2edc04..c76b905 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -450,7 +450,7 @@
return isAnimating;
}
- void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index f142ff6..b083aee 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -366,7 +366,6 @@
// if made visible again.
wtoken.removeDeadWindows();
wtoken.setVisibleBeforeClientHidden();
- mService.mUnknownAppVisibilityController.appRemovedOrHidden(wtoken);
} else {
if (!mService.mAppTransition.isTransitionSet()
&& mService.mAppTransition.isReady()) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f4ac961..0a7d1c1 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -368,10 +368,10 @@
boolean runningAppAnimation = false;
+ if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
+ mAppAnimator.setNullAnimation();
+ }
if (transit != AppTransition.TRANSIT_UNSET) {
- if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
- mAppAnimator.setNullAnimation();
- }
if (mService.applyAnimationLocked(this, lp, transit, visible, isVoiceInteraction)) {
delayed = runningAppAnimation = true;
}
@@ -1759,6 +1759,9 @@
if (mRemovingFromDisplay) {
pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
}
+ if (mAppAnimator.isAnimating()) {
+ mAppAnimator.dump(pw, prefix + " ");
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index cff2fad..7953ee4 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -21,7 +21,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.animation.AnimationHandler;
-import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
@@ -32,13 +31,11 @@
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
-import android.view.Choreographer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.WindowManagerInternal;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -142,9 +139,6 @@
// True if this this animation was canceled and will be replaced the another animation from
// the same {@link #BoundsAnimationTarget} target.
private boolean mSkipFinalResize;
- // True if this animation replaced a previous animation of the same
- // {@link #BoundsAnimationTarget} target.
- private final boolean mSkipAnimationStart;
// True if this animation was canceled by the user, not as a part of a replacing animation
private boolean mSkipAnimationEnd;
@@ -159,6 +153,7 @@
// Whether to schedule PiP mode changes on animation start/end
private @SchedulePipModeChangedState int mSchedulePipModeChangedState;
+ private @SchedulePipModeChangedState int mPrevSchedulePipModeChangedState;
// Depending on whether we are animating from
// a smaller to a larger size
@@ -171,14 +166,14 @@
BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
@SchedulePipModeChangedState int schedulePipModeChangedState,
- boolean moveFromFullscreen, boolean moveToFullscreen,
- boolean replacingExistingAnimation) {
+ @SchedulePipModeChangedState int prevShedulePipModeChangedState,
+ boolean moveFromFullscreen, boolean moveToFullscreen) {
super();
mTarget = target;
mFrom.set(from);
mTo.set(to);
- mSkipAnimationStart = replacingExistingAnimation;
mSchedulePipModeChangedState = schedulePipModeChangedState;
+ mPrevSchedulePipModeChangedState = prevShedulePipModeChangedState;
mMoveFromFullscreen = moveFromFullscreen;
mMoveToFullscreen = moveToFullscreen;
addUpdateListener(this);
@@ -200,7 +195,7 @@
@Override
public void onAnimationStart(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
- + " mSkipAnimationStart=" + mSkipAnimationStart
+ + " mPrevSchedulePipModeChangedState=" + mPrevSchedulePipModeChangedState
+ " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState);
mFinishAnimationAfterTransition = false;
mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
@@ -210,18 +205,26 @@
// running
updateBooster();
- // Ensure that we have prepared the target for animation before
- // we trigger any size changes, so it can swap surfaces
- // in to appropriate modes, or do as it wishes otherwise.
- if (!mSkipAnimationStart) {
+ // Ensure that we have prepared the target for animation before we trigger any size
+ // changes, so it can swap surfaces in to appropriate modes, or do as it wishes
+ // otherwise.
+ if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) {
mTarget.onAnimationStart(mSchedulePipModeChangedState ==
- SCHEDULE_PIP_MODE_CHANGED_ON_START);
+ SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */);
// When starting an animation from fullscreen, pause here and wait for the
// windows-drawn signal before we start the rest of the transition down into PiP.
if (mMoveFromFullscreen) {
pause();
}
+ } else if (mPrevSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END &&
+ mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
+ // We are replacing a running animation into PiP, but since it hasn't completed, the
+ // client will not currently receive any picture-in-picture mode change callbacks.
+ // However, we still need to report to them that they are leaving PiP, so this will
+ // force an update via a mode changed callback.
+ mTarget.onAnimationStart(true /* schedulePipModeChangedCallback */,
+ true /* forceUpdate */);
}
// Immediately update the task bounds if they have to become larger, but preserve
@@ -388,6 +391,8 @@
boolean moveFromFullscreen, boolean moveToFullscreen) {
final BoundsAnimator existing = mRunningAnimations.get(target);
final boolean replacing = existing != null;
+ @SchedulePipModeChangedState int prevSchedulePipModeChangedState =
+ NO_PIP_MODE_CHANGED_CALLBACKS;
if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to
+ " schedulePipModeChangedState=" + schedulePipModeChangedState
@@ -403,6 +408,9 @@
return existing;
}
+ // Save the previous state
+ prevSchedulePipModeChangedState = existing.mSchedulePipModeChangedState;
+
// Update the PiP callback states if we are replacing the animation
if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
@@ -428,7 +436,8 @@
existing.cancel();
}
final BoundsAnimator animator = new BoundsAnimator(target, from, to,
- schedulePipModeChangedState, moveFromFullscreen, moveToFullscreen, replacing);
+ schedulePipModeChangedState, prevSchedulePipModeChangedState,
+ moveFromFullscreen, moveToFullscreen);
mRunningAnimations.put(target, animator);
animator.setFloatValues(0f, 1f);
animator.setDuration((animationDuration != -1 ? animationDuration
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 8b1bf7b..647a2d6 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -31,7 +31,7 @@
* @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed
* callbacks
*/
- void onAnimationStart(boolean schedulePipModeChangedCallback);
+ void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
/**
* Sets the size of the target (without any intermediate steps, like scheduling animation)
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 989e8f2..fc0baad 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -202,10 +202,12 @@
*/
/** Calls directly into activity manager so window manager lock shouldn't held. */
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) {
+ public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {
if (mListener != null) {
PinnedStackWindowListener listener = (PinnedStackWindowListener) mListener;
- listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds);
+ listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds,
+ forceUpdate);
}
}
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
index 12b9c1f..33e8a60 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
@@ -28,5 +28,6 @@
* Called when the stack container pinned stack animation will change the picture-in-picture
* mode. This is a direct call into ActivityManager.
*/
- default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) {}
+ default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 39878cc..55151a1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1498,7 +1498,7 @@
}
@Override // AnimatesBounds
- public void onAnimationStart(boolean schedulePipModeChangedCallback) {
+ public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
synchronized (mService.mWindowMap) {
mBoundsAnimatingRequested = false;
@@ -1523,9 +1523,11 @@
final PinnedStackWindowController controller =
(PinnedStackWindowController) getController();
if (schedulePipModeChangedCallback && controller != null) {
- // We need to schedule the PiP mode change after the animation down, so use the
- // final bounds
- controller.updatePictureInPictureModeForPinnedStackAnimation(null);
+ // We need to schedule the PiP mode change before the animation up. It is possible
+ // in this case for the animation down to not have been completed, so always
+ // force-schedule and update to the client to ensure that it is notified that it
+ // is no longer in picture-in-picture mode
+ controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
}
}
}
@@ -1553,7 +1555,7 @@
// We need to schedule the PiP mode change after the animation down, so use the
// final bounds
controller.updatePictureInPictureModeForPinnedStackAnimation(
- mBoundsAnimationTarget);
+ mBoundsAnimationTarget, false /* forceUpdate */);
}
if (finalStackSize != null) {
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 0370490..d2f374d 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -153,9 +153,9 @@
if (status == Status::OK) {
return lengthMs;
} else if (status != Status::UNSUPPORTED_OPERATION) {
- // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor
- // doesn't have a pre-defined waveform to perform for it, so we should just fall back
- // to the framework waveforms.
+ // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
+ // doesn't have a pre-defined waveform to perform for it, so we should just give the
+ // opportunity to fall back to the framework waveforms.
ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
", error=%" PRIu32 ").", static_cast<int64_t>(effect),
static_cast<int32_t>(strength), static_cast<uint32_t>(status));
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 9d32496..0081214 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -126,6 +126,7 @@
boolean mMovedToFullscreen;
boolean mAnimationStarted;
boolean mSchedulePipModeChangedOnStart;
+ boolean mForcePipModeChangedCallback;
boolean mAnimationEnded;
Rect mAnimationEndFinalStackBounds;
boolean mSchedulePipModeChangedOnEnd;
@@ -140,6 +141,7 @@
mAnimationStarted = false;
mAnimationEnded = false;
mAnimationEndFinalStackBounds = null;
+ mForcePipModeChangedCallback = false;
mSchedulePipModeChangedOnStart = false;
mSchedulePipModeChangedOnEnd = false;
mStackBounds = from;
@@ -148,10 +150,11 @@
}
@Override
- public void onAnimationStart(boolean schedulePipModeChangedCallback) {
+ public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
mAwaitingAnimationStart = false;
mAnimationStarted = true;
mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
+ mForcePipModeChangedCallback = forceUpdate;
}
@Override
@@ -232,7 +235,7 @@
return this;
}
- BoundsAnimationDriver restart(Rect to) {
+ BoundsAnimationDriver restart(Rect to, boolean expectStartedAndPipModeChangedCallback) {
if (mAnimator == null) {
throw new IllegalArgumentException("Call start() to start a new animation");
}
@@ -251,8 +254,15 @@
assertSame(oldAnimator, mAnimator);
}
- // No animation start for replacing animation
- assertTrue(!mTarget.mAnimationStarted);
+ if (expectStartedAndPipModeChangedCallback) {
+ // Replacing animation with pending pip mode changed callback, ensure we update
+ assertTrue(mTarget.mAnimationStarted);
+ assertTrue(mTarget.mSchedulePipModeChangedOnStart);
+ assertTrue(mTarget.mForcePipModeChangedCallback);
+ } else {
+ // No animation start for replacing animation
+ assertTrue(!mTarget.mAnimationStarted);
+ }
mTarget.mAnimationStarted = true;
return this;
}
@@ -467,7 +477,7 @@
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_FLOATING)
+ .restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
@@ -478,7 +488,8 @@
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_SMALLER_FLOATING)
+ .restart(BOUNDS_SMALLER_FLOATING,
+ false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
@@ -486,10 +497,12 @@
@UiThreadTest
@Test
public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception {
+ // When animating from fullscreen and the animation is interruped, we expect the animation
+ // start callback to be made, with a forced pip mode change callback
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_FULL)
+ .restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
}
@@ -512,7 +525,7 @@
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_FULL)
+ .restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
}
@@ -523,7 +536,8 @@
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_SMALLER_FLOATING)
+ .restart(BOUNDS_SMALLER_FLOATING,
+ false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 0c2ad38..9c10264 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -27,7 +27,10 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.server.net.NetworkStatsCollection.multiplySafe;
+
import android.content.res.Resources;
+import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
@@ -40,6 +43,7 @@
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.format.DateUtils;
+import android.util.RecurrenceRule;
import com.android.frameworks.tests.net.R;
@@ -53,6 +57,9 @@
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -70,14 +77,27 @@
private static final long TIME_B = 1326110400000L; // UTC: Monday 9th January 2012 12:00:00 PM
private static final long TIME_C = 1326132000000L; // UTC: Monday 9th January 2012 06:00:00 PM
+ private static Clock sOriginalClock;
+
@Override
public void setUp() throws Exception {
super.setUp();
+ sOriginalClock = RecurrenceRule.sClock;
// ignore any device overlay while testing
NetworkTemplate.forceAllNetworkTypes();
}
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ RecurrenceRule.sClock = sOriginalClock;
+ }
+
+ private void setClock(Instant instant) {
+ RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
+ }
+
public void testReadLegacyNetwork() throws Exception {
final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
stageFile(R.raw.netstats_v1, testFile);
@@ -238,6 +258,9 @@
final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
collection.readLegacyNetwork(testFile);
+ // We're in the future, but not that far off
+ setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
+
// Test a bunch of plans that should result in no augmentation
final List<SubscriptionPlan> plans = new ArrayList<>();
@@ -416,6 +439,28 @@
}
}
+ public void testAugmentPlanGigantic() throws Exception {
+ // We're in the future, but not that far off
+ setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
+
+ // Create a simple history with a ton of measured usage
+ final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
+ final NetworkIdentitySet ident = new NetworkIdentitySet();
+ ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
+ false, true));
+ large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
+ new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
+
+ // Verify untouched total
+ assertEquals(12_730_893_164L, getHistory(large, null, TIME_A, TIME_C).getTotalBytes());
+
+ // Verify anchor that might cause overflows
+ final SubscriptionPlan plan = SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2012-01-09T00:00:00.00Z"))
+ .setDataUsage(4_939_212_390L, TIME_B).build();
+ assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes());
+ }
+
public void testRounding() throws Exception {
final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
@@ -437,6 +482,25 @@
assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
}
+ public void testMultiplySafe() {
+ assertEquals(25, multiplySafe(50, 1, 2));
+ assertEquals(100, multiplySafe(50, 2, 1));
+
+ assertEquals(-10, multiplySafe(30, -1, 3));
+ assertEquals(0, multiplySafe(30, 0, 3));
+ assertEquals(10, multiplySafe(30, 1, 3));
+ assertEquals(20, multiplySafe(30, 2, 3));
+ assertEquals(30, multiplySafe(30, 3, 3));
+ assertEquals(40, multiplySafe(30, 4, 3));
+
+ assertEquals(100_000_000_000L,
+ multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
+ assertEquals(100_000_000_010L,
+ multiplySafe(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
+ assertEquals(823_202_048L,
+ multiplySafe(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
+ }
+
/**
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
* testing purposes.