Merge changes from topic "sc_handles"
* changes:
Remove SurfaceControl#getHandle from JAVA apis 2/2
Remove SurfaceControl#getHandle from JAVA apis 1/2
diff --git a/api/test-current.txt b/api/test-current.txt
index 0127dfe..bf2730a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -318,10 +318,16 @@
}
public final class NotificationChannel implements android.os.Parcelable {
+ method public int getOriginalImportance();
+ method public boolean isBlockableSystem();
method public boolean isImportanceLockedByCriticalDeviceFunction();
method public boolean isImportanceLockedByOEM();
+ method public void setBlockableSystem(boolean);
+ method public void setDeleted(boolean);
+ method public void setFgServiceShown(boolean);
method public void setImportanceLockedByCriticalDeviceFunction(boolean);
method public void setImportanceLockedByOEM(boolean);
+ method public void setOriginalImportance(int);
}
public final class NotificationChannelGroup implements android.os.Parcelable {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 69ec831..3effd11 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,8 +15,6 @@
*/
package android.app;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -86,6 +84,7 @@
private static final String ATT_GROUP = "group";
private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
private static final String ATT_ALLOW_BUBBLE = "can_bubble";
+ private static final String ATT_ORIG_IMP = "orig_imp";
private static final String DELIMITER = ",";
/**
@@ -151,6 +150,7 @@
private String mName;
private String mDesc;
private int mImportance = DEFAULT_IMPORTANCE;
+ private int mOriginalImportance = DEFAULT_IMPORTANCE;
private boolean mBypassDnd;
private int mLockscreenVisibility = DEFAULT_VISIBILITY;
private Uri mSound = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -234,6 +234,7 @@
mBlockableSystem = in.readBoolean();
mAllowBubbles = in.readBoolean();
mImportanceLockedByOEM = in.readBoolean();
+ mOriginalImportance = in.readInt();
}
@Override
@@ -288,6 +289,7 @@
dest.writeBoolean(mBlockableSystem);
dest.writeBoolean(mAllowBubbles);
dest.writeBoolean(mImportanceLockedByOEM);
+ dest.writeInt(mOriginalImportance);
}
/**
@@ -307,6 +309,7 @@
/**
* @hide
*/
+ @TestApi
public void setFgServiceShown(boolean shown) {
mFgServiceShown = shown;
}
@@ -314,6 +317,7 @@
/**
* @hide
*/
+ @TestApi
public void setDeleted(boolean deleted) {
mDeleted = deleted;
}
@@ -322,6 +326,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public void setBlockableSystem(boolean blockableSystem) {
mBlockableSystem = blockableSystem;
}
@@ -641,6 +646,7 @@
/**
* @hide
*/
+ @TestApi
public boolean isBlockableSystem() {
return mBlockableSystem;
}
@@ -678,6 +684,22 @@
}
/**
+ * @hide
+ */
+ @TestApi
+ public int getOriginalImportance() {
+ return mOriginalImportance;
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
+ public void setOriginalImportance(int importance) {
+ mOriginalImportance = importance;
+ }
+
+ /**
* Returns whether the user has chosen the importance of this channel, either to affirm the
* initial selection from the app, or changed it to be higher or lower.
* @see #getImportance()
@@ -729,6 +751,7 @@
setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
setAllowBubbles(safeBool(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
+ setOriginalImportance(safeInt(parser, ATT_ORIG_IMP, DEFAULT_IMPORTANCE));
}
@Nullable
@@ -850,6 +873,9 @@
if (canBubble() != DEFAULT_ALLOW_BUBBLE) {
out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
}
+ if (getOriginalImportance() != DEFAULT_IMPORTANCE) {
+ out.attribute(null, ATT_ORIG_IMP, Integer.toString(getOriginalImportance()));
+ }
// mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
// truth and so aren't written to this xml file
@@ -896,6 +922,7 @@
record.put(ATT_GROUP, getGroup());
record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
record.put(ATT_ALLOW_BUBBLE, canBubble());
+ // TODO: original importance
return record;
}
@@ -1005,7 +1032,8 @@
&& Objects.equals(getGroup(), that.getGroup())
&& Objects.equals(getAudioAttributes(), that.getAudioAttributes())
&& mImportanceLockedByOEM == that.mImportanceLockedByOEM
- && mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp;
+ && mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp
+ && mOriginalImportance == that.mOriginalImportance;
}
@Override
@@ -1015,7 +1043,7 @@
getUserLockedFields(),
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
- mImportanceLockedByOEM, mImportanceLockedDefaultApp);
+ mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
}
@@ -1045,6 +1073,7 @@
+ ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ + ", mOriginalImp=" + mOriginalImportance
+ '}';
pw.println(prefix + output);
}
@@ -1073,6 +1102,7 @@
+ ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ + ", mOriginalImp=" + mOriginalImportance
+ '}';
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index bf0ef94..2c2c295 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1122,6 +1122,9 @@
if (limit > lineEnd) {
limit = lineEnd;
}
+ if (limit == start) {
+ continue;
+ }
level[limit - lineStart - 1] =
(byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
}
@@ -1220,8 +1223,8 @@
}
/**
- * Computes in linear time the results of calling
- * #getHorizontal for all offsets on a line.
+ * Computes in linear time the results of calling #getHorizontal for all offsets on a line.
+ *
* @param line The line giving the offsets we compute information for
* @param clamped Whether to clamp the results to the width of the layout
* @param primary Whether the results should be the primary or the secondary horizontal
@@ -1257,7 +1260,7 @@
TextLine.recycle(tl);
if (clamped) {
- for (int offset = 0; offset <= wid.length; ++offset) {
+ for (int offset = 0; offset < wid.length; ++offset) {
if (wid[offset] > mWidth) {
wid[offset] = mWidth;
}
diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index bc21722..5370645 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -21,10 +21,10 @@
import android.os.SystemClock;
import android.os.Trace;
-import java.util.ArrayDeque;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Deque;
import java.util.List;
/**
@@ -37,16 +37,37 @@
public class TimingsTraceLog {
// Debug boot time for every step if it's non-user build.
private static final boolean DEBUG_BOOT_TIME = !Build.IS_USER;
- private final Deque<Pair<String, Long>> mStartTimes =
- DEBUG_BOOT_TIME ? new ArrayDeque<>() : null;
+
+ // Maximum number of nested calls that are stored
+ private static final int MAX_NESTED_CALLS = 10;
+
+ private final String[] mStartNames;
+ private final long[] mStartTimes;
+
private final String mTag;
- private long mTraceTag;
- private long mThreadId;
+ private final long mTraceTag;
+ private final long mThreadId;
+ private final int mMaxNestedCalls;
+
+ private int mCurrentLevel = -1;
public TimingsTraceLog(String tag, long traceTag) {
+ this(tag, traceTag, DEBUG_BOOT_TIME ? MAX_NESTED_CALLS : -1);
+ }
+
+ @VisibleForTesting
+ public TimingsTraceLog(String tag, long traceTag, int maxNestedCalls) {
mTag = tag;
mTraceTag = traceTag;
mThreadId = Thread.currentThread().getId();
+ mMaxNestedCalls = maxNestedCalls;
+ if (maxNestedCalls > 0) {
+ mStartNames = new String[maxNestedCalls];
+ mStartTimes = new long[maxNestedCalls];
+ } else {
+ mStartNames = null;
+ mStartTimes = null;
+ }
}
/**
@@ -56,27 +77,41 @@
public void traceBegin(String name) {
assertSameThread();
Trace.traceBegin(mTraceTag, name);
- if (DEBUG_BOOT_TIME) {
- mStartTimes.push(Pair.create(name, SystemClock.elapsedRealtime()));
+
+ if (!DEBUG_BOOT_TIME) return;
+
+ if (mCurrentLevel + 1 >= mMaxNestedCalls) {
+ Slog.w(mTag, "not tracing duration of '" + name + "' because already reached "
+ + mMaxNestedCalls + " levels");
+ return;
}
+
+ mCurrentLevel++;
+ mStartNames[mCurrentLevel] = name;
+ mStartTimes[mCurrentLevel] = SystemClock.elapsedRealtime();
}
/**
* End tracing previously {@link #traceBegin(String) started} section.
- * Also {@link #logDuration logs} the duration.
+ *
+ * <p>Also {@link #logDuration logs} the duration.
*/
public void traceEnd() {
assertSameThread();
Trace.traceEnd(mTraceTag);
- if (!DEBUG_BOOT_TIME) {
- return;
- }
- if (mStartTimes.peek() == null) {
+
+ if (!DEBUG_BOOT_TIME) return;
+
+ if (mCurrentLevel < 0) {
Slog.w(mTag, "traceEnd called more times than traceBegin");
return;
}
- Pair<String, Long> event = mStartTimes.pop();
- logDuration(event.first, (SystemClock.elapsedRealtime() - event.second));
+
+ final String name = mStartNames[mCurrentLevel];
+ final long duration = SystemClock.elapsedRealtime() - mStartTimes[mCurrentLevel];
+ mCurrentLevel--;
+
+ logDuration(name, duration);
}
private void assertSameThread() {
@@ -89,7 +124,7 @@
}
/**
- * Log the duration so it can be parsed by external tools for performance reporting
+ * Logs a duration so it can be parsed by external tools for performance reporting.
*/
public void logDuration(String name, long timeMs) {
Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
@@ -105,10 +140,11 @@
*/
@NonNull
public final List<String> getUnfinishedTracesForDebug() {
- if (mStartTimes == null || mStartTimes.isEmpty()) return Collections.emptyList();
-
- final ArrayList<String> stack = new ArrayList<>(mStartTimes.size());
- mStartTimes.descendingIterator().forEachRemaining((pair) -> stack.add(pair.first));
- return stack;
+ if (mStartTimes == null || mCurrentLevel < 0) return Collections.emptyList();
+ final ArrayList<String> list = new ArrayList<>(mCurrentLevel + 1);
+ for (int i = 0; i <= mCurrentLevel; i++) {
+ list.add(mStartNames[i]);
+ }
+ return list;
}
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index be13710..d1ab7c99 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -84,7 +84,6 @@
private static native long nativeCopyFromSurfaceControl(long nativeObject);
private static native void nativeWriteToParcel(long nativeObject, Parcel out);
private static native void nativeRelease(long nativeObject);
- private static native void nativeDestroy(long nativeObject);
private static native void nativeDisconnect(long nativeObject);
private static native ScreenshotGraphicBuffer nativeScreenshot(IBinder displayToken,
@@ -931,19 +930,6 @@
}
/**
- * Release the local resources like {@link #release} but also
- * remove the Surface from the screen.
- * @hide
- */
- public void remove() {
- if (mNativeObject != 0) {
- nativeDestroy(mNativeObject);
- mNativeObject = 0;
- }
- mCloseGuard.close();
- }
-
- /**
* Disconnect any client still connected to the surface.
* @hide
*/
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f765471..f661e06 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -200,6 +200,7 @@
private int mPendingReportDraws;
private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
+ private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
public SurfaceView(Context context) {
this(context, null);
@@ -339,7 +340,7 @@
updateSurface();
if (mSurfaceControl != null) {
- mSurfaceControl.remove();
+ mTmpTransaction.remove(mSurfaceControl).apply();
}
mSurfaceControl = null;
@@ -534,13 +535,14 @@
private void releaseSurfaces() {
if (mSurfaceControl != null) {
- mSurfaceControl.remove();
+ mTmpTransaction.remove(mSurfaceControl);
mSurfaceControl = null;
}
if (mBackgroundControl != null) {
- mBackgroundControl.remove();
+ mTmpTransaction.remove(mBackgroundControl);
mBackgroundControl = null;
}
+ mTmpTransaction.apply();
}
/** @hide */
@@ -849,7 +851,7 @@
}
if (mDeferredDestroySurfaceControl != null) {
- mDeferredDestroySurfaceControl.remove();
+ mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
mDeferredDestroySurfaceControl = null;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6b30f5e..fa1c05d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1631,7 +1631,7 @@
mSurfaceSession = null;
if (mBoundsSurfaceControl != null) {
- mBoundsSurfaceControl.remove();
+ mTransaction.remove(mBoundsSurfaceControl).apply();
mBoundsSurface.release();
mBoundsSurfaceControl = null;
}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index ccafa64..d3c6972 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -1035,7 +1035,7 @@
// Destroy the renderer. This will not proceed until pending frame callbacks complete.
mRenderer.destroy();
mSurface.destroy();
- mSurfaceControl.remove();
+ new SurfaceControl.Transaction().remove(mSurfaceControl).apply();
mSurfaceSession.kill();
mHandler.removeCallbacks(mMagnifierUpdater);
if (mBitmap != null) {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 454fe3c..0e7c1d4 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -196,6 +196,11 @@
public static final String ASSIST_TAP_PASSTHROUGH = "assist_tap_passthrough";
/**
+ * (bool) Whether to show handles when taught.
+ */
+ public static final String ASSIST_HANDLES_SHOW_WHEN_TAUGHT = "assist_handles_show_when_taught";
+
+ /**
* (bool) Whether to use the new BrightLineFalsingManager.
*/
public static final String BRIGHTLINE_FALSING_MANAGER_ENABLED =
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 53a35be..78dd1aa 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -217,12 +217,6 @@
ctrl->decStrong((void *)nativeCreate);
}
-static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
- sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
- ctrl->destroy();
- ctrl->decStrong((void *)nativeCreate);
-}
-
static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
if (ctrl != NULL) {
@@ -1278,8 +1272,6 @@
(void*)nativeWriteToParcel },
{"nativeRelease", "(J)V",
(void*)nativeRelease },
- {"nativeDestroy", "(J)V",
- (void*)nativeDestroy },
{"nativeDisconnect", "(J)V",
(void*)nativeDisconnect },
{"nativeCreateTransaction", "()J",
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 990161a..93a6b15 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -743,6 +743,9 @@
assertPrimaryIsTrailingPrevious(
RTL + LRI + RTL + LTR + PDI + RTL,
new boolean[]{false, false, true, false, false, false, false});
+ assertPrimaryIsTrailingPrevious(
+ "",
+ new boolean[]{false});
}
}
diff --git a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
deleted file mode 100644
index f76471c..0000000
--- a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 android.util;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Trace;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link TimingsTraceLog}.
- *
- * <p>Usage: {@code atest FrameworksCoreTests:android.util.TimingsTraceLogTest}
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TimingsTraceLogTest {
-
- @Test
- public void testDifferentThreads() throws Exception {
- TimingsTraceLog log = new TimingsTraceLog("TEST", Trace.TRACE_TAG_APP);
- // Should be able to log on the same thread
- log.traceBegin("test");
- log.traceEnd();
- final List<String> errors = new ArrayList<>();
- // Calling from a different thread should fail
- Thread t = new Thread(() -> {
- try {
- log.traceBegin("test");
- errors.add("traceBegin should fail on a different thread");
- } catch (IllegalStateException expected) {
- }
- try {
- log.traceEnd();
- errors.add("traceEnd should fail on a different thread");
- } catch (IllegalStateException expected) {
- }
- // Verify that creating a new log will work
- TimingsTraceLog log2 = new TimingsTraceLog("TEST", Trace.TRACE_TAG_APP);
- log2.traceBegin("test");
- log2.traceEnd();
-
- });
- t.start();
- t.join();
- assertThat(errors).isEmpty();
- }
-
- @Test
- public void testGetUnfinishedTracesForDebug() {
- TimingsTraceLog log = new TimingsTraceLog("TEST", Trace.TRACE_TAG_APP);
- assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
-
- log.traceBegin("One");
- assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
-
- log.traceBegin("Two");
- assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
-
- log.traceEnd();
- assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
-
- log.traceEnd();
- assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
- }
-}
diff --git a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
new file mode 100644
index 0000000..5dc44d2
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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 android.util;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceLog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingCoreTests:android.util.TimingsTraceLogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceLogTest {
+
+ private static final String TAG = "TEST";
+
+ private MockitoSession mSession;
+
+ @Before
+ public final void startMockSession() {
+ mSession = mockitoSession()
+ .spyStatic(Slog.class)
+ .spyStatic(Trace.class)
+ .startMocking();
+ }
+
+ @After
+ public final void finishMockSession() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testDifferentThreads() throws Exception {
+ TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP);
+ // Should be able to log on the same thread
+ log.traceBegin("test");
+ log.traceEnd();
+ final List<String> errors = new ArrayList<>();
+ // Calling from a different thread should fail
+ Thread t = new Thread(() -> {
+ try {
+ log.traceBegin("test");
+ errors.add("traceBegin should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ log.traceEnd();
+ errors.add("traceEnd should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ // Verify that creating a new log will work
+ TimingsTraceLog log2 = new TimingsTraceLog(TAG, TRACE_TAG_APP);
+ log2.traceBegin("test");
+ log2.traceEnd();
+
+ });
+ t.start();
+ t.join();
+ assertThat(errors).isEmpty();
+ }
+
+ @Test
+ public void testGetUnfinishedTracesForDebug() {
+ TimingsTraceLog log = new TimingsTraceLog("TEST", Trace.TRACE_TAG_APP);
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+ log.traceBegin("One");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceBegin("Two");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+ }
+
+ @Test
+ public void testLogDuration() throws Exception {
+ TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
+ log.logDuration("logro", 42);
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+ }
+
+ @Test
+ public void testOneLevel() throws Exception {
+ TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
+ log.traceBegin("test");
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+ }
+
+ @Test
+ public void testMultipleLevels() throws Exception {
+ TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_APP, 10);
+ log.traceBegin("L1");
+ log.traceBegin("L2");
+ log.traceEnd();
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ }
+
+ @Test
+ public void testTooManyLevels() throws Exception {
+ TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_APP, 2);
+
+ log.traceBegin("L1"); // ok
+ log.traceBegin("L2"); // ok
+ log.traceBegin("L3"); // logging ignored ( > 2)
+
+ log.traceEnd();
+ log.traceEnd();
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
+
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+ never());
+
+ verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
+ + "because already reached 2 levels"));
+ }
+
+ @Test
+ public void testEndNoBegin() throws Exception {
+ TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP);
+ log.traceEnd();
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+ verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+ }
+}
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 5133bae..3b8caeb 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -27,7 +27,7 @@
namespace skiapipeline {
StartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data)
- : mEndChildIndex(0), mBeginChildIndex(data->mChildNodes.size()), mDisplayList(data) {}
+ : mEndChildIndex(-1), mBeginChildIndex(data->mChildNodes.size()), mDisplayList(data) {}
void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
if (mChildren.empty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 0af333e..f9ddeae 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -67,6 +67,7 @@
private static final boolean DEFAULT_SUPPRESS_ON_LOCKSCREEN = false;
private static final boolean DEFAULT_SUPPRESS_ON_LAUNCHER = false;
private static final boolean DEFAULT_SUPPRESS_ON_APPS = true;
+ private static final boolean DEFAULT_SHOW_WHEN_TAUGHT = false;
private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
@@ -309,7 +310,7 @@
return;
}
- if (mIsDozing || mIsNavBarHidden || mOnLockscreen) {
+ if (mIsDozing || mIsNavBarHidden || mOnLockscreen || !getShowWhenTaught()) {
mAssistHandleCallbacks.hide();
} else if (justUnlocked) {
long currentEpochDay = LocalDate.now().toEpochDay();
@@ -429,6 +430,12 @@
DEFAULT_SUPPRESS_ON_APPS);
}
+ private boolean getShowWhenTaught() {
+ return mPhenotypeHelper.getBoolean(
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_WHEN_TAUGHT,
+ DEFAULT_SHOW_WHEN_TAUGHT);
+ }
+
@Override
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "Current AssistHandleReminderExpBehavior State:");
@@ -480,5 +487,9 @@
+ SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_APPS
+ "="
+ getSuppressOnApps());
+ pw.println(prefix + " "
+ + SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_WHEN_TAUGHT
+ + "="
+ + getShowWhenTaught());
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index d6657f1..8415272 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -31,6 +31,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
@@ -83,6 +84,7 @@
mInteractionConnections = new SparseArray<>();
private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>();
+ private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>();
private List<AccessibilityWindowInfo> mWindows;
private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
@@ -173,25 +175,133 @@
}
/**
- * Callbacks from from window manager when there's an accessibility change in windows.
+ * Callbacks from window manager when there's an accessibility change in windows.
*
+ * @param forceSend Send the windows for accessibility even if they haven't changed.
* @param windows The windows of current display for accessibility.
*/
@Override
- public void onWindowsForAccessibilityChanged(@NonNull List<WindowInfo> windows) {
+ public void onWindowsForAccessibilityChanged(boolean forceSend,
+ @NonNull List<WindowInfo> windows) {
synchronized (mLock) {
if (DEBUG) {
Slog.i(LOG_TAG, "Windows changed: " + windows);
}
- // Let the policy update the focused and active windows.
- updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
-
- // Someone may be waiting for the windows - advertise it.
- mLock.notifyAll();
+ if (shouldUpdateWindowsLocked(forceSend, windows)) {
+ cacheWindows(windows);
+ // Let the policy update the focused and active windows.
+ updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
+ // Someone may be waiting for the windows - advertise it.
+ mLock.notifyAll();
+ }
}
}
+ private boolean shouldUpdateWindowsLocked(boolean forceSend,
+ @NonNull List<WindowInfo> windows) {
+ if (forceSend) {
+ return true;
+ }
+
+ final int windowCount = windows.size();
+ // We computed the windows and if they changed notify the client.
+ if (mCachedWindowInfos.size() != windowCount) {
+ // Different size means something changed.
+ return true;
+ } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) {
+ // Since we always traverse windows from high to low layer
+ // the old and new windows at the same index should be the
+ // same, otherwise something changed.
+ for (int i = 0; i < windowCount; i++) {
+ WindowInfo oldWindow = mCachedWindowInfos.get(i);
+ WindowInfo newWindow = windows.get(i);
+ // We do not care for layer changes given the window
+ // order does not change. This brings no new information
+ // to the clients.
+ if (windowChangedNoLayer(oldWindow, newWindow)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void cacheWindows(List<WindowInfo> windows) {
+ final int oldWindowCount = mCachedWindowInfos.size();
+ for (int i = oldWindowCount - 1; i >= 0; i--) {
+ mCachedWindowInfos.remove(i).recycle();
+ }
+ final int newWindowCount = windows.size();
+ for (int i = 0; i < newWindowCount; i++) {
+ WindowInfo newWindow = windows.get(i);
+ mCachedWindowInfos.add(WindowInfo.obtain(newWindow));
+ }
+ }
+
+ private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
+ if (oldWindow == newWindow) {
+ return false;
+ }
+ if (oldWindow == null) {
+ return true;
+ }
+ if (newWindow == null) {
+ return true;
+ }
+ if (oldWindow.type != newWindow.type) {
+ return true;
+ }
+ if (oldWindow.focused != newWindow.focused) {
+ return true;
+ }
+ if (oldWindow.token == null) {
+ if (newWindow.token != null) {
+ return true;
+ }
+ } else if (!oldWindow.token.equals(newWindow.token)) {
+ return true;
+ }
+ if (oldWindow.parentToken == null) {
+ if (newWindow.parentToken != null) {
+ return true;
+ }
+ } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
+ return true;
+ }
+ if (oldWindow.activityToken == null) {
+ if (newWindow.activityToken != null) {
+ return true;
+ }
+ } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
+ return true;
+ }
+ if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
+ return true;
+ }
+ if (oldWindow.childTokens != null && newWindow.childTokens != null
+ && !oldWindow.childTokens.equals(newWindow.childTokens)) {
+ return true;
+ }
+ if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+ return true;
+ }
+ if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+ return true;
+ }
+ if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) {
+ return true;
+ }
+ if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) {
+ return true;
+ }
+ if (oldWindow.displayId != newWindow.displayId) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Start tracking windows changes from window manager.
*/
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f451a09..4222fc1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -272,6 +272,7 @@
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.provider.DeviceConfig.Properties;
import android.server.ServerProtoEnums;
import android.sysprop.VoldProperties;
import android.text.TextUtils;
@@ -356,6 +357,7 @@
import com.android.server.utils.PriorityDump;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerService;
@@ -392,6 +394,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
@@ -861,6 +864,51 @@
*/
final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
+ /**
+ * Depth of overlapping activity-start PSS deferral notes
+ */
+ private final AtomicInteger mActivityStartingNesting = new AtomicInteger(0);
+
+ private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
+ new ActivityMetricsLaunchObserver() {
+ @Override
+ public void onActivityLaunched(byte[] activity, int temperature) {
+ // This is safe to force to the head of the queue because it relies only
+ // on refcounting to track begin/end of deferrals, not on actual
+ // message ordering. We don't care *what* activity is being
+ // launched; only that we're doing so.
+ if (mPssDeferralTime > 0) {
+ final Message msg = mBgHandler.obtainMessage(DEFER_PSS_MSG);
+ mBgHandler.sendMessageAtFrontOfQueue(msg);
+ }
+ }
+
+ // The other observer methods are unused
+ @Override
+ public void onIntentStarted(Intent intent) {
+ }
+
+ @Override
+ public void onIntentFailed() {
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(byte[] abortingActivity) {
+ }
+
+ @Override
+ public void onActivityLaunchFinished(byte[] finalActivity) {
+ }
+ };
+
+ /**
+ * How long we defer PSS gathering while activities are starting, in milliseconds.
+ * This is adjustable via DeviceConfig. If it is zero or negative, no PSS deferral
+ * is done.
+ */
+ private volatile long mPssDeferralTime = 0;
+ private static final String ACTIVITY_START_PSS_DEFER_CONFIG = "activity_start_pss_defer";
+
private boolean mBinderTransactionTrackingEnabled = false;
/**
@@ -874,6 +922,20 @@
*/
boolean mFullPssPending = false;
+ /**
+ * Observe DeviceConfig changes to the PSS calculation interval
+ */
+ private final DeviceConfig.OnPropertiesChangedListener mPssDelayConfigListener =
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(Properties properties) {
+ mPssDeferralTime = properties.getLong(ACTIVITY_START_PSS_DEFER_CONFIG, 0);
+ if (DEBUG_PSS) {
+ Slog.d(TAG_PSS, "Activity-start PSS delay now "
+ + mPssDeferralTime + " ms");
+ }
+ }
+ };
/**
* This is for verifying the UID report flow.
@@ -1838,6 +1900,8 @@
}
static final int COLLECT_PSS_BG_MSG = 1;
+ static final int DEFER_PSS_MSG = 2;
+ static final int STOP_DEFERRING_PSS_MSG = 3;
final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
@Override
@@ -1945,6 +2009,30 @@
}
} while (true);
}
+
+ case DEFER_PSS_MSG: {
+ deferPssForActivityStart();
+ } break;
+
+ case STOP_DEFERRING_PSS_MSG: {
+ final int nesting = mActivityStartingNesting.decrementAndGet();
+ if (nesting <= 0) {
+ if (DEBUG_PSS) {
+ Slog.d(TAG_PSS, "PSS activity start deferral interval ended; now "
+ + nesting);
+ }
+ if (nesting < 0) {
+ Slog.wtf(TAG, "Activity start nesting undercount!");
+ mActivityStartingNesting.incrementAndGet();
+ }
+ } else {
+ if (DEBUG_PSS) {
+ Slog.d(TAG_PSS, "Still deferring PSS, nesting=" + nesting);
+ }
+ }
+ }
+ break;
+
}
}
};
@@ -8832,6 +8920,12 @@
NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
mHiddenApiBlacklist.registerObserver();
+ final long pssDeferralMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ACTIVITY_START_PSS_DEFER_CONFIG, 0L);
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ActivityThread.currentApplication().getMainExecutor(),
+ mPssDelayConfigListener);
+
synchronized (this) {
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
@@ -8848,6 +8942,7 @@
com.android.internal.R.bool.config_multiuserDelayUserDataLocking);
mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
+ mPssDeferralTime = pssDeferralMs;
}
}
@@ -8921,6 +9016,10 @@
mAtmInternal.updateTopComponentForFactoryTest();
t.traceEnd();
+ t.traceBegin("registerActivityLaunchObserver");
+ mAtmInternal.getLaunchObserverRegistry().registerLaunchObserver(mActivityLaunchObserver);
+ t.traceEnd();
+
t.traceBegin("watchDeviceProvisioning");
watchDeviceProvisioning(mContext);
t.traceEnd();
@@ -16177,7 +16276,13 @@
return false;
}
if (mPendingPssProcesses.size() == 0) {
- mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+ final long deferral = (mPssDeferralTime > 0 && mActivityStartingNesting.get() > 0)
+ ? mPssDeferralTime : 0;
+ if (DEBUG_PSS && deferral > 0) {
+ Slog.d(TAG_PSS, "requestPssLocked() deferring PSS request by "
+ + deferral + " ms");
+ }
+ mBgHandler.sendEmptyMessageDelayed(COLLECT_PSS_BG_MSG, deferral);
}
if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of: " + proc);
proc.pssProcState = procState;
@@ -16187,6 +16292,30 @@
}
/**
+ * Re-defer a posted PSS collection pass, if one exists. Assumes deferral is
+ * currently active policy when called.
+ */
+ private void deferPssIfNeededLocked() {
+ if (mPendingPssProcesses.size() > 0) {
+ mBgHandler.removeMessages(COLLECT_PSS_BG_MSG);
+ mBgHandler.sendEmptyMessageDelayed(COLLECT_PSS_BG_MSG, mPssDeferralTime);
+ }
+ }
+
+ private void deferPssForActivityStart() {
+ synchronized (ActivityManagerService.this) {
+ if (mPssDeferralTime > 0) {
+ if (DEBUG_PSS) {
+ Slog.d(TAG_PSS, "Deferring PSS collection for activity start");
+ }
+ deferPssIfNeededLocked();
+ mActivityStartingNesting.getAndIncrement();
+ mBgHandler.sendEmptyMessageDelayed(STOP_DEFERRING_PSS_MSG, mPssDeferralTime);
+ }
+ }
+ }
+
+ /**
* Schedule PSS collection of all processes.
*/
void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 36d9c0e..7be1b8a 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -634,13 +634,8 @@
if (mSurfaceControl != null) {
mSurfaceLayout.dispose();
mSurfaceLayout = null;
- SurfaceControl.openTransaction();
- try {
- mSurfaceControl.remove();
- mSurface.release();
- } finally {
- SurfaceControl.closeTransaction();
- }
+ new Transaction().remove(mSurfaceControl).apply();
+ mSurface.release();
mSurfaceControl = null;
mSurfaceVisible = false;
mSurfaceAlpha = 0f;
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7b45a1b..92ac1d4 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -17,6 +17,7 @@
package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -686,6 +687,11 @@
}
}
+ if (existing.getOriginalImportance() == IMPORTANCE_UNSPECIFIED) {
+ existing.setOriginalImportance(channel.getImportance());
+ needsPolicyFileChange = true;
+ }
+
updateConfig();
return needsPolicyFileChange;
}
@@ -719,7 +725,7 @@
if (!r.showBadge) {
channel.setShowBadge(false);
}
-
+ channel.setOriginalImportance(channel.getImportance());
r.channels.put(channel.getId(), channel);
if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
updateChannelsBypassingDnd(mContext.getUserId());
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 6b7187e..bace7e3 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -43,9 +43,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -907,7 +905,7 @@
}
public void releaseSurface() {
- mSurfaceControl.remove();
+ mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
mSurface.release();
}
@@ -1036,12 +1034,9 @@
private static final boolean DEBUG = false;
- private final SparseArray<WindowState> mTempWindowStates =
- new SparseArray<WindowState>();
+ private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();
- private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
-
- private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
+ private final Set<IBinder> mTempBinderSet = new ArraySet<>();
private final RectF mTempRectF = new RectF();
@@ -1098,8 +1093,7 @@
Slog.i(LOG_TAG, "computeChangedWindows()");
}
- boolean windowsChanged = false;
- List<WindowInfo> windows = new ArrayList<WindowInfo>();
+ List<WindowInfo> windows = new ArrayList<>();
synchronized (mService.mGlobalLock) {
// Do not send the windows if there is no current focus as
@@ -1169,46 +1163,9 @@
visibleWindows.clear();
addedWindows.clear();
-
- if (!forceSend) {
- // We computed the windows and if they changed notify the client.
- if (mOldWindows.size() != windows.size()) {
- // Different size means something changed.
- windowsChanged = true;
- } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
- // Since we always traverse windows from high to low layer
- // the old and new windows at the same index should be the
- // same, otherwise something changed.
- for (int i = 0; i < windowCount; i++) {
- WindowInfo oldWindow = mOldWindows.get(i);
- WindowInfo newWindow = windows.get(i);
- // We do not care for layer changes given the window
- // order does not change. This brings no new information
- // to the clients.
- if (windowChangedNoLayer(oldWindow, newWindow)) {
- windowsChanged = true;
- break;
- }
- }
- }
- }
-
- if (forceSend || windowsChanged) {
- cacheWindows(windows);
- }
}
- // Now we do not hold the lock, so send the windows over.
- if (forceSend || windowsChanged) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Windows changed or force sending:" + windows);
- }
- mCallback.onWindowsForAccessibilityChanged(windows);
- } else {
- if (DEBUG) {
- Log.i(LOG_TAG, "No windows changed.");
- }
- }
+ mCallback.onWindowsForAccessibilityChanged(forceSend, windows);
// Recycle the windows as we do not need them.
clearAndRecycleWindows(windows);
@@ -1313,67 +1270,6 @@
tokenOut.add(window.token);
}
- private void cacheWindows(List<WindowInfo> windows) {
- final int oldWindowCount = mOldWindows.size();
- for (int i = oldWindowCount - 1; i >= 0; i--) {
- mOldWindows.remove(i).recycle();
- }
- final int newWindowCount = windows.size();
- for (int i = 0; i < newWindowCount; i++) {
- WindowInfo newWindow = windows.get(i);
- mOldWindows.add(WindowInfo.obtain(newWindow));
- }
- }
-
- private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
- if (oldWindow == newWindow) {
- return false;
- }
- if (oldWindow == null) {
- return true;
- }
- if (newWindow == null) {
- return true;
- }
- if (oldWindow.type != newWindow.type) {
- return true;
- }
- if (oldWindow.focused != newWindow.focused) {
- return true;
- }
- if (oldWindow.token == null) {
- if (newWindow.token != null) {
- return true;
- }
- } else if (!oldWindow.token.equals(newWindow.token)) {
- return true;
- }
- if (oldWindow.parentToken == null) {
- if (newWindow.parentToken != null) {
- return true;
- }
- } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
- return true;
- }
- if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
- return true;
- }
- if (oldWindow.childTokens != null && newWindow.childTokens != null
- && !oldWindow.childTokens.equals(newWindow.childTokens)) {
- return true;
- }
- if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
- return true;
- }
- if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
- return true;
- }
- if (oldWindow.displayId != newWindow.displayId) {
- return true;
- }
- return false;
- }
-
private static void clearAndRecycleWindows(List<WindowInfo> windows) {
final int windowCount = windows.size();
for (int i = windowCount - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 84ba5ca9..7fc17e1 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -97,6 +97,7 @@
final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
final boolean mForceDefaultOrientation;
+ private final TransactionFactory mTransactionFactory;
public void printTo(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("Outer: "); mOuterRect.printShortString(pw);
@@ -111,11 +112,12 @@
}
}
- public BlackFrame(SurfaceControl.Transaction t,
- Rect outer, Rect inner, int layer, DisplayContent dc,
- boolean forceDefaultOrientation) throws OutOfResourcesException {
+ public BlackFrame(TransactionFactory factory, SurfaceControl.Transaction t, Rect outer,
+ Rect inner, int layer, DisplayContent dc, boolean forceDefaultOrientation)
+ throws OutOfResourcesException {
boolean success = false;
+ mTransactionFactory = factory;
mForceDefaultOrientation = forceDefaultOrientation;
// TODO: Why do we use 4 surfaces instead of just one big one behind the screenshot?
@@ -149,14 +151,16 @@
public void kill() {
if (mBlackSurfaces != null) {
+ SurfaceControl.Transaction t = mTransactionFactory.make();
for (int i=0; i<mBlackSurfaces.length; i++) {
if (mBlackSurfaces[i] != null) {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" BLACK " + mBlackSurfaces[i].surface + ": DESTROY");
- mBlackSurfaces[i].surface.remove();
+ t.remove(mBlackSurfaces[i].surface);
mBlackSurfaces[i] = null;
}
}
+ t.apply();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4dcb58a..57ed92d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4554,13 +4554,15 @@
.show(mSplitScreenDividerAnchor);
scheduleAnimation();
} else {
- mAppAnimationLayer.remove();
+ mWmService.mTransactionFactory.make()
+ .remove(mAppAnimationLayer)
+ .remove(mBoostedAppAnimationLayer)
+ .remove(mHomeAppAnimationLayer)
+ .remove(mSplitScreenDividerAnchor)
+ .apply();
mAppAnimationLayer = null;
- mBoostedAppAnimationLayer.remove();
mBoostedAppAnimationLayer = null;
- mHomeAppAnimationLayer.remove();
mHomeAppAnimationLayer = null;
- mSplitScreenDividerAnchor.remove();
mSplitScreenDividerAnchor = null;
}
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index c3ea72f..bb035d5 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -261,7 +261,7 @@
public void remove() {
if (mSurface != null) {
- mSurface.remove();
+ new SurfaceControl.Transaction().remove(mSurface).apply();
mSurface = null;
}
if (mInputInterceptor != null) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index b90d602..fe4c9a4 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -557,7 +557,7 @@
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mCustomBlackFrame = new BlackFrame(t, outer, inner,
+ mCustomBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false);
mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
@@ -588,7 +588,7 @@
mOriginalWidth*2, mOriginalHeight*2);
inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
}
- mExitingBlackFrame = new BlackFrame(t, outer, inner,
+ mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation);
mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
@@ -601,7 +601,7 @@
Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
finalWidth*2, finalHeight*2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
- mEnteringBlackFrame = new BlackFrame(t, outer, inner,
+ mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
@@ -639,7 +639,7 @@
if (SHOW_TRANSACTIONS ||
SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" FREEZE " + mSurfaceControl + ": DESTROY");
- mSurfaceControl.remove();
+ mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
mSurfaceControl = null;
}
if (mCustomBlackFrame != null) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0798c59..ddf25e6 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1007,7 +1007,7 @@
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
if (mAnimationBackgroundSurface != null) {
- mAnimationBackgroundSurface.remove();
+ mWmService.mTransactionFactory.make().remove(mAnimationBackgroundSurface).apply();
mAnimationBackgroundSurface = null;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 40bec14..6910ce9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -51,9 +51,10 @@
/**
* Called when the windows for accessibility changed.
*
+ * @param forceSend Send the windows for accessibility even if they haven't changed.
* @param windows The windows for accessibility.
*/
- public void onWindowsForAccessibilityChanged(List<WindowInfo> windows);
+ void onWindowsForAccessibilityChanged(boolean forceSend, List<WindowInfo> windows);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 264eeda..2bf24f6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7694,7 +7694,7 @@
private void onPointerDownOutsideFocusLocked(IBinder touchedToken) {
final WindowState touchedWindow = windowForClientLocked(null, touchedToken, false);
- if (touchedWindow == null) {
+ if (touchedWindow == null || !touchedWindow.canReceiveKeys()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 836460f..a616e06 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -161,7 +161,7 @@
}
try {
if (mSurfaceControl != null) {
- mSurfaceControl.remove();
+ mTmpTransaction.remove(mSurfaceControl).apply();
}
} catch (RuntimeException e) {
Slog.w(TAG, "Error destroying surface in: " + this, e);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 04ca40e..22408cc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -70,6 +70,8 @@
*/
public class AccessibilityWindowManagerTest {
private static final String PACKAGE_NAME = "com.android.server.accessibility";
+ private static final boolean FORCE_SEND = true;
+ private static final boolean SEND_ON_WINDOW_CHANGES = false;
private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
private static final int NUM_GLOBAL_WINDOWS = 4;
private static final int NUM_APP_WINDOWS = 4;
@@ -122,7 +124,7 @@
mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true;
// Turn on windows tracking, and update window info
mA11yWindowManager.startTrackingWindows();
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
assertEquals(mA11yWindowManager.getWindowListLocked().size(),
mWindowInfos.size());
@@ -169,16 +171,16 @@
@Test
public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- WindowInfo focuedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
+ WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, focuedWindowInfo.token));
+ USER_SYSTEM_ID, focusedWindowInfo.token));
- focuedWindowInfo.focused = false;
- focuedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
- focuedWindowInfo.focused = true;
+ focusedWindowInfo.focused = false;
+ focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
+ focusedWindowInfo.focused = true;
mA11yWindowManager.onTouchInteractionStart();
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
}
@@ -208,6 +210,52 @@
}
@Test
+ public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+ final WindowInfo windowInfo = mWindowInfos.get(0);
+ final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
+ windowInfo.layer += 1;
+
+ mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
+ assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
+ }
+
+ @Test
+ public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
+ final WindowInfo windowInfo = mWindowInfos.get(0);
+ final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
+ windowInfo.layer += 1;
+
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+ assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
+ }
+
+ @Test
+ public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
+ throws RemoteException {
+ final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0);
+ final IWindow token = addAccessibilityInteractionConnection(true);
+ final WindowInfo windowInfo = WindowInfo.obtain();
+ windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
+ windowInfo.token = token.asBinder();
+ windowInfo.layer = 0;
+ windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ mWindowInfos.set(0, windowInfo);
+
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+ assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0));
+ }
+
+ @Test
+ public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
+ final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
+ final WindowInfo windowInfo = mWindowInfos.get(0);
+ focusedWindowInfo.focused = false;
+ windowInfo.focused = true;
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+ assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused());
+ }
+
+ @Test
public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
for (int i = 0; i < NUM_OF_WINDOWS; i++) {
final int windowId = mA11yWindowTokens.keyAt(i);
@@ -264,7 +312,7 @@
windowInfo = mWindowInfos.get(1);
windowInfo.boundsInScreen.set(0, SCREEN_HEIGHT / 2,
SCREEN_WIDTH, SCREEN_HEIGHT);
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
@@ -291,7 +339,7 @@
windowInfo = mWindowInfos.get(1);
windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -309,7 +357,7 @@
windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
windowInfo = mWindowInfos.get(1);
windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
@@ -498,7 +546,7 @@
public void getPictureInPictureWindow_shouldNotNull() {
assertNull(mA11yWindowManager.getPictureInPictureWindow());
mWindowInfos.get(1).inPictureInPicture = true;
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertNotNull(mA11yWindowManager.getPictureInPictureWindow());
}
@@ -511,7 +559,7 @@
mA11yWindowManager.getConnectionLocked(
USER_SYSTEM_ID, outsideWindowId).getRemote();
mWindowInfos.get(0).hasFlagWatchOutsideTouch = true;
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
verify(mockRemoteConnection).notifyOutsideTouch();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
deleted file mode 100644
index 1408749..0000000
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.server.notification;
-
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNull;
-
-import android.app.NotificationChannel;
-import android.net.Uri;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Xml;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.FastXmlSerializer;
-import com.android.server.UiServiceTestCase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NotificationChannelTest extends UiServiceTestCase {
-
- @Test
- public void testWriteToParcel() {
- NotificationChannel channel =
- new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
- Parcel parcel = Parcel.obtain();
- channel.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- NotificationChannel channel1 = NotificationChannel.CREATOR.createFromParcel(parcel);
- assertEquals(channel, channel1);
- }
-
- @Test
- public void testSystemBlockable() {
- NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
- assertEquals(false, channel.isBlockableSystem());
- channel.setBlockableSystem(true);
- assertEquals(true, channel.isBlockableSystem());
- }
-
- @Test
- public void testEmptyVibration_noException() throws Exception {
- NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
- channel.setVibrationPattern(new long[0]);
-
- XmlSerializer serializer = new FastXmlSerializer();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
- channel.writeXml(serializer);
- }
-
- @Test
- public void testBackupEmptySound() throws Exception {
- NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
- channel.setSound(Uri.EMPTY, null);
-
- XmlSerializer serializer = new FastXmlSerializer();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
- channel.writeXmlForBackup(serializer, getContext());
-
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
- restored.populateFromXmlForRestore(parser, getContext());
-
- assertNull(restored.getSound());
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 1ed1639..9ecf198 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -131,6 +131,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.Xml;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
@@ -138,6 +139,7 @@
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiServiceTestCase;
@@ -156,9 +158,13 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
@@ -3060,6 +3066,25 @@
}
@Test
+ public void testBackupEmptySound() throws Exception {
+ NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ channel.setSound(Uri.EMPTY, null);
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ channel.writeXmlForBackup(serializer, getContext());
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ restored.populateFromXmlForRestore(parser, getContext());
+
+ assertNull(restored.getSound());
+ }
+
+ @Test
public void testBackup() throws Exception {
int systemChecks = mService.countSystemChecks;
mBinderService.getBackupPayload(1);
@@ -3067,6 +3092,17 @@
}
@Test
+ public void testEmptyVibration_noException() throws Exception {
+ NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ channel.setVibrationPattern(new long[0]);
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ channel.writeXml(serializer);
+ }
+
+ @Test
public void updateUriPermissions_update() throws Exception {
NotificationChannel c = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 292a05b..a98f79c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -169,7 +169,7 @@
mDimmer.updateDims(mTransaction, new Rect());
verify(mTransaction).show(getDimLayer());
- verify(dimLayer, never()).remove();
+ verify(mTransaction, never()).remove(dimLayer);
}
@Test
@@ -231,7 +231,7 @@
mDimmer.updateDims(mTransaction, new Rect());
verify(mTransaction).show(dimLayer);
- verify(dimLayer, never()).remove();
+ verify(mTransaction, never()).remove(dimLayer);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index b93c994..acfc2ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -114,16 +114,12 @@
@Test
public void testAddChildSetsSurfacePosition() {
try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
-
- final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
- mWm.mTransactionFactory = () -> transaction;
-
WindowContainer child = new WindowContainer(mWm);
child.setBounds(1, 1, 10, 10);
- verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
+ verify(mTransaction, never()).setPosition(any(), anyFloat(), anyFloat());
top.addChild(child, 0);
- verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
+ verify(mTransaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
}
}
diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch
index 643df1b..92a31c3 100755
--- a/startop/scripts/app_startup/run_app_with_prefetch
+++ b/startop/scripts/app_startup/run_app_with_prefetch
@@ -101,6 +101,15 @@
esac
shift
done
+
+ if [[ $when == "aot" ]]; then
+ # TODO: re-implement aot later for experimenting.
+ echo "Error: --when $when is unsupported" >&2
+ exit 1
+ elif [[ $when != "jit" ]]; then
+ echo "Error: --when must be one of (aot jit)." >&2
+ exit 1
+ fi
}
echo_to_output_file() {
@@ -212,6 +221,12 @@
local the_when="$1" # user: aot, jit
local the_mode="$2" # warm, cold, fadvise, mlock, etc.
+ # iorapd readahead for jit+(mlock/fadvise)
+ if [[ $the_when == "jit" && $the_mode != 'warm' && $the_mode != 'cold' ]]; then
+ iorapd_readahead_enable
+ return 0
+ fi
+
if [[ $the_when != "aot" ]]; then
# TODO: just in time implementation.. should probably use system server.
return 0
@@ -250,13 +265,18 @@
local the_when="$1" # user: aot, jit
local the_mode="$2" # warm, cold, fadvise, mlock, etc.
local logcat_timestamp="$3" # timestamp from before am start.
+ local res
if [[ $the_when != "aot" ]]; then
if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then
# Validate that readahead completes.
# If this fails for some reason, then this will also discard the timing of the run.
iorapd_readahead_wait_until_finished "$package" "$activity" "$logcat_timestamp" "$timeout"
- return $?
+ res=$?
+
+ iorapd_readahead_disable
+
+ return $res
fi
# Don't need to do anything for warm or cold.
return 0
diff --git a/startop/scripts/iorap/collector b/startop/scripts/iorap/collector
index d96125f..3dc080a 100755
--- a/startop/scripts/iorap/collector
+++ b/startop/scripts/iorap/collector
@@ -322,6 +322,7 @@
iorapd_compiler_purge_trace_file "$package" "$activity" || return $?
iorapd_perfetto_enable || return $?
+ iorapd_readahead_disable || return $?
iorapd_start || return $?
# Wait for perfetto trace to finished writing itself out.
diff --git a/startop/scripts/iorap/common b/startop/scripts/iorap/common
index cb2b618..031dabf 100755
--- a/startop/scripts/iorap/common
+++ b/startop/scripts/iorap/common
@@ -45,7 +45,7 @@
iorapd_reset # iorapd only reads this flag when initializing
}
-# Enable perfetto tracing.
+# Disable perfetto tracing.
# Subsequent launches of applications will no longer record perfetto trace protobufs.
iorapd_perfetto_disable() {
verbose_print 'disable perfetto'
@@ -53,6 +53,31 @@
iorapd_reset # iorapd only reads this flag when initializing
}
+# Enable readahead
+# Subsequent launches of an application will be sped up by iorapd readahead prefetching
+# (Provided an appropriate compiled trace exists for that application)
+iorapd_readahead_enable() {
+ if [[ "$(adb shell getprop iorapd.readahead.enable)" == true ]]; then
+ verbose_print 'enable readahead [already enabled]'
+ return 0
+ fi
+ verbose_print 'enable readahead [reset iorapd]'
+ adb shell setprop iorapd.readahead.enable true
+ iorapd_reset # iorapd only reads this flag when initializing
+}
+
+# Disable readahead
+# Subsequent launches of an application will be not be sped up by iorapd readahead prefetching.
+iorapd_readahead_disable() {
+ if [[ "$(adb shell getprop iorapd.readahead.enable)" == false ]]; then
+ verbose_print 'disable readahead [already disabled]'
+ return 0
+ fi
+ verbose_print 'disable readahead [reset iorapd]'
+ adb shell setprop iorapd.readahead.enable false
+ iorapd_reset # iorapd only reads this flag when initializing
+}
+
_iorapd_path_to_data_file() {
local package="$1"
local activity="$2"