diff options
29 files changed, 218 insertions, 49 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 0d852e52665b..f2a8ea5eb148 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -978,18 +978,19 @@ public final class ActivityThread { @Override public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, - boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) { + boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, + boolean dumpUnreachable, String[] args) { FileOutputStream fout = new FileOutputStream(fd); PrintWriter pw = new FastPrintWriter(fout); try { - dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly); + dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable); } finally { pw.flush(); } } private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin, - boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly) { + boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable) { long nativeMax = Debug.getNativeHeapSize() / 1024; long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024; long nativeFree = Debug.getNativeHeapFreeSize() / 1024; @@ -1103,6 +1104,16 @@ public final class ActivityThread { pw.println(" Asset Allocations"); pw.print(assetAlloc); } + + // Unreachable native memory + if (dumpUnreachable) { + boolean showContents = ((mBoundApplication != null) + && ((mBoundApplication.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0)) + || android.os.Build.IS_DEBUGGABLE; + pw.println(" "); + pw.println(" Unreachable memory"); + pw.print(Debug.getUnreachableMemory(100, showContents)); + } } @Override diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 59ecc03d1295..744ddf704161 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -548,11 +548,12 @@ public abstract class ApplicationThreadNative extends Binder boolean dumpInfo = data.readInt() != 0; boolean dumpDalvik = data.readInt() != 0; boolean dumpSummaryOnly = data.readInt() != 0; + boolean dumpUnreachable = data.readInt() != 0; String[] args = data.readStringArray(); if (fd != null) { try { dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo, - dumpDalvik, dumpSummaryOnly, args); + dumpDalvik, dumpSummaryOnly, dumpUnreachable, args); } finally { try { fd.close(); @@ -1328,7 +1329,8 @@ class ApplicationThreadProxy implements IApplicationThread { } public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, - boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException { + boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, + boolean dumpUnreachable, String[] args) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); @@ -1338,6 +1340,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeInt(dumpInfo ? 1 : 0); data.writeInt(dumpDalvik ? 1 : 0); data.writeInt(dumpSummaryOnly ? 1 : 0); + data.writeInt(dumpUnreachable ? 1 : 0); data.writeStringArray(args); mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0); reply.readException(); diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index b55da88c8a3e..a3c95916bb98 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -133,7 +133,8 @@ public interface IApplicationThread extends IInterface { void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException; void scheduleTrimMemory(int level) throws RemoteException; void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo, - boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException; + boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable, + String[] args) throws RemoteException; void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException; void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException; void unstableProviderDied(IBinder provider) throws RemoteException; diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index fb16150b9abf..f3822413add3 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -2160,6 +2160,14 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo public static native void dumpNativeBacktraceToFile(int pid, String file); /** + * Get description of unreachable native memory. + * @param limit the number of leaks to provide info on, 0 to only get a summary. + * @param contents true to include a hex dump of the contents of unreachable memory. + * @return the String containing a description of unreachable memory. + * @hide */ + public static native String getUnreachableMemory(int limit, boolean contents); + + /** * Return a String describing the calling method and location at a particular stack depth. * @param callStack the Thread stack * @param depth the depth of stack to return information for. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c5b165321d91..afe2f1061f3a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4398,8 +4398,14 @@ public final class ViewRootImpl implements ViewParent, private boolean updatePointerIcon(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); + if (mView == null) { + // E.g. click outside a popup to dismiss it + Slog.d(mTag, "updatePointerIcon called after view was removed"); + return false; + } if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) { - Slog.e(mTag, "updatePointerIcon called with position out of bounds"); + // E.g. when moving window divider with mouse + Slog.d(mTag, "updatePointerIcon called with position out of bounds"); return false; } final PointerIcon pointerIcon = mView.getPointerIcon(event, x, y); diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a8d684d7a612..d5f080ae4b27 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -260,7 +260,8 @@ LOCAL_SHARED_LIBRARIES := \ libprocessgroup \ libnativebridge \ libradio_metadata \ - libnativeloader + libnativeloader \ + libmemunreachable \ LOCAL_SHARED_LIBRARIES += \ libhwui \ diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 8b248b07a07d..29c1075a3420 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -555,6 +555,12 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file, SkFILEStream::kCallerPasses_Ownership)); + // If there is no offset for the file descriptor, we use SkFILEStream directly. + if (::lseek(descriptor, 0, SEEK_CUR) == 0) { + assert(isSeekable(dupDescriptor)); + return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions); + } + // Use a buffered stream. Although an SkFILEStream can be rewound, this // ensures that SkImageDecoder::Factory never rewinds beyond the // current position of the file descriptor. @@ -584,7 +590,7 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) { jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); - return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE; + return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE; } jobject decodeBitmap(JNIEnv* env, void* data, size_t size) { diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp index 4f9ce8bfcef7..5fa445e256fe 100644 --- a/core/jni/android/graphics/Utils.cpp +++ b/core/jni/android/graphics/Utils.cpp @@ -116,3 +116,7 @@ jobject android::nullObjectReturn(const char msg[]) { } return NULL; } + +bool android::isSeekable(int descriptor) { + return ::lseek64(descriptor, 0, SEEK_CUR) != -1; +} diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h index c0b941004758..d1a74a0adf6c 100644 --- a/core/jni/android/graphics/Utils.h +++ b/core/jni/android/graphics/Utils.h @@ -68,6 +68,10 @@ private: jobject nullObjectReturn(const char msg[]); +/** Check if the file descriptor is seekable. + */ +bool isSeekable(int descriptor); + }; // namespace android #endif // _ANDROID_GRAPHICS_UTILS_H_ diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 03a1e718d2ea..3df0876532cb 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -21,6 +21,7 @@ #include "utils/misc.h" #include "cutils/debugger.h" #include <memtrack/memtrack.h> +#include <memunreachable/memunreachable.h> #include <cutils/log.h> #include <fcntl.h> @@ -36,6 +37,9 @@ #include <ctype.h> #include <malloc.h> +#include <iomanip> +#include <string> + namespace android { @@ -1023,6 +1027,13 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz close(fd); } +static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz, + jint limit, jboolean contents) +{ + std::string s = GetUnreachableMemoryString(contents, limit); + return env->NewStringUTF(s.c_str()); +} + /* * JNI registration. */ @@ -1058,6 +1069,8 @@ static const JNINativeMethod gMethods[] = { (void*)android_os_Debug_getDeathObjectCount }, { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V", (void*)android_os_Debug_dumpNativeBacktraceToFile }, + { "getUnreachableMemory", "(IZ)Ljava/lang/String;", + (void*)android_os_Debug_getUnreachableMemory }, }; int register_android_os_Debug(JNIEnv *env) diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index d4f745d818bd..af99f79e4b3b 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -91,8 +91,11 @@ public class Canvas { // a Canvas object. private static final long NATIVE_ALLOCATION_SIZE = 525; - private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( - getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); + // Use a Holder to allow static initialization of Canvas in the boot image. + private static class NoImagePreloadHolder { + public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( + getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); + } // This field is used to finalize the native Canvas properly private Runnable mFinalizer; @@ -107,7 +110,8 @@ public class Canvas { if (!isHardwareAccelerated()) { // 0 means no native bitmap mNativeCanvasWrapper = initRaster(null); - mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper); + mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( + this, mNativeCanvasWrapper); } else { mFinalizer = null; } @@ -128,7 +132,8 @@ public class Canvas { } throwIfCannotDraw(bitmap); mNativeCanvasWrapper = initRaster(bitmap); - mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper); + mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( + this, mNativeCanvasWrapper); mBitmap = bitmap; mDensity = bitmap.mDensity; } @@ -139,7 +144,8 @@ public class Canvas { throw new IllegalStateException(); } mNativeCanvasWrapper = nativeCanvas; - mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper); + mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( + this, mNativeCanvasWrapper); mDensity = Bitmap.getDefaultDensity(); } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 534121a2e361..291fdc4f8e05 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -44,8 +44,11 @@ public class Paint { // The approximate size of a native paint object. private static final long NATIVE_PAINT_SIZE = 98; - private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( - nGetNativeFinalizer(), NATIVE_PAINT_SIZE); + // Use a Holder to allow static initialization of Paint in the boot image. + private static class NoImagePreloadHolder { + public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( + nGetNativeFinalizer(), NATIVE_PAINT_SIZE); + } /** * @hide @@ -452,7 +455,7 @@ public class Paint { */ public Paint(int flags) { mNativePaint = nInit(); - sRegistry.registerNativeAllocation(this, mNativePaint); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint); setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS); // TODO: Turning off hinting has undesirable side effects, we need to // revisit hinting once we add support for subpixel positioning @@ -471,7 +474,7 @@ public class Paint { */ public Paint(Paint paint) { mNativePaint = nInitWithPaint(paint.getNativeInstance()); - sRegistry.registerNativeAllocation(this, mNativePaint); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint); setClassVariablesFrom(paint); } diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 8831bafd43d7..54b453d044b4 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -242,6 +242,7 @@ LOCAL_SRC_FILES += \ tests/unit/GpuMemoryTrackerTests.cpp \ tests/unit/LayerUpdateQueueTests.cpp \ tests/unit/LinearAllocatorTests.cpp \ + tests/unit/MatrixTests.cpp \ tests/unit/OffscreenBufferPoolTests.cpp \ tests/unit/SkiaBehaviorTests.cpp \ tests/unit/StringUtilsTests.cpp \ diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp index 2198fcc95fe5..f170e9cda8af 100644 --- a/libs/hwui/AnimatorManager.cpp +++ b/libs/hwui/AnimatorManager.cpp @@ -95,11 +95,11 @@ void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) class AnimateFunctor { public: - AnimateFunctor(TreeInfo& info, AnimationContext& context) - : dirtyMask(0), mInfo(info), mContext(context) {} + AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask) + : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {} bool operator() (sp<BaseRenderNodeAnimator>& animator) { - dirtyMask |= animator->dirtyMask(); + *mDirtyMask |= animator->dirtyMask(); bool remove = animator->animate(mContext); if (remove) { animator->detach(); @@ -114,11 +114,10 @@ public: return remove; } - uint32_t dirtyMask; - private: TreeInfo& mInfo; AnimationContext& mContext; + uint32_t* mDirtyMask; }; uint32_t AnimatorManager::animate(TreeInfo& info) { @@ -143,12 +142,13 @@ void AnimatorManager::animateNoDamage(TreeInfo& info) { } uint32_t AnimatorManager::animateCommon(TreeInfo& info) { - AnimateFunctor functor(info, mAnimationHandle->context()); + uint32_t dirtyMask; + AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask); auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor); mAnimators.erase(newEnd, mAnimators.end()); mAnimationHandle->notifyAnimationsRan(); mParent.mProperties.updateMatrix(); - return functor.dirtyMask; + return dirtyMask; } static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) { diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 78764b5f4448..1aab3c79dcfd 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -368,7 +368,7 @@ void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, cons op.startAngle, op.sweepAngle, op.useCenter, op.paint); const AutoTexture holder(texture); if (CC_LIKELY(holder.texture)) { - renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.right, + renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top, *texture, *(op.paint)); } } else { diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp index e368537f0b4f..501cbe50ee05 100644 --- a/libs/hwui/ClipArea.cpp +++ b/libs/hwui/ClipArea.cpp @@ -404,11 +404,17 @@ static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* s return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles; } +static const ClipRect sEmptyClipRect(Rect(0, 0)); + const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator, const ClipBase* recordedClip, const Matrix4& recordedClipTransform) { + // if no recordedClip passed, just serialize current state if (!recordedClip) return serializeClip(allocator); + // if either is empty, clip is empty + if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect; + if (!mLastResolutionResult || recordedClip != mLastResolutionClip || recordedClipTransform != mLastResolutionTransform) { diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index 73ebd1304750..deab95690d0e 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -438,7 +438,7 @@ void Matrix4::mapPoint(float& x, float& y) const { } void Matrix4::mapRect(Rect& r) const { - if (isIdentity()) return; + if (isIdentity() || r.isEmpty()) return; if (isSimple()) { MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]); diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 31de305d5246..9ae2212d0732 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -594,7 +594,14 @@ void RecordingCanvas::callDrawGLFunction(Functor* functor) { } size_t RecordingCanvas::addOp(RecordedOp* op) { - // TODO: validate if "addDrawOp" quickrejection logic is useful before adding + // skip op with empty clip + if (op->localClip && op->localClip->rect.isEmpty()) { + // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd + // and held by renderthread isn't affected by clip rejection. + // Could rewind alloc here if desired, but callers would have to not touch op afterwards. + return -1; + } + int insertIndex = mDisplayList->ops.size(); mDisplayList->ops.push_back(op); if (mDeferredBarrierType != DeferredBarrierType::None) { diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp index 679569ef5a78..dc2ea0784b7e 100644 --- a/libs/hwui/tests/unit/ClipAreaTests.cpp +++ b/libs/hwui/tests/unit/ClipAreaTests.cpp @@ -228,6 +228,7 @@ TEST(ClipArea, serializeIntersectedClip) { ClipRegion recordedClip; recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200))); + recordedClip.rect = Rect(200, 200); Matrix4 translate10x20; translate10x20.loadTranslate(10, 20, 0); diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp new file mode 100644 index 000000000000..da2263788c25 --- /dev/null +++ b/libs/hwui/tests/unit/MatrixTests.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <gtest/gtest.h> + +#include "Matrix.h" +#include "Rect.h" + +using namespace android::uirenderer; + +TEST(Matrix, mapRect) { + // Skew, so we don't hit identity/translate/simple fast paths + Matrix4 matrix; + matrix.skew(0.1f, 0.1f); + + // non-zero empty rect, so sorting x/y would make rect non-empty + Rect empty(100, 100, -100, -100); + ASSERT_TRUE(empty.isEmpty()); + matrix.mapRect(empty); + EXPECT_TRUE(empty.isEmpty()) + << "Empty rect should always remain empty, regardless of mapping."; +} diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index f988da399665..c39047ca1d89 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -58,6 +58,17 @@ TEST(RecordingCanvas, clipRect) { << "Clip should be serialized once"; } +TEST(RecordingCanvas, emptyClipRect) { + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { + canvas.save(SaveFlags::MatrixClip); + canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op); + canvas.clipRect(100, 100, 200, 200, SkRegion::kIntersect_Op); + canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time + canvas.restore(); + }); + ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected."; +} + TEST(RecordingCanvas, drawArc) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 9bd645d79240..d0358f4cda60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -959,7 +959,7 @@ public abstract class BaseStatusBar extends SystemUI implements }, false /* afterKeyguardGone */); } - private void bindGuts(ExpandableNotificationRow row) { + private void bindGuts(final ExpandableNotificationRow row) { row.inflateGuts(); final StatusBarNotification sbn = row.getStatusBarNotification(); PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier()); @@ -1003,7 +1003,17 @@ public abstract class BaseStatusBar extends SystemUI implements @Override public void onClick(View v) { guts.saveImportance(sbn); - dismissPopups(); + + int[] rowLocation = new int[2]; + int[] doneLocation = new int[2]; + row.getLocationOnScreen(rowLocation); + v.getLocationOnScreen(doneLocation); + + final int centerX = v.getWidth() / 2; + final int centerY = v.getHeight() / 2; + final int x = doneLocation[0] - rowLocation[0] + centerX; + final int y = doneLocation[1] - rowLocation[1] + centerY; + dismissPopups(x, y); } }); @@ -1049,7 +1059,7 @@ public abstract class BaseStatusBar extends SystemUI implements // Post to ensure the the guts are properly laid out. guts.post(new Runnable() { public void run() { - dismissPopups(); + dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */); guts.setVisibility(View.VISIBLE); final double horz = Math.max(guts.getWidth() - x, x); final double vert = Math.max(guts.getHeight() - y, y); @@ -1083,10 +1093,14 @@ public abstract class BaseStatusBar extends SystemUI implements } public void dismissPopups() { - dismissPopups(-1, -1); + dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */); } private void dismissPopups(int x, int y) { + dismissPopups(x, y, true /* resetGear */); + } + + public void dismissPopups(int x, int y, boolean resetGear) { if (mNotificationGutsExposed != null) { final NotificationGuts v = mNotificationGutsExposed; mNotificationGutsExposed = null; @@ -1114,8 +1128,7 @@ public abstract class BaseStatusBar extends SystemUI implements v.setExposed(false); mStackScroller.onHeightChanged(null, true /* needsAnimation */); } - - if (mNotificationGearDisplayed != null) { + if (resetGear && mNotificationGearDisplayed != null) { mNotificationGearDisplayed.resetTranslation(); mNotificationGearDisplayed = null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index da125d8f77a6..e109b0901532 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -656,7 +656,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { mGuts = (NotificationGuts) inflated; mGuts.setClipTopAmount(getClipTopAmount()); mGuts.setActualHeight(getActualHeight()); - mTranslateableViews.add(mGuts); mGutsStub = null; } }); @@ -1175,6 +1174,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { @Override public void setActualHeight(int height, boolean notifyListeners) { super.setActualHeight(height, notifyListeners); + if (mGuts != null && mGuts.areGutsExposed()) { + mGuts.setActualHeight(height); + return; + } int contentHeight = Math.max(getMinHeight(), height); mPrivateLayout.setContentHeight(contentHeight); mPublicLayout.setContentHeight(contentHeight); @@ -1184,7 +1187,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { if (mGuts != null) { mGuts.setActualHeight(height); } - invalidate(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java index 4491ebde742b..476e146d1859 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java @@ -33,7 +33,7 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC /** * Called when the gear behind a notification is touched. */ - public void onGearTouched(ExpandableNotificationRow row); + public void onGearTouched(ExpandableNotificationRow row, int x, int y); } private ExpandableNotificationRow mParent; @@ -45,6 +45,8 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC private boolean mSettingsFadedIn = false; private boolean mAnimating = false; private boolean mOnLeft = true; + private int[] mGearLocation = new int[2]; + private int[] mParentLocation = new int[2]; public NotificationSettingsIconRow(Context context) { this(context, null); @@ -74,6 +76,12 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC resetState(); } + public void resetState() { + setGearAlpha(0f); + mAnimating = false; + setIconLocation(true /* on left */); + } + public void setGearListener(SettingsIconRowListener listener) { mListener = listener; } @@ -86,12 +94,6 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC return mParent; } - public void resetState() { - setGearAlpha(0f); - mAnimating = false; - setIconLocation(true /* on left */); - } - private void setGearAlpha(float alpha) { if (alpha == 0) { mSettingsFadedIn = false; // Can fade in again once it's gone. @@ -200,7 +202,16 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC public void onClick(View v) { if (v.getId() == R.id.gear_icon) { if (mListener != null) { - mListener.onGearTouched(mParent); + mGearIcon.getLocationOnScreen(mGearLocation); + mParent.getLocationOnScreen(mParentLocation); + + final int centerX = (int) (mHorizSpaceForGear / 2); + // Top / bottom padding are not equal, need to subtract them to get center of gear. + final int centerY = (int) (mGearIcon.getHeight() - mGearIcon.getPaddingTop() + - mGearIcon.getPaddingBottom()) / 2 + mGearIcon.getPaddingTop(); + final int x = mGearLocation[0] - mParentLocation[0] + centerX; + final int y = mGearLocation[1] - mParentLocation[1] + centerY; + mListener.onGearTouched(mParent, x, y); } } else { // Do nothing when the background is touched. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 340ebb444a86..85b14264837d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -361,9 +361,9 @@ public class NotificationStackScrollLayout extends ViewGroup } @Override - public void onGearTouched(ExpandableNotificationRow row) { + public void onGearTouched(ExpandableNotificationRow row, int x, int y) { if (mLongPressListener != null) { - mLongPressListener.onLongPress(row, 0, 0); + mLongPressListener.onLongPress(row, x, y); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5f40e5c38085..71a0f495eea1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15150,6 +15150,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean dumpFullDetails = false; boolean dumpDalvik = false; boolean dumpSummaryOnly = false; + boolean dumpUnreachable = false; boolean oomOnly = false; boolean isCompact = false; boolean localOnly = false; @@ -15178,6 +15179,8 @@ public final class ActivityManagerService extends ActivityManagerNative dumpSummaryOnly = true; } else if ("-S".equals(opt)) { dumpSwapPss = true; + } else if ("--unreachable".equals(opt)) { + dumpUnreachable = true; } else if ("--oom".equals(opt)) { oomOnly = true; } else if ("--local".equals(opt)) { @@ -15339,7 +15342,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { pw.flush(); thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails, - dumpDalvik, dumpSummaryOnly, innerArgs); + dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs); } catch (RemoteException e) { if (!isCheckinRequest) { pw.println("Got RemoteException!"); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 018164028fd0..bcdc800c5857 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1416,7 +1416,7 @@ class ActivityStarter { } intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); - } else if (!mStartActivity.intent.filterEquals(intentActivity.intent)) { + } else if (!intentActivity.task.isSameIntentResolution(mStartActivity)) { // In this case we are launching the root activity of the task, but with a // different intent. We should start a new instance on top. mAddingToTask = true; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 37a549a960a7..62275a98aba1 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -469,6 +469,19 @@ final class TaskRecord { setLockTaskAuth(); } + /** + * Return true if the input activity has the same intent resolution as the intent this task + * record is based on (normally the root activity intent). + */ + boolean isSameIntentResolution(ActivityRecord r) { + final Intent intent = new Intent(r.intent); + // Correct the activity intent for aliasing. The task record intent will always be based on + // the real activity that will be launched not the alias, so we need to use an intent with + // the component name pointing to the real activity not the alias in the activity record. + intent.setComponent(r.realActivity); + return this.intent.filterEquals(intent); + } + void setTaskToReturnTo(int taskToReturnTo) { mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE) ? HOME_ACTIVITY_TYPE : taskToReturnTo; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 60c3a35017d4..0252ea45c0b6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -769,7 +769,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_VALUE, Boolean.toString(disableContactsSearch)); out.endTag(null, TAG_DISABLE_CONTACTS_SEARCH); } - if (disableBluetoothContactSharing) { + if (!disableBluetoothContactSharing) { out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING); out.attribute(null, ATTR_VALUE, Boolean.toString(disableBluetoothContactSharing)); |