[automerger skipped] Merge "Don't set screen state until boot is completed" into tm-qpr-dev am: 63d87dcbe9 am: 8e2e91c411 -s ours am: 7f029edeac -s ours am: b550565006 -s ours
am skip reason: skipped by user wilczynskip
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21264319
Change-Id: Idb5ca4f9682f46364ab4c2b36c3c0a6cccbb3ab9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
new file mode 100644
index 0000000..324fcc6
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2023 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.input
+
+import android.perftests.utils.PerfStatusReporter
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.VelocityTracker
+
+import androidx.test.filters.LargeTest
+import androidx.test.runner.AndroidJUnit4
+
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private fun createScrollMotionEvent(scrollAmount: Float, eventTimeMs: Long): MotionEvent {
+ val props = MotionEvent.PointerProperties()
+ props.id = 0
+ val coords = MotionEvent.PointerCoords()
+ coords.setAxisValue(MotionEvent.AXIS_SCROLL, scrollAmount)
+ return MotionEvent.obtain(
+ /*downTime=*/0,
+ eventTimeMs,
+ MotionEvent.ACTION_SCROLL,
+ /*pointerCount=*/1,
+ arrayOf(props),
+ arrayOf(coords),
+ /*metaState=*/0,
+ /*buttonState=*/0,
+ /*xPrecision=*/0f,
+ /*yPrecision=*/0f,
+ /*deviceId=*/1,
+ /*edgeFlags=*/0,
+ InputDevice.SOURCE_ROTARY_ENCODER,
+ /*flags=*/0
+ )
+}
+
+/**
+ * Benchmark tests for [VelocityTracker]
+ *
+ * Build/Install/Run:
+ * atest VelocityTrackerBenchmarkTest
+ */
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class VelocityTrackerBenchmarkTest {
+ @get:Rule
+ val perfStatusReporter: PerfStatusReporter = PerfStatusReporter()
+
+ private val velocityTracker = VelocityTracker.obtain()
+ @Before
+ fun setup() {
+ velocityTracker.clear()
+ }
+
+ @Test
+ fun addMovement_axisScroll() {
+ val state = perfStatusReporter.getBenchmarkState()
+ while (state.keepRunning()) {
+ state.pauseTiming()
+ var eventTimeMs: Long = 100
+ val scrollAmount = 30f
+ for (i in 0 until TEST_NUM_DATAPOINTS) {
+ state.resumeTiming()
+ velocityTracker.addMovement(createScrollMotionEvent(scrollAmount, eventTimeMs))
+ state.pauseTiming()
+ eventTimeMs += 2
+ }
+ velocityTracker.computeCurrentVelocity(1000)
+ Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) > 0)
+ // Clear the tracker for the next run
+ velocityTracker.clear()
+ state.resumeTiming()
+ }
+ }
+
+ @Test
+ fun computeCurrentVelocity_constantVelocity_axisScroll_computeAfterAllAdditions() {
+ val state = perfStatusReporter.getBenchmarkState()
+ while (state.keepRunning()) {
+ // Add the data points
+ state.pauseTiming()
+ var eventTimeMs: Long = 100
+ val scrollAmount = 30f
+ for (i in 0 until TEST_NUM_DATAPOINTS) {
+ velocityTracker.addMovement(createScrollMotionEvent(scrollAmount, eventTimeMs))
+ eventTimeMs += 2
+ }
+
+ // Do the velocity computation
+ state.resumeTiming()
+ velocityTracker.computeCurrentVelocity(1000)
+
+ // Clear the tracker for the next run
+ state.pauseTiming()
+ Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) > 0)
+ velocityTracker.clear()
+ state.resumeTiming()
+ }
+ }
+
+ @Test
+ fun computeCurrentVelocity_constantVelocity_axisScroll_computeAfterEachAdd() {
+ val state = perfStatusReporter.getBenchmarkState()
+ while (state.keepRunning()) {
+ state.pauseTiming()
+ var eventTimeMs: Long = 100
+ val scrollAmount = 30f
+ for (i in 0 until TEST_NUM_DATAPOINTS) {
+ velocityTracker.addMovement(createScrollMotionEvent(scrollAmount, eventTimeMs))
+ state.resumeTiming()
+ velocityTracker.computeCurrentVelocity(1000)
+ state.pauseTiming()
+ eventTimeMs += 2
+ }
+ Assert.assertTrue(velocityTracker.getAxisVelocity(MotionEvent.AXIS_SCROLL) > 0)
+ // Clear the tracker for the next run
+ velocityTracker.clear()
+ state.resumeTiming()
+ }
+ }
+
+ companion object {
+ private const val TEST_NUM_DATAPOINTS = 100
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 051dde0..4c2cf2b 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -1554,8 +1554,9 @@
}
private void waitCoolDownPeriod() {
- final int tenSeconds = 1000 * 10;
+ // Heuristic value based on local tests. Stability increased compared to no waiting.
+ final int fiveSeconds = 1000 * 5;
waitForBroadcastIdle();
- sleep(tenSeconds);
+ sleep(fiveSeconds);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e2fff0f..deb8a63 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -766,11 +766,11 @@
* Default quota for pre-S apps. The same as allowing an alarm slot once
* every ALLOW_WHILE_IDLE_LONG_DELAY, which was 9 minutes.
*/
- private static final int DEFAULT_ALLOW_WHILE_IDLE_COMPAT_QUOTA = 1;
+ private static final int DEFAULT_ALLOW_WHILE_IDLE_COMPAT_QUOTA = 7;
private static final int DEFAULT_ALLOW_WHILE_IDLE_QUOTA = 72;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WINDOW = 60 * 60 * 1000; // 1 hour.
- private static final long DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW = 9 * 60 * 1000; // 9 mins.
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW = 60 * 60 * 1000;
private static final long DEFAULT_PRIORITY_ALARM_DELAY = 9 * 60_000;
diff --git a/core/api/current.txt b/core/api/current.txt
index eef16be..9f27457 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5279,8 +5279,8 @@
}
public class BroadcastOptions {
+ ctor public BroadcastOptions();
method public boolean isShareIdentityEnabled();
- method @NonNull public static android.app.BroadcastOptions makeBasic();
method @NonNull public android.app.BroadcastOptions setShareIdentityEnabled(boolean);
method @NonNull public android.os.Bundle toBundle();
}
@@ -32557,6 +32557,7 @@
field public static final int S_V2 = 32; // 0x20
field public static final int TIRAMISU = 33; // 0x21
field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710
+ field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -41246,6 +41247,7 @@
method public void setUiEnabled(boolean);
method public void show(android.os.Bundle, int);
method public void startAssistantActivity(android.content.Intent);
+ method public void startAssistantActivity(@NonNull android.content.Intent, @NonNull android.os.Bundle);
method public void startVoiceActivity(android.content.Intent);
method public final void unregisterVisibleActivityCallback(@NonNull android.service.voice.VoiceInteractionSession.VisibleActivityCallback);
field public static final String KEY_SHOW_SESSION_ID = "android.service.voice.SHOW_SESSION_ID";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 95e331e..701054f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -842,6 +842,7 @@
method public int getPendingIntentBackgroundActivityStartMode();
method public boolean isDeferUntilActive();
method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed();
+ method @Deprecated @NonNull public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void recordResponseEventWhileInBackground(@IntRange(from=0) long);
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
method @NonNull public android.app.BroadcastOptions setDeferUntilActive(boolean);
@@ -5117,7 +5118,7 @@
method @NonNull public android.hardware.input.VirtualTouchEvent build();
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setAction(int);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setMajorAxisSize(@FloatRange(from=0.0f) float);
- method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPointerId(int);
+ method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPointerId(@IntRange(from=0, to=0x10 - 1) int);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPressure(@FloatRange(from=0.0f) float);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setToolType(int);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setX(float);
@@ -10719,15 +10720,15 @@
public static final class PowerManager.LowPowerStandbyPortDescription {
ctor public PowerManager.LowPowerStandbyPortDescription(int, int, int);
- ctor public PowerManager.LowPowerStandbyPortDescription(int, int, int, @Nullable android.net.LinkAddress);
- method @Nullable public android.net.LinkAddress getBindAddress();
+ ctor public PowerManager.LowPowerStandbyPortDescription(int, int, int, @Nullable java.net.InetAddress);
+ method @Nullable public java.net.InetAddress getLocalAddress();
method public int getPortMatcher();
method public int getPortNumber();
method public int getProtocol();
field public static final int MATCH_PORT_LOCAL = 1; // 0x1
field public static final int MATCH_PORT_REMOTE = 2; // 0x2
- field public static final int PROTOCOL_TCP = 1; // 0x1
- field public static final int PROTOCOL_UDP = 2; // 0x2
+ field public static final int PROTOCOL_TCP = 6; // 0x6
+ field public static final int PROTOCOL_UDP = 17; // 0x11
}
public final class PowerManager.LowPowerStandbyPortsLock {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c0cd638..addb3e7 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -985,7 +985,7 @@
method public boolean isInitialized();
method public boolean isMain();
method public boolean isManagedProfile();
- method public boolean isPrimary();
+ method @Deprecated public boolean isPrimary();
method public boolean isProfile();
method public boolean isQuietModeEnabled();
method public boolean isRestricted();
@@ -1002,7 +1002,7 @@
field public static final int FLAG_INITIALIZED = 16; // 0x10
field public static final int FLAG_MAIN = 16384; // 0x4000
field @Deprecated public static final int FLAG_MANAGED_PROFILE = 32; // 0x20
- field public static final int FLAG_PRIMARY = 1; // 0x1
+ field @Deprecated public static final int FLAG_PRIMARY = 1; // 0x1
field public static final int FLAG_PROFILE = 4096; // 0x1000
field public static final int FLAG_QUIET_MODE = 128; // 0x80
field @Deprecated public static final int FLAG_RESTRICTED = 8; // 0x8
@@ -3294,6 +3294,7 @@
public interface WindowManager extends android.view.ViewManager {
method public default int getDisplayImePolicy(int);
+ method public static boolean hasWindowExtensionsEnabled();
method public default void holdLock(android.os.IBinder, int);
method public default boolean isGlobalKey(int);
method public default boolean isTaskSnapshotSupported();
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index a81ef18..322d23b 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -72,6 +72,13 @@
private static long sBackgroundPauseDelay = 10000;
/**
+ * A cache of the values in a list. Used so that when calling the list, we have a copy
+ * of it in case the list is modified while iterating. The array can be reused to avoid
+ * allocation on every notification.
+ */
+ private Object[] mCachedList;
+
+ /**
* Sets the duration for delaying pausing animators when apps go into the background.
* Used by AnimationHandler when requested to pause animators.
*
@@ -160,14 +167,7 @@
public void pause() {
if (isStarted() && !mPaused) {
mPaused = true;
- if (mPauseListeners != null) {
- ArrayList<AnimatorPauseListener> tmpListeners =
- (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationPause(this);
- }
- }
+ notifyPauseListeners(AnimatorCaller.ON_PAUSE);
}
}
@@ -184,14 +184,7 @@
public void resume() {
if (mPaused) {
mPaused = false;
- if (mPauseListeners != null) {
- ArrayList<AnimatorPauseListener> tmpListeners =
- (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationResume(this);
- }
- }
+ notifyPauseListeners(AnimatorCaller.ON_RESUME);
}
}
@@ -450,6 +443,7 @@
if (mPauseListeners != null) {
anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
}
+ anim.mCachedList = null;
return anim;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
@@ -591,6 +585,70 @@
}
/**
+ * Calls notification for each AnimatorListener.
+ *
+ * @param notification The notification method to call on each listener.
+ * @param isReverse When this is used with start/end, this is the isReverse parameter. For
+ * other calls, this is ignored.
+ */
+ void notifyListeners(
+ AnimatorCaller<AnimatorListener, Animator> notification,
+ boolean isReverse
+ ) {
+ callOnList(mListeners, notification, this, isReverse);
+ }
+
+ /**
+ * Call pause/resume on each AnimatorPauseListener.
+ *
+ * @param notification Either ON_PAUSE or ON_RESUME to call onPause or onResume on each
+ * listener.
+ */
+ void notifyPauseListeners(AnimatorCaller<AnimatorPauseListener, Animator> notification) {
+ callOnList(mPauseListeners, notification, this, false);
+ }
+
+ /**
+ * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and
+ * <code>isReverse</code> as parameters.
+ *
+ * @param list The list of items to make calls on.
+ * @param call The method to call for each item in list.
+ * @param animator The animator parameter of call.
+ * @param isReverse The isReverse parameter of call.
+ * @param <T> The item type of list
+ * @param <A> The Animator type of animator.
+ */
+ <T, A> void callOnList(
+ ArrayList<T> list,
+ AnimatorCaller<T, A> call,
+ A animator,
+ boolean isReverse
+ ) {
+ int size = list == null ? 0 : list.size();
+ if (size > 0) {
+ // Try to reuse mCacheList to store the items of list.
+ Object[] array;
+ if (mCachedList == null || mCachedList.length < size) {
+ array = new Object[size];
+ } else {
+ array = mCachedList;
+ // Clear it in case there is some reentrancy
+ mCachedList = null;
+ }
+ list.toArray(array);
+ for (int i = 0; i < size; i++) {
+ //noinspection unchecked
+ T item = (T) array[i];
+ call.call(item, animator, isReverse);
+ array[i] = null;
+ }
+ // Store it for the next call so we can reuse this array, if needed.
+ mCachedList = array;
+ }
+ }
+
+ /**
* <p>An animation listener receives notifications from an animation.
* Notifications indicate animation related events, such as the end or the
* repetition of the animation.</p>
@@ -748,4 +806,29 @@
return clone;
}
}
+
+ /**
+ * Internally used by {@link #callOnList(ArrayList, AnimatorCaller, Object, boolean)} to
+ * make a call on all children of a list. This can be for start, stop, pause, cancel, update,
+ * etc notifications.
+ *
+ * @param <T> The type of listener to make the call on
+ * @param <A> The type of animator that is passed as a parameter
+ */
+ interface AnimatorCaller<T, A> {
+ void call(T listener, A animator, boolean isReverse);
+
+ AnimatorCaller<AnimatorListener, Animator> ON_START = AnimatorListener::onAnimationStart;
+ AnimatorCaller<AnimatorListener, Animator> ON_END = AnimatorListener::onAnimationEnd;
+ AnimatorCaller<AnimatorListener, Animator> ON_CANCEL =
+ (listener, animator, isReverse) -> listener.onAnimationCancel(animator);
+ AnimatorCaller<AnimatorListener, Animator> ON_REPEAT =
+ (listener, animator, isReverse) -> listener.onAnimationRepeat(animator);
+ AnimatorCaller<AnimatorPauseListener, Animator> ON_PAUSE =
+ (listener, animator, isReverse) -> listener.onAnimationPause(animator);
+ AnimatorCaller<AnimatorPauseListener, Animator> ON_RESUME =
+ (listener, animator, isReverse) -> listener.onAnimationResume(animator);
+ AnimatorCaller<ValueAnimator.AnimatorUpdateListener, ValueAnimator> ON_UPDATE =
+ (listener, animator, isReverse) -> listener.onAnimationUpdate(animator);
+ }
}
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 257adfe..09eec9d 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -32,6 +32,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
+import java.util.function.Consumer;
/**
* This class plays a set of {@link Animator} objects in the specified order. Animations
@@ -424,24 +425,28 @@
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
if (isStarted()) {
- ArrayList<AnimatorListener> tmpListeners = null;
- if (mListeners != null) {
- tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
- int size = tmpListeners.size();
- for (int i = 0; i < size; i++) {
- tmpListeners.get(i).onAnimationCancel(this);
- }
- }
- ArrayList<Node> playingSet = new ArrayList<>(mPlayingSet);
- int setSize = playingSet.size();
- for (int i = 0; i < setSize; i++) {
- playingSet.get(i).mAnimation.cancel();
- }
+ notifyListeners(AnimatorCaller.ON_CANCEL, false);
+ callOnPlayingSet(Animator::cancel);
mPlayingSet.clear();
endAnimation();
}
}
+ /**
+ * Calls consumer on every Animator of mPlayingSet.
+ *
+ * @param consumer The method to call on every Animator of mPlayingSet.
+ */
+ private void callOnPlayingSet(Consumer<Animator> consumer) {
+ final ArrayList<Node> list = mPlayingSet;
+ final int size = list.size();
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < size; i++) {
+ final Animator animator = list.get(i).mAnimation;
+ consumer.accept(animator);
+ }
+ }
+
// Force all the animations to end when the duration scale is 0.
private void forceToEnd() {
if (mEndCanBeCalled) {
@@ -662,6 +667,7 @@
super.pause();
if (!previouslyPaused && mPaused) {
mPauseTime = -1;
+ callOnPlayingSet(Animator::pause);
}
}
@@ -676,6 +682,7 @@
if (mPauseTime >= 0) {
addAnimationCallback(0);
}
+ callOnPlayingSet(Animator::resume);
}
}
@@ -751,26 +758,14 @@
private void notifyStartListeners(boolean inReverse) {
if (mListeners != null && !mStartListenersCalled) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- AnimatorListener listener = tmpListeners.get(i);
- listener.onAnimationStart(this, inReverse);
- }
+ notifyListeners(AnimatorCaller.ON_START, inReverse);
}
mStartListenersCalled = true;
}
private void notifyEndListeners(boolean inReverse) {
if (mListeners != null && mStartListenersCalled) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- AnimatorListener listener = tmpListeners.get(i);
- listener.onAnimationEnd(this, inReverse);
- }
+ notifyListeners(AnimatorCaller.ON_END, inReverse);
}
mStartListenersCalled = false;
}
@@ -1503,6 +1498,7 @@
anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
anim.mEvents = new ArrayList<AnimationEvent>();
+ anim.mStartListenersCalled = false;
anim.mAnimationEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 7009725..46d9847 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1110,24 +1110,14 @@
private void notifyStartListeners(boolean isReversing) {
if (mListeners != null && !mStartListenersCalled) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationStart(this, isReversing);
- }
+ notifyListeners(AnimatorCaller.ON_START, isReversing);
}
mStartListenersCalled = true;
}
private void notifyEndListeners(boolean isReversing) {
if (mListeners != null && mStartListenersCalled) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(this, isReversing);
- }
+ notifyListeners(AnimatorCaller.ON_END, isReversing);
}
mStartListenersCalled = false;
}
@@ -1224,15 +1214,7 @@
// If it's not yet running, then start listeners weren't called. Call them now.
notifyStartListeners(mReversing);
}
- int listenersSize = mListeners.size();
- if (listenersSize > 0) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (int i = 0; i < listenersSize; i++) {
- AnimatorListener listener = tmpListeners.get(i);
- listener.onAnimationCancel(this);
- }
- }
+ notifyListeners(AnimatorCaller.ON_CANCEL, false);
}
endAnimation();
@@ -1435,12 +1417,7 @@
done = true;
} else if (newIteration && !lastIterationFinished) {
// Time to repeat
- if (mListeners != null) {
- int numListeners = mListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- mListeners.get(i).onAnimationRepeat(this);
- }
- }
+ notifyListeners(AnimatorCaller.ON_REPEAT, false);
} else if (lastIterationFinished) {
done = true;
}
@@ -1494,12 +1471,7 @@
lastIteration = Math.min(lastIteration, mRepeatCount);
if (iteration != lastIteration) {
- if (mListeners != null) {
- int numListeners = mListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- mListeners.get(i).onAnimationRepeat(this);
- }
- }
+ notifyListeners(AnimatorCaller.ON_REPEAT, false);
}
}
@@ -1697,12 +1669,7 @@
for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
}
- if (mUpdateListeners != null) {
- int numListeners = mUpdateListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- mUpdateListeners.get(i).onAnimationUpdate(this);
- }
- }
+ callOnList(mUpdateListeners, AnimatorCaller.ON_UPDATE, this, false);
}
@Override
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index f35bdfb..fe40a4c 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -262,7 +262,12 @@
* Creates a basic {@link BroadcastOptions} with no options initially set.
*
* @return an instance of {@code BroadcastOptions} against which options can be set
+ *
+ * @deprecated Use {@link BroadcastOptions#BroadcastOptions()} instead.
+ * @hide
*/
+ @Deprecated
+ @SystemApi
public static @NonNull BroadcastOptions makeBasic() {
BroadcastOptions opts = new BroadcastOptions();
return opts;
@@ -280,7 +285,10 @@
return opts;
}
- private BroadcastOptions() {
+ /**
+ * Creates a new {@code BroadcastOptions} with no options initially set.
+ */
+ public BroadcastOptions() {
super();
resetTemporaryAppAllowlist();
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index bf69531..dc197bd 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1401,95 +1401,99 @@
if (mApplication != null) {
return mApplication;
}
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
- synchronized (sApplications) {
- final Application cached = sApplications.get(mPackageName);
- if (cached != null) {
- // Looks like this is always happening for the system server, because
- // the LoadedApk created in systemMain() -> attach() isn't cached properly?
- if (!"android".equals(mPackageName)) {
- Slog.wtfStack(TAG, "App instance already created for package=" + mPackageName
- + " instance=" + cached);
- }
- if (!allowDuplicateInstances) {
- mApplication = cached;
- return cached;
- }
- // Some apps intentionally call makeApplication() to create a new Application
- // instance... Sigh...
- }
- }
- Application app = null;
-
- final String myProcessName = Process.myProcessName();
- String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
- myProcessName);
- if (forceDefaultAppClass || (appClass == null)) {
- appClass = "android.app.Application";
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
}
try {
- final java.lang.ClassLoader cl = getClassLoader();
- if (!mPackageName.equals("android")) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- "initializeJavaContextClassLoader");
- initializeJavaContextClassLoader();
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
-
- // Rewrite the R 'constants' for all library apks.
- SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
- false, false);
- for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
- final int id = packageIdentifiers.keyAt(i);
- if (id == 0x01 || id == 0x7f) {
- continue;
- }
-
- rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
- }
-
- ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
- // The network security config needs to be aware of multiple
- // applications in the same process to handle discrepancies
- NetworkSecurityConfigProvider.handleNewApplication(appContext);
- app = mActivityThread.mInstrumentation.newApplication(
- cl, appClass, appContext);
- appContext.setOuterContext(app);
- } catch (Exception e) {
- if (!mActivityThread.mInstrumentation.onException(app, e)) {
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- throw new RuntimeException(
- "Unable to instantiate application " + appClass
- + " package " + mPackageName + ": " + e.toString(), e);
- }
- }
- mActivityThread.mAllApplications.add(app);
- mApplication = app;
- if (!allowDuplicateInstances) {
synchronized (sApplications) {
- sApplications.put(mPackageName, app);
- }
- }
-
- if (instrumentation != null) {
- try {
- instrumentation.callApplicationOnCreate(app);
- } catch (Exception e) {
- if (!instrumentation.onException(app, e)) {
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- throw new RuntimeException(
- "Unable to create application " + app.getClass().getName()
- + ": " + e.toString(), e);
+ final Application cached = sApplications.get(mPackageName);
+ if (cached != null) {
+ // Looks like this is always happening for the system server, because
+ // the LoadedApk created in systemMain() -> attach() isn't cached properly?
+ if (!"android".equals(mPackageName)) {
+ Slog.wtfStack(TAG, "App instance already created for package="
+ + mPackageName + " instance=" + cached);
+ }
+ if (!allowDuplicateInstances) {
+ mApplication = cached;
+ return cached;
+ }
+ // Some apps intentionally call makeApplication() to create a new Application
+ // instance... Sigh...
}
}
+
+ Application app = null;
+
+ final String myProcessName = Process.myProcessName();
+ String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
+ myProcessName);
+ if (forceDefaultAppClass || (appClass == null)) {
+ appClass = "android.app.Application";
+ }
+
+ try {
+ final java.lang.ClassLoader cl = getClassLoader();
+ if (!mPackageName.equals("android")) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "initializeJavaContextClassLoader");
+ initializeJavaContextClassLoader();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ // Rewrite the R 'constants' for all library apks.
+ SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
+ false, false);
+ for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
+ final int id = packageIdentifiers.keyAt(i);
+ if (id == 0x01 || id == 0x7f) {
+ continue;
+ }
+
+ rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
+ }
+
+ ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
+ // The network security config needs to be aware of multiple
+ // applications in the same process to handle discrepancies
+ NetworkSecurityConfigProvider.handleNewApplication(appContext);
+ app = mActivityThread.mInstrumentation.newApplication(
+ cl, appClass, appContext);
+ appContext.setOuterContext(app);
+ } catch (Exception e) {
+ if (!mActivityThread.mInstrumentation.onException(app, e)) {
+ throw new RuntimeException(
+ "Unable to instantiate application " + appClass
+ + " package " + mPackageName + ": " + e.toString(), e);
+ }
+ }
+ mActivityThread.mAllApplications.add(app);
+ mApplication = app;
+ if (!allowDuplicateInstances) {
+ synchronized (sApplications) {
+ sApplications.put(mPackageName, app);
+ }
+ }
+
+ if (instrumentation != null) {
+ try {
+ instrumentation.callApplicationOnCreate(app);
+ } catch (Exception e) {
+ if (!instrumentation.onException(app, e)) {
+ throw new RuntimeException(
+ "Unable to create application " + app.getClass().getName()
+ + ": " + e.toString(), e);
+ }
+ }
+ }
+
+ return app;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
-
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
- return app;
}
@UnsupportedAppUsage
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3a3ad8ce..352e753 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5249,17 +5249,17 @@
boolean hasSecondLine = showProgress;
if (p.hasTitle()) {
contentView.setViewVisibility(p.mTitleViewId, View.VISIBLE);
- contentView.setTextViewText(p.mTitleViewId, processTextSpans(p.title));
+ contentView.setTextViewText(p.mTitleViewId, processTextSpans(p.mTitle));
setTextViewColorPrimary(contentView, p.mTitleViewId, p);
} else if (p.mTitleViewId != R.id.title) {
// This alternate title view ID is not cleared by resetStandardTemplate
contentView.setViewVisibility(p.mTitleViewId, View.GONE);
contentView.setTextViewText(p.mTitleViewId, null);
}
- if (p.text != null && p.text.length() != 0
+ if (p.mText != null && p.mText.length() != 0
&& (!showProgress || p.mAllowTextWithProgress)) {
contentView.setViewVisibility(p.mTextViewId, View.VISIBLE);
- contentView.setTextViewText(p.mTextViewId, processTextSpans(p.text));
+ contentView.setTextViewText(p.mTextViewId, processTextSpans(p.mText));
setTextViewColorSecondary(contentView, p.mTextViewId, p);
hasSecondLine = true;
} else if (p.mTextViewId != R.id.text) {
@@ -5533,20 +5533,20 @@
if (p.mHideSubText) {
return false;
}
- CharSequence summaryText = p.summaryText;
- if (summaryText == null && mStyle != null && mStyle.mSummaryTextSet
+ CharSequence headerText = p.mSubText;
+ if (headerText == null && mStyle != null && mStyle.mSummaryTextSet
&& mStyle.hasSummaryInHeader()) {
- summaryText = mStyle.mSummaryText;
+ headerText = mStyle.mSummaryText;
}
- if (summaryText == null
+ if (headerText == null
&& mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
&& mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
- summaryText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);
+ headerText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);
}
- if (!TextUtils.isEmpty(summaryText)) {
+ if (!TextUtils.isEmpty(headerText)) {
// TODO: Remove the span entirely to only have the string with propper formating.
contentView.setTextViewText(R.id.header_text, processTextSpans(
- processLegacyText(summaryText)));
+ processLegacyText(headerText)));
setTextViewColorSecondary(contentView, R.id.header_text, p);
contentView.setViewVisibility(R.id.header_text, View.VISIBLE);
if (hasTextToLeft) {
@@ -5566,9 +5566,9 @@
if (p.mHideSubText) {
return false;
}
- if (!TextUtils.isEmpty(p.headerTextSecondary)) {
+ if (!TextUtils.isEmpty(p.mHeaderTextSecondary)) {
contentView.setTextViewText(R.id.header_text_secondary, processTextSpans(
- processLegacyText(p.headerTextSecondary)));
+ processLegacyText(p.mHeaderTextSecondary)));
setTextViewColorSecondary(contentView, R.id.header_text_secondary, p);
contentView.setViewVisibility(R.id.header_text_secondary, View.VISIBLE);
if (hasTextToLeft) {
@@ -6175,7 +6175,7 @@
.viewType(StandardTemplateParams.VIEW_TYPE_MINIMIZED)
.highlightExpander(false)
.fillTextsFrom(this);
- if (!useRegularSubtext || TextUtils.isEmpty(p.summaryText)) {
+ if (!useRegularSubtext || TextUtils.isEmpty(p.mSubText)) {
p.summaryText(createSummaryText());
}
RemoteViews header = makeNotificationHeader(p);
@@ -7190,7 +7190,7 @@
checkBuilder();
if (mBigContentTitle != null) {
- p.title = mBigContentTitle;
+ p.mTitle = mBigContentTitle;
}
return mBuilder.applyStandardTemplateWithActions(layoutId, p, result);
@@ -12453,10 +12453,10 @@
boolean mAllowTextWithProgress;
int mTitleViewId;
int mTextViewId;
- CharSequence title;
- CharSequence text;
- CharSequence headerTextSecondary;
- CharSequence summaryText;
+ @Nullable CharSequence mTitle;
+ @Nullable CharSequence mText;
+ @Nullable CharSequence mHeaderTextSecondary;
+ @Nullable CharSequence mSubText;
int maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
boolean allowColorization = true;
boolean mHighlightExpander = false;
@@ -12478,10 +12478,10 @@
mAllowTextWithProgress = false;
mTitleViewId = R.id.title;
mTextViewId = R.id.text;
- title = null;
- text = null;
- summaryText = null;
- headerTextSecondary = null;
+ mTitle = null;
+ mText = null;
+ mSubText = null;
+ mHeaderTextSecondary = null;
maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
allowColorization = true;
mHighlightExpander = false;
@@ -12489,7 +12489,7 @@
}
final boolean hasTitle() {
- return !TextUtils.isEmpty(title) && !mHideTitle;
+ return !TextUtils.isEmpty(mTitle) && !mHideTitle;
}
final StandardTemplateParams viewType(int viewType) {
@@ -12562,23 +12562,23 @@
return this;
}
- final StandardTemplateParams title(CharSequence title) {
- this.title = title;
+ final StandardTemplateParams title(@Nullable CharSequence title) {
+ this.mTitle = title;
return this;
}
- final StandardTemplateParams text(CharSequence text) {
- this.text = text;
+ final StandardTemplateParams text(@Nullable CharSequence text) {
+ this.mText = text;
return this;
}
- final StandardTemplateParams summaryText(CharSequence text) {
- this.summaryText = text;
+ final StandardTemplateParams summaryText(@Nullable CharSequence text) {
+ this.mSubText = text;
return this;
}
- final StandardTemplateParams headerTextSecondary(CharSequence text) {
- this.headerTextSecondary = text;
+ final StandardTemplateParams headerTextSecondary(@Nullable CharSequence text) {
+ this.mHeaderTextSecondary = text;
return this;
}
@@ -12605,9 +12605,9 @@
final StandardTemplateParams fillTextsFrom(Builder b) {
Bundle extras = b.mN.extras;
- this.title = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE));
- this.text = b.processLegacyText(extras.getCharSequence(EXTRA_TEXT));
- this.summaryText = extras.getCharSequence(EXTRA_SUB_TEXT);
+ this.mTitle = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE));
+ this.mText = b.processLegacyText(extras.getCharSequence(EXTRA_TEXT));
+ this.mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
return this;
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index e8f0a89..f55f355 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -19,7 +19,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.Process.myUserHandle;
-import static android.os.Trace.TRACE_TAG_DATABASE;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_CHECK_URI_PERMISSION;
@@ -284,7 +284,7 @@
// Return an empty cursor for all columns.
return new MatrixCursor(cursor.getColumnNames(), 0);
}
- traceBegin(TRACE_TAG_DATABASE, "query: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "query: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -295,7 +295,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -304,7 +304,7 @@
// getCallingPackage() isn't available in getType(), as the javadoc states.
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- traceBegin(TRACE_TAG_DATABASE, "getType: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "getType: ", uri.getAuthority());
try {
final String type = mInterface.getType(uri);
if (type != null) {
@@ -314,7 +314,7 @@
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} finally {
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -395,7 +395,7 @@
setCallingAttributionSource(original);
}
}
- traceBegin(TRACE_TAG_DATABASE, "insert: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "insert: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -404,7 +404,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -417,7 +417,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return 0;
}
- traceBegin(TRACE_TAG_DATABASE, "bulkInsert: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "bulkInsert: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -426,7 +426,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -463,7 +463,7 @@
}
}
}
- traceBegin(TRACE_TAG_DATABASE, "applyBatch: ", authority);
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "applyBatch: ", authority);
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -482,7 +482,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -495,7 +495,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return 0;
}
- traceBegin(TRACE_TAG_DATABASE, "delete: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "delete: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -504,7 +504,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -517,7 +517,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return 0;
}
- traceBegin(TRACE_TAG_DATABASE, "update: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "update: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -526,7 +526,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -537,7 +537,7 @@
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(attributionSource, uri, mode);
- traceBegin(TRACE_TAG_DATABASE, "openFile: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "openFile: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -547,7 +547,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -558,7 +558,7 @@
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(attributionSource, uri, mode);
- traceBegin(TRACE_TAG_DATABASE, "openAssetFile: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "openAssetFile: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -568,7 +568,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -577,7 +577,7 @@
String method, @Nullable String arg, @Nullable Bundle extras) {
validateIncomingAuthority(authority);
Bundle.setDefusable(extras, true);
- traceBegin(TRACE_TAG_DATABASE, "call: ", authority);
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "call: ", authority);
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -586,7 +586,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -595,13 +595,13 @@
// getCallingPackage() isn't available in getType(), as the javadoc states.
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- traceBegin(TRACE_TAG_DATABASE, "getStreamTypes: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "getStreamTypes: ", uri.getAuthority());
try {
return mInterface.getStreamTypes(uri, mimeTypeFilter);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} finally {
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -613,7 +613,7 @@
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(attributionSource, uri, "r");
- traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "openTypedAssetFile: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -623,7 +623,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -641,7 +641,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return null;
}
- traceBegin(TRACE_TAG_DATABASE, "canonicalize: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "canonicalize: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -650,7 +650,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -677,7 +677,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return null;
}
- traceBegin(TRACE_TAG_DATABASE, "uncanonicalize: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "uncanonicalize: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -686,7 +686,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -713,7 +713,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return false;
}
- traceBegin(TRACE_TAG_DATABASE, "refresh: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "refresh: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -721,7 +721,7 @@
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -730,7 +730,7 @@
int uid, int modeFlags) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- traceBegin(TRACE_TAG_DATABASE, "checkUriPermission: ", uri.getAuthority());
+ traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "checkUriPermission: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -739,7 +739,7 @@
throw e.rethrowAsRuntimeException();
} finally {
setCallingAttributionSource(original);
- Trace.traceEnd(TRACE_TAG_DATABASE);
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 6386f75..81fc029 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -60,10 +60,17 @@
*/
/**
- * Primary user. Only one user can have this flag set. It identifies the first human user
- * on a device. This flag is not supported in headless system user mode.
+ * Primary user. In practice, this is just synonymous with {@link #FLAG_SYSTEM}.
+ *
+ * <p>On many devices, this will also be the first human user.
+ * However, in {@link UserManager#isHeadlessSystemUserMode() headless system user mode}, this
+ * should be regarded as unsupported since the system user may not be a human.
+ *
+ * @deprecated For checking for user 0, use {@link #FLAG_SYSTEM}.
+ * For checking for the designated "main human user", use {@link #FLAG_MAIN}.
*/
@UnsupportedAppUsage
+ @Deprecated
public static final int FLAG_PRIMARY = 0x00000001;
/**
@@ -335,7 +342,12 @@
}
}
+ /**
+ * @deprecated For checking for user 0, compare {@link #id} to {@link UserHandle#USER_SYSTEM}.
+ * For checking for the designated "main human user", use {@link #isMain()}.
+ */
@UnsupportedAppUsage
+ @Deprecated
public boolean isPrimary() {
return (flags & FLAG_PRIMARY) == FLAG_PRIMARY;
}
diff --git a/core/java/android/credentials/CredentialDescription.java b/core/java/android/credentials/CredentialDescription.java
index f9db5e8..e74de9c 100644
--- a/core/java/android/credentials/CredentialDescription.java
+++ b/core/java/android/credentials/CredentialDescription.java
@@ -151,16 +151,4 @@
public List<CredentialEntry> getCredentialEntries() {
return mCredentialEntries;
}
-
- @Override
- public int hashCode() {
- return Objects.hash(mType, mFlattenedRequestString);
- }
-
- @Override
- public boolean equals(Object obj) {
- return Objects.equals(mType, ((CredentialDescription) obj).getType())
- && Objects.equals(mFlattenedRequestString, ((CredentialDescription) obj)
- .getFlattenedRequestString());
- }
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 2ea9ea0..a33cd97 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -74,6 +74,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -99,13 +100,12 @@
private final IInputManager mIm;
/**
- * InputManager has historically used its own static getter {@link #getInstance()} that doesn't
- * provide a context. We provide a Context to the InputManager instance through the
- * {@link android.app.SystemServiceRegistry}. Methods that need a Context must use
- * {@link #getContext()} to obtain it.
+ * We hold a weak reference to the context to avoid leaking it indefinitely,
+ * since we currently store the input manager instance as a static variable that
+ * will outlive any context.
*/
@Nullable
- private Context mLateInitContext;
+ private WeakReference<Context> mWeakContext;
/**
* Whether a PointerIcon is shown for stylus pointers.
@@ -372,8 +372,8 @@
throw new IllegalStateException(e);
}
}
- if (sInstance.mLateInitContext == null) {
- sInstance.mLateInitContext = context;
+ if (sInstance.mWeakContext == null || sInstance.mWeakContext.get() == null) {
+ sInstance.mWeakContext = new WeakReference(context);
}
return sInstance;
}
@@ -381,9 +381,14 @@
@NonNull
private Context getContext() {
- return Objects.requireNonNull(mLateInitContext,
+ WeakReference<Context> weakContext = Objects.requireNonNull(mWeakContext,
"A context is required for InputManager. Get the InputManager instance using "
+ "Context#getSystemService before calling this method.");
+ // If we get at this point, an app calling this function could potentially expect a
+ // Context that has disappeared due to garbage collection. Holding a weak reference
+ // is a temporary solution that should be resolved before the release of a
+ // production version. This is being tracked in b/267758905
+ return Objects.requireNonNull(weakContext.get(), "missing Context");
}
/**
diff --git a/core/java/android/hardware/input/VirtualTouchEvent.java b/core/java/android/hardware/input/VirtualTouchEvent.java
index 9b1e6e8..a2bb382 100644
--- a/core/java/android/hardware/input/VirtualTouchEvent.java
+++ b/core/java/android/hardware/input/VirtualTouchEvent.java
@@ -18,6 +18,7 @@
import android.annotation.FloatRange;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
@@ -82,6 +83,10 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Action {}
+ // The maximum number of pointers that can be touching the screen at once. (See MAX_POINTERS
+ // in frameworks/native/include/input/Input.h)
+ private static final int MAX_POINTERS = 16;
+
private final int mPointerId;
private final @ToolType int mToolType;
private final @Action int mAction;
@@ -214,9 +219,17 @@
/**
* Sets the pointer id of the event.
*
+ * <p>A Valid pointer id need to be in the range of 0 to 15.
+ *
* @return this builder, to allow for chaining of calls
*/
- public @NonNull Builder setPointerId(int pointerId) {
+ public @NonNull Builder setPointerId(
+ @IntRange(from = 0, to = MAX_POINTERS - 1) int pointerId) {
+ if (pointerId < 0 || pointerId > 15) {
+ throw new IllegalArgumentException(
+ "The pointer id must be in the range 0 - " + (MAX_POINTERS - 1)
+ + "inclusive, but was: " + pointerId);
+ }
mPointerId = pointerId;
return this;
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9689be2..168db17 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1204,6 +1204,11 @@
* Upside Down Cake.
*/
public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT;
+
+ /**
+ * Vanilla Ice Cream.
+ */
+ public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 80ae8a8..6f4cdce 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -104,7 +104,7 @@
int protocol;
int portMatcher;
int portNumber;
- @nullable String bindAddress;
+ @nullable byte[] localAddress;
}
@UnsupportedAppUsage
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 1a634f5..1224941 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -32,7 +32,6 @@
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.net.LinkAddress;
import android.service.dreams.Sandman;
import android.sysprop.InitProperties;
import android.util.ArrayMap;
@@ -45,6 +44,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
@@ -3244,11 +3245,11 @@
/**
* Constant to indicate the {@link LowPowerStandbyPortDescription} refers to a TCP port.
*/
- public static final int PROTOCOL_TCP = 1;
+ public static final int PROTOCOL_TCP = 6;
/**
* Constant to indicate the {@link LowPowerStandbyPortDescription} refers to a UDP port.
*/
- public static final int PROTOCOL_UDP = 2;
+ public static final int PROTOCOL_UDP = 17;
/** @hide */
@IntDef(prefix = { "MATCH_PORT_" }, value = {
@@ -3277,7 +3278,7 @@
private final int mPortMatcher;
private final int mPortNumber;
@Nullable
- private final LinkAddress mBindAddress;
+ private final InetAddress mLocalAddress;
/**
* Describes a port.
@@ -3296,7 +3297,7 @@
this.mProtocol = protocol;
this.mPortMatcher = portMatcher;
this.mPortNumber = portNumber;
- this.mBindAddress = null;
+ this.mLocalAddress = null;
}
/**
@@ -3308,16 +3309,16 @@
* ({@link #MATCH_PORT_REMOTE}), or the destination port
* ({@link #MATCH_PORT_LOCAL}).
* @param portNumber The port number to match.
- * @param bindAddress The bind address to match.
+ * @param localAddress The local address to match.
*
* @see #newLowPowerStandbyPortsLock(List)
*/
public LowPowerStandbyPortDescription(@Protocol int protocol, @PortMatcher int portMatcher,
- int portNumber, @Nullable LinkAddress bindAddress) {
+ int portNumber, @Nullable InetAddress localAddress) {
this.mProtocol = protocol;
this.mPortMatcher = portMatcher;
this.mPortNumber = portNumber;
- this.mBindAddress = bindAddress;
+ this.mLocalAddress = localAddress;
}
private String protocolToString(int protocol) {
@@ -3383,8 +3384,8 @@
* @see #getProtocol()
*/
@Nullable
- public LinkAddress getBindAddress() {
- return mBindAddress;
+ public InetAddress getLocalAddress() {
+ return mLocalAddress;
}
@Override
@@ -3393,7 +3394,7 @@
+ "mProtocol=" + protocolToString(mProtocol)
+ ", mPortMatcher=" + portMatcherToString(mPortMatcher)
+ ", mPortNumber=" + mPortNumber
- + ", mBindAddress=" + mBindAddress
+ + ", mLocalAddress=" + mLocalAddress
+ '}';
}
@@ -3403,13 +3404,13 @@
if (!(o instanceof LowPowerStandbyPortDescription)) return false;
LowPowerStandbyPortDescription that = (LowPowerStandbyPortDescription) o;
return mProtocol == that.mProtocol && mPortMatcher == that.mPortMatcher
- && mPortNumber == that.mPortNumber && Objects.equals(mBindAddress,
- that.mBindAddress);
+ && mPortNumber == that.mPortNumber && Objects.equals(mLocalAddress,
+ that.mLocalAddress);
}
@Override
public int hashCode() {
- return Objects.hash(mProtocol, mPortMatcher, mPortNumber, mBindAddress);
+ return Objects.hash(mProtocol, mPortMatcher, mPortNumber, mLocalAddress);
}
/** @hide */
@@ -3424,8 +3425,8 @@
parcelablePortDescription.protocol = portDescription.mProtocol;
parcelablePortDescription.portMatcher = portDescription.mPortMatcher;
parcelablePortDescription.portNumber = portDescription.mPortNumber;
- if (portDescription.mBindAddress != null) {
- parcelablePortDescription.bindAddress = portDescription.mBindAddress.toString();
+ if (portDescription.mLocalAddress != null) {
+ parcelablePortDescription.localAddress = portDescription.mLocalAddress.getAddress();
}
return parcelablePortDescription;
}
@@ -3451,15 +3452,19 @@
return null;
}
- LinkAddress bindAddress = null;
- if (parcelablePortDescription.bindAddress != null) {
- bindAddress = new LinkAddress(parcelablePortDescription.bindAddress);
+ InetAddress localAddress = null;
+ if (parcelablePortDescription.localAddress != null) {
+ try {
+ localAddress = InetAddress.getByAddress(parcelablePortDescription.localAddress);
+ } catch (UnknownHostException e) {
+ Log.w(TAG, "Address has invalid length", e);
+ }
}
return new LowPowerStandbyPortDescription(
parcelablePortDescription.protocol,
parcelablePortDescription.portMatcher,
parcelablePortDescription.portNumber,
- bindAddress);
+ localAddress);
}
/** @hide */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9c55ad6..bbf7f81 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4381,11 +4381,16 @@
}
/**
- * Returns information for Primary user.
+ * Returns information for Primary user (which in practice is the same as the System user).
*
* @return the Primary user, null if not found.
+ * @deprecated For the system user, call {@link #getUserInfo} on {@link UserHandle#USER_SYSTEM},
+ * or just use {@link UserHandle#SYSTEM} or {@link UserHandle#USER_SYSTEM}.
+ * For the designated MainUser, use {@link #getMainUser()}.
+ *
* @hide
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @Nullable UserInfo getPrimaryUser() {
try {
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 5778518..cabcae3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -26,6 +26,7 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.Dialog;
import android.app.DirectAction;
import android.app.Instrumentation;
@@ -1527,8 +1528,34 @@
* <p>By default, the system will create a window for the UI for this session. If you are using
* an assistant activity instead, then you can disable the window creation by calling
* {@link #setUiEnabled} in {@link #onPrepareShow(Bundle, int)}.</p>
+ *
+ * NOTE: if the app would like to override some options to start the Activity,
+ * use {@link #startAssistantActivity(Intent, Bundle)} instead.
*/
public void startAssistantActivity(Intent intent) {
+ startAssistantActivity(intent, ActivityOptions.makeBasic().toBundle());
+ }
+
+ /**
+ * <p>Ask that a new assistant activity be started. This will create a new task in the
+ * in activity manager: this means that
+ * {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
+ * will be set for you to make it a new task.</p>
+ *
+ * <p>The newly started activity will be displayed on top of other activities in the system
+ * in a new layer that is not affected by multi-window mode. Tasks started from this activity
+ * will go into the normal activity layer and not this new layer.</p>
+ *
+ * <p>By default, the system will create a window for the UI for this session. If you are using
+ * an assistant activity instead, then you can disable the window creation by calling
+ * {@link #setUiEnabled} in {@link #onPrepareShow(Bundle, int)}.</p>
+ *
+ * @param intent the intent used to start an assistant activity
+ * @param bundle Additional options for how the Activity should be started. See
+ * {@link ActivityOptions} for how to build the Bundle supplied here.
+ */
+ public void startAssistantActivity(@NonNull Intent intent, @NonNull Bundle bundle) {
+ Objects.requireNonNull(bundle);
if (mToken == null) {
throw new IllegalStateException("Can't call before onCreate()");
}
@@ -1537,7 +1564,7 @@
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startAssistantActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()),
- mContext.getAttributionTag());
+ mContext.getAttributionTag(), bundle);
Instrumentation.checkStartActivityResult(res, intent);
} catch (RemoteException e) {
}
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
index f46c60f..da56b4b 100644
--- a/core/java/android/service/wallpaper/IWallpaperService.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -26,5 +26,5 @@
void attach(IWallpaperConnection connection,
IBinder windowToken, int windowType, boolean isPreview,
int reqWidth, int reqHeight, in Rect padding, int displayId, int which);
- void detach();
+ void detach(IBinder windowToken);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d21e5df..390fe52 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -68,9 +68,11 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.MergedConfiguration;
+import android.util.Slog;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.Gravity;
@@ -102,7 +104,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -177,8 +178,7 @@
private static final long DIMMING_ANIMATION_DURATION_MS = 300L;
- private final ArrayList<Engine> mActiveEngines
- = new ArrayList<Engine>();
+ private final ArrayMap<IBinder, IWallpaperEngineWrapper> mActiveEngines = new ArrayMap<>();
static final class WallpaperCommand {
String action;
@@ -2231,7 +2231,6 @@
final DisplayManager mDisplayManager;
final Display mDisplay;
final WallpaperManager mWallpaperManager;
- private final AtomicBoolean mDetached = new AtomicBoolean();
Engine mEngine;
@SetWallpaperFlags int mWhich;
@@ -2346,21 +2345,18 @@
mEngine.removeLocalColorsAreas(regions);
}
- public void destroy() {
- Message msg = mCaller.obtainMessage(DO_DETACH);
- mCaller.sendMessage(msg);
- }
-
- public void detach() {
- mDetached.set(true);
- }
-
public void applyDimming(float dimAmount) throws RemoteException {
Message msg = mCaller.obtainMessageI(MSG_UPDATE_DIMMING,
Float.floatToIntBits(dimAmount));
mCaller.sendMessage(msg);
}
+ public void destroy() {
+ Message msg = mCaller.obtainMessage(DO_DETACH);
+ mCaller.getHandler().removeCallbacksAndMessages(null);
+ mCaller.sendMessage(msg);
+ }
+
public void resizePreview(Rect position) {
Message msg = mCaller.obtainMessageO(MSG_RESIZE_PREVIEW, position);
mCaller.sendMessage(msg);
@@ -2383,25 +2379,27 @@
engine.detach();
Log.w(TAG, "Wallpaper host disappeared", e);
return;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Connector instance already destroyed, "
+ + "can't attach engine to non existing connector", e);
+ return;
} finally {
Trace.endSection();
}
- mActiveEngines.add(engine);
Trace.beginSection("WPMS.engine.attach");
engine.attach(this);
Trace.endSection();
}
private void doDetachEngine() {
- mActiveEngines.remove(mEngine);
- mEngine.detach();
// Some wallpapers will not trigger the rendering threads of the remaining engines even
// if they are visible, so we need to toggle the state to get their attention.
- if (!mDetached.get()) {
- for (Engine eng : mActiveEngines) {
- if (eng.mVisible) {
- eng.doVisibilityChanged(false);
- eng.doVisibilityChanged(true);
+ if (!mEngine.mDestroyed) {
+ mEngine.detach();
+ for (IWallpaperEngineWrapper engineWrapper : mActiveEngines.values()) {
+ if (engineWrapper.mEngine != null && engineWrapper.mEngine.mVisible) {
+ engineWrapper.mEngine.doVisibilityChanged(false);
+ engineWrapper.mEngine.doVisibilityChanged(true);
}
}
}
@@ -2409,12 +2407,6 @@
@Override
public void executeMessage(Message message) {
- if (mDetached.get()) {
- if (mActiveEngines.contains(mEngine)) {
- doDetachEngine();
- }
- return;
- }
switch (message.what) {
case DO_ATTACH: {
Trace.beginSection("WPMS.DO_ATTACH");
@@ -2525,7 +2517,6 @@
*/
class IWallpaperServiceWrapper extends IWallpaperService.Stub {
private final WallpaperService mTarget;
- private IWallpaperEngineWrapper mEngineWrapper;
public IWallpaperServiceWrapper(WallpaperService context) {
mTarget = context;
@@ -2536,14 +2527,27 @@
int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
int displayId, @SetWallpaperFlags int which) {
Trace.beginSection("WPMS.ServiceWrapper.attach");
- mEngineWrapper = new IWallpaperEngineWrapper(mTarget, conn, windowToken,
- windowType, isPreview, reqWidth, reqHeight, padding, displayId, which);
+ IWallpaperEngineWrapper engineWrapper =
+ new IWallpaperEngineWrapper(mTarget, conn, windowToken, windowType,
+ isPreview, reqWidth, reqHeight, padding, displayId, which);
+ mActiveEngines.put(windowToken, engineWrapper);
+ if (DEBUG) {
+ Slog.v(TAG, "IWallpaperServiceWrapper Attaching window token " + windowToken);
+ }
Trace.endSection();
}
@Override
- public void detach() {
- mEngineWrapper.detach();
+ public void detach(IBinder windowToken) {
+ IWallpaperEngineWrapper engineWrapper = mActiveEngines.remove(windowToken);
+ if (engineWrapper == null) {
+ Log.w(TAG, "Engine for window token " + windowToken + " already detached");
+ return;
+ }
+ if (DEBUG) {
+ Slog.v(TAG, "IWallpaperServiceWrapper Detaching window token " + windowToken);
+ }
+ engineWrapper.destroy();
}
}
@@ -2558,8 +2562,8 @@
public void onDestroy() {
Trace.beginSection("WPMS.onDestroy");
super.onDestroy();
- for (int i=0; i<mActiveEngines.size(); i++) {
- mActiveEngines.get(i).detach();
+ for (IWallpaperEngineWrapper engineWrapper : mActiveEngines.values()) {
+ engineWrapper.destroy();
}
mActiveEngines.clear();
Trace.endSection();
@@ -2586,8 +2590,12 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter out, String[] args) {
out.print("State of wallpaper "); out.print(this); out.println(":");
- for (int i=0; i<mActiveEngines.size(); i++) {
- Engine engine = mActiveEngines.get(i);
+ for (IWallpaperEngineWrapper engineWrapper : mActiveEngines.values()) {
+ Engine engine = engineWrapper.mEngine;
+ if (engine == null) {
+ Slog.w(TAG, "Engine for wrapper " + engineWrapper + " not attached");
+ continue;
+ }
out.print(" Engine "); out.print(engine); out.println(":");
engine.dump(" ", fd, out, args);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 725eb51..e7cefd6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -108,6 +108,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -1105,6 +1106,26 @@
public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
/**
+ * Whether the device supports the WindowManager Extensions.
+ * OEMs can enable this by having their device config to inherit window_extensions.mk, such as:
+ * <pre>
+ * $(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)
+ * </pre>
+ * @hide
+ */
+ boolean WINDOW_EXTENSIONS_ENABLED =
+ SystemProperties.getBoolean("persist.wm.extensions.enabled", false);
+
+ /**
+ * @see #WINDOW_EXTENSIONS_ENABLED
+ * @hide
+ */
+ @TestApi
+ static boolean hasWindowExtensionsEnabled() {
+ return WINDOW_EXTENSIONS_ENABLED;
+ }
+
+ /**
* Application-level
* {@link android.content.pm.PackageManager.Property PackageManager.Property}
* tag that specifies whether OEMs are permitted to provide activity
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 5eb9786..6b40d98 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -51,7 +51,7 @@
int startVoiceActivity(IBinder token, in Intent intent, String resolvedType,
String attributionTag);
int startAssistantActivity(IBinder token, in Intent intent, String resolvedType,
- String attributionTag);
+ String attributionTag, in Bundle bundle);
void setKeepAwake(IBinder token, boolean keepAwake);
void closeSystemDialogs(IBinder token);
void finish(IBinder token);
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 47b83be..ae192a4 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -45,8 +45,13 @@
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
import android.widget.Toast;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -151,17 +156,60 @@
if (isResolverActivityResolveInfo(targetResolveInfo)) {
launchResolverActivityWithCorrectTab(intentReceived, className, newIntent,
callingUserId, targetUserId);
- return targetResolveInfo;
+ // When switching to the personal profile, automatically start the activity
+ } else if (className.equals(FORWARD_INTENT_TO_PARENT)) {
+ startActivityAsCaller(newIntent, targetUserId);
}
- startActivityAsCaller(newIntent, targetUserId);
return targetResolveInfo;
}, mExecutorService)
.thenAcceptAsync(result -> {
- maybeShowDisclosure(intentReceived, result, userMessage);
- finish();
+ // When switching to the personal profile, inform user after starting activity
+ if (className.equals(FORWARD_INTENT_TO_PARENT)) {
+ maybeShowDisclosure(intentReceived, result, userMessage);
+ finish();
+ // When switching to the work profile, ask the user for consent before launching
+ } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+ maybeShowUserConsentMiniResolver(result, newIntent, targetUserId);
+ }
}, getApplicationContext().getMainExecutor());
}
+ private void maybeShowUserConsentMiniResolver(
+ ResolveInfo target, Intent launchIntent, int targetUserId) {
+ if (target == null || isIntentForwarderResolveInfo(target) || !isDeviceProvisioned()) {
+ finish();
+ return;
+ }
+
+ int layoutId = R.layout.miniresolver;
+ setContentView(layoutId);
+
+ findViewById(R.id.title_container).setElevation(0);
+
+ ImageView icon = findViewById(R.id.icon);
+ PackageManager packageManagerForTargetUser =
+ createContextAsUser(UserHandle.of(targetUserId), /* flags= */ 0)
+ .getPackageManager();
+ icon.setImageDrawable(target.loadIcon(packageManagerForTargetUser));
+
+ View buttonContainer = findViewById(R.id.button_bar_container);
+ buttonContainer.setPadding(0, 0, 0, buttonContainer.getPaddingBottom());
+
+ ((TextView) findViewById(R.id.open_cross_profile)).setText(
+ getResources().getString(
+ R.string.miniresolver_open_in_work,
+ target.loadLabel(packageManagerForTargetUser)));
+
+ // The mini-resolver's negative button is reused in this flow to cancel the intent
+ ((Button) findViewById(R.id.use_same_profile_browser)).setText(R.string.cancel);
+ findViewById(R.id.use_same_profile_browser).setOnClickListener(v -> finish());
+
+ findViewById(R.id.button_open).setOnClickListener(v -> {
+ startActivityAsCaller(launchIntent, targetUserId);
+ finish();
+ });
+ }
+
private String getForwardToPersonalMessage() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e9771a9..22dbb26 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7688,8 +7688,11 @@
</activity>
<activity android:name="com.android.internal.app.IntentForwarderActivity"
android:finishOnCloseSystemDialogs="true"
- android:theme="@style/Theme.Translucent.NoTitleBar"
+ android:theme="@style/Theme.DeviceDefault.Resolver"
android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
android:label="@string/user_owner_label"
android:exported="true"
android:visibleToInstantApps="true"
diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml
index 38a71f0..d07ad89 100644
--- a/core/res/res/layout/miniresolver.xml
+++ b/core/res/res/layout/miniresolver.xml
@@ -14,6 +14,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+
+<!-- Layout used to decide whether to launch a single target in another profile.
+ When this layout is used in ResolverActivity, the user can choose between a verified app in the
+ other profile and the default browser in the current profile.
+ In IntentForwarderActivity, they choose whether to launch in the other profile or cancel. -->
<com.android.internal.widget.ResolverDrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -24,6 +29,7 @@
android:id="@id/contentPanel">
<RelativeLayout
+ android:id="@+id/title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d1bef47..b9e5366 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9026,10 +9026,10 @@
{@link android.os.Build.VERSION_CODES#N} and not used in previous versions. -->
<attr name="supportsLocalInteraction" format="boolean" />
<!-- The service that provides {@link android.service.voice.HotwordDetectionService}.
- @hide @SystemApi -->
+ Expect a component name to be provided. @hide @SystemApi -->
<attr name="hotwordDetectionService" format="string" />
<!-- The service that provides {@link android.service.voice.VisualQueryDetectionService}.
- @hide @SystemApi -->
+ Expect a component name to be provided. @hide @SystemApi -->
<attr name="visualQueryDetectionService" format="string" />
</declare-styleable>
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
new file mode 100644
index 0000000..fda08ff
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2023 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.animation;
+
+import static org.junit.Assert.assertEquals;
+
+import android.util.PollingCheck;
+import android.view.View;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+@MediumTest
+public class AnimatorSetCallsTest {
+ @Rule
+ public final ActivityScenarioRule<AnimatorSetActivity> mRule =
+ new ActivityScenarioRule<>(AnimatorSetActivity.class);
+
+ private AnimatorSetActivity mActivity;
+ private AnimatorSet mSet1;
+ private CountListener mListener1;
+ private CountListener mListener2;
+ private CountListener mListener3;
+
+ @Before
+ public void setUp() throws Exception {
+ mRule.getScenario().onActivity((activity) -> {
+ mActivity = activity;
+ View square = mActivity.findViewById(R.id.square1);
+
+ mSet1 = new AnimatorSet();
+ mListener1 = new CountListener();
+ mSet1.addListener(mListener1);
+ mSet1.addPauseListener(mListener1);
+
+ AnimatorSet set2 = new AnimatorSet();
+ mListener2 = new CountListener();
+ set2.addListener(mListener2);
+ set2.addPauseListener(mListener2);
+
+ ObjectAnimator anim = ObjectAnimator.ofFloat(square, "translationX", 0f, 100f);
+ mListener3 = new CountListener();
+ anim.addListener(mListener3);
+ anim.addPauseListener(mListener3);
+ anim.setDuration(1);
+
+ set2.play(anim);
+ mSet1.play(set2);
+ });
+ }
+
+ @Test
+ public void startEndCalledOnChildren() {
+ mRule.getScenario().onActivity((a) -> mSet1.start());
+ waitForOnUiThread(() -> mListener1.endForward > 0);
+
+ // only startForward and endForward should have been called once
+ mListener1.assertValues(
+ 1, 0, 1, 0, 0, 0, 0, 0
+ );
+ mListener2.assertValues(
+ 1, 0, 1, 0, 0, 0, 0, 0
+ );
+ mListener3.assertValues(
+ 1, 0, 1, 0, 0, 0, 0, 0
+ );
+ }
+
+ @Test
+ public void cancelCalledOnChildren() {
+ mRule.getScenario().onActivity((a) -> {
+ mSet1.start();
+ mSet1.cancel();
+ });
+ waitForOnUiThread(() -> mListener1.endForward > 0);
+
+ // only startForward and endForward should have been called once
+ mListener1.assertValues(
+ 1, 0, 1, 0, 1, 0, 0, 0
+ );
+ mListener2.assertValues(
+ 1, 0, 1, 0, 1, 0, 0, 0
+ );
+ mListener3.assertValues(
+ 1, 0, 1, 0, 1, 0, 0, 0
+ );
+ }
+
+ @Test
+ public void startEndReversedCalledOnChildren() {
+ mRule.getScenario().onActivity((a) -> mSet1.reverse());
+ waitForOnUiThread(() -> mListener1.endReverse > 0);
+
+ // only startForward and endForward should have been called once
+ mListener1.assertValues(
+ 0, 1, 0, 1, 0, 0, 0, 0
+ );
+ mListener2.assertValues(
+ 0, 1, 0, 1, 0, 0, 0, 0
+ );
+ mListener3.assertValues(
+ 0, 1, 0, 1, 0, 0, 0, 0
+ );
+ }
+
+ @Test
+ public void pauseResumeCalledOnChildren() {
+ mRule.getScenario().onActivity((a) -> {
+ mSet1.start();
+ mSet1.pause();
+ });
+ waitForOnUiThread(() -> mListener1.pause > 0);
+
+ // only startForward and pause should have been called once
+ mListener1.assertValues(
+ 1, 0, 0, 0, 0, 0, 1, 0
+ );
+ mListener2.assertValues(
+ 1, 0, 0, 0, 0, 0, 1, 0
+ );
+ mListener3.assertValues(
+ 1, 0, 0, 0, 0, 0, 1, 0
+ );
+
+ mRule.getScenario().onActivity((a) -> mSet1.resume());
+ waitForOnUiThread(() -> mListener1.endForward > 0);
+
+ // resume and endForward should have been called once
+ mListener1.assertValues(
+ 1, 0, 1, 0, 0, 0, 1, 1
+ );
+ mListener2.assertValues(
+ 1, 0, 1, 0, 0, 0, 1, 1
+ );
+ mListener3.assertValues(
+ 1, 0, 1, 0, 0, 0, 1, 1
+ );
+ }
+
+ private void waitForOnUiThread(PollingCheck.PollingCheckCondition condition) {
+ final boolean[] value = new boolean[1];
+ PollingCheck.waitFor(() -> {
+ mActivity.runOnUiThread(() -> value[0] = condition.canProceed());
+ return value[0];
+ });
+ }
+
+ private static class CountListener implements Animator.AnimatorListener,
+ Animator.AnimatorPauseListener {
+ public int startNoParam;
+ public int endNoParam;
+ public int startReverse;
+ public int startForward;
+ public int endForward;
+ public int endReverse;
+ public int cancel;
+ public int repeat;
+ public int pause;
+ public int resume;
+
+ public void assertValues(
+ int startForward,
+ int startReverse,
+ int endForward,
+ int endReverse,
+ int cancel,
+ int repeat,
+ int pause,
+ int resume
+ ) {
+ assertEquals(0, startNoParam);
+ assertEquals(0, endNoParam);
+ assertEquals(startForward, this.startForward);
+ assertEquals(startReverse, this.startReverse);
+ assertEquals(endForward, this.endForward);
+ assertEquals(endReverse, this.endReverse);
+ assertEquals(cancel, this.cancel);
+ assertEquals(repeat, this.repeat);
+ assertEquals(pause, this.pause);
+ assertEquals(resume, this.resume);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation, boolean isReverse) {
+ if (isReverse) {
+ startReverse++;
+ } else {
+ startForward++;
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ if (isReverse) {
+ endReverse++;
+ } else {
+ endForward++;
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ startNoParam++;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endNoParam++;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ cancel++;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ repeat++;
+ }
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ pause++;
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ resume++;
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
index 81cd4da..8cc88ea 100644
--- a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
@@ -135,11 +135,15 @@
* @throws Exception
*/
@Before
- public void setUp() throws Exception {
+ public void setUp() throws Throwable {
final BasicAnimatorActivity activity = mActivityRule.getActivity();
Button button = activity.findViewById(R.id.animatingButton);
mAnimator = button.animate().x(100).y(100);
+ mActivityRule.runOnUiThread(() -> {
+ mAnimator.start();
+ mAnimator.cancel();
+ });
// mListener is the main testing mechanism of this file. The asserts of each test
// are embedded in the listener callbacks that it implements.
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index a663095..58cfc66 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -16,6 +16,12 @@
package com.android.internal.app;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -53,6 +59,7 @@
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -140,6 +147,8 @@
@Test
public void forwardToManagedProfile_canForward_sendIntent() throws Exception {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
+ sActivityName = "MyTestActivity";
+ sPackageName = "test.package.name";
// Intent can be forwarded.
when(mIPm.canForwardTo(
@@ -160,7 +169,13 @@
verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt());
assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
- assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ onView(withId(R.id.icon)).check(matches(isDisplayed()));
+ onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
+ onView(withId(R.id.use_same_profile_browser)).check(matches(isDisplayed()));
+ onView(withId(R.id.button_open)).perform(click());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
assertNotNull(activity.mStartActivityIntent);
assertEquals(Intent.ACTION_SEND, activity.mStartActivityIntent.getAction());
assertNull(activity.mStartActivityIntent.getPackage());
@@ -250,6 +265,8 @@
@Test
public void forwardToManagedProfile_canForward_selectorIntent() throws Exception {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
+ sActivityName = "MyTestActivity";
+ sPackageName = "test.package.name";
// Intent can be forwarded.
when(mIPm.canForwardTo(
@@ -264,6 +281,7 @@
// Create selector intent.
Intent intent = Intent.makeMainSelectorActivity(
Intent.ACTION_VIEW, Intent.CATEGORY_BROWSABLE);
+
IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -271,6 +289,13 @@
intentCaptor.capture(), nullable(String.class), anyInt(), anyInt());
assertEquals(Intent.ACTION_VIEW, intentCaptor.getValue().getAction());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ onView(withId(R.id.icon)).check(matches(isDisplayed()));
+ onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
+ onView(withId(R.id.use_same_profile_browser)).check(matches(isDisplayed()));
+ onView(withId(R.id.button_open)).perform(click());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
assertNotNull(activity.mStartActivityIntent);
assertEquals(Intent.ACTION_MAIN, activity.mStartActivityIntent.getAction());
assertNull(activity.mStartActivityIntent.getPackage());
@@ -608,7 +633,7 @@
}
private void setupShouldSkipDisclosureTest() throws RemoteException {
- sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
+ sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
sActivityName = "MyTestActivity";
sPackageName = "test.package.name";
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
@@ -619,6 +644,7 @@
profiles.add(CURRENT_USER_INFO);
profiles.add(MANAGED_PROFILE_INFO);
when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
+ when(mUserManager.getProfileParent(anyInt())).thenReturn(CURRENT_USER_INFO);
// Intent can be forwarded.
when(mIPm.canForwardTo(
any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
@@ -654,6 +680,11 @@
}
@Override
+ public Context createContextAsUser(UserHandle user, int flags) {
+ return this;
+ }
+
+ @Override
protected MetricsLogger getMetricsLogger() {
return mMetricsLogger;
}
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index ff8d96d..421bc25 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -102,11 +102,29 @@
to pre-existing users, but cannot uninstall pre-existing system packages from pre-existing users.
-->
<config>
+ <!-- Bluetooth (com.android.btservices apex) - visible on the sharesheet -->
+ <install-in-user-type package="com.android.bluetooth">
+ <install-in user-type="SYSTEM" />
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ <do-not-install-in user-type="android.os.usertype.profile.CLONE" />
+ </install-in-user-type>
+
+ <!-- Settings (Settings app) -->
+ <install-in-user-type package="com.android.settings">
+ <install-in user-type="SYSTEM" />
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+
+ <!-- Settings Storage (SettingsProvider) -->
<install-in-user-type package="com.android.providers.settings">
<install-in user-type="SYSTEM" />
<install-in user-type="FULL" />
<install-in user-type="PROFILE" />
</install-in-user-type>
+
+ <!-- WallpaperBackup (WallpaperBackup)-->
<install-in-user-type package="com.android.wallpaperbackup">
<install-in user-type="FULL" />
</install-in-user-type>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d726b67..71050fa 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -506,6 +506,8 @@
<permission name="android.permission.ACCESS_BROADCAST_RADIO"/>
<!-- Permission required for CTS test - CtsAmbientContextServiceTestCases -->
<permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/>
+ <!-- Permission required for CTS test - CtsTelephonyProviderTestCases -->
+ <permission name="android.permission.WRITE_APN_SETTINGS"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 65923ff..67ca9a1 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -24,7 +24,11 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="run-command" value="settings put system show_touches 1" />
+ <option name="run-command" value="settings put system pointer_location 1" />
<option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
+ <option name="teardown-command" value="settings delete system show_touches" />
+ <option name="teardown-command" value="settings delete system pointer_location" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index b0896da..33c9eac 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -21,7 +21,7 @@
#ifdef __ANDROID__
#include "HWUIProperties.sysprop.h"
#endif
-#include "SkTraceEventCommon.h"
+#include "src/core/SkTraceEventCommon.h"
#include <algorithm>
#include <cstdlib>
diff --git a/libs/hwui/jni/MaskFilter.cpp b/libs/hwui/jni/MaskFilter.cpp
index 048ce02..cbd4520 100644
--- a/libs/hwui/jni/MaskFilter.cpp
+++ b/libs/hwui/jni/MaskFilter.cpp
@@ -1,6 +1,5 @@
#include "GraphicsJNI.h"
#include "SkMaskFilter.h"
-#include "SkBlurMask.h"
#include "SkBlurMaskFilter.h"
#include "SkBlurTypes.h"
#include "SkTableMaskFilter.h"
@@ -11,6 +10,13 @@
}
}
+// From https://skia.googlesource.com/skia/+/d74c99a3cd5eef5f16b2eb226e6b45fe523c8552/src/core/SkBlurMask.cpp#28
+static constexpr float kBLUR_SIGMA_SCALE = 0.57735f;
+
+static float convertRadiusToSigma(float radius) {
+ return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
class SkMaskFilterGlue {
public:
static void destructor(JNIEnv* env, jobject, jlong filterHandle) {
@@ -19,7 +25,7 @@
}
static jlong createBlur(JNIEnv* env, jobject, jfloat radius, jint blurStyle) {
- SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
+ SkScalar sigma = convertRadiusToSigma(radius);
SkMaskFilter* filter = SkMaskFilter::MakeBlur((SkBlurStyle)blurStyle, sigma).release();
ThrowIAE_IfNull(env, filter);
return reinterpret_cast<jlong>(filter);
@@ -34,7 +40,7 @@
direction[i] = values[i];
}
- SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
+ SkScalar sigma = convertRadiusToSigma(radius);
SkMaskFilter* filter = SkBlurMaskFilter::MakeEmboss(sigma,
direction, ambient, specular).release();
ThrowIAE_IfNull(env, filter);
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 41ac285..e886558 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -41,7 +41,6 @@
</activity>
<activity android:label="Camera2CtsActivity"
android:name="Camera2SurfaceViewActivity"
- android:screenOrientation="landscape"
android:configChanges="keyboardHidden|orientation|screenSize"
android:showWhenLocked="true"
android:turnScreenOn="true"
diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp
index 9b0e044..bf4c858 100644
--- a/packages/SettingsLib/ActionBarShadow/Android.bp
+++ b/packages/SettingsLib/ActionBarShadow/Android.bp
@@ -22,7 +22,8 @@
min_sdk_version: "28",
apex_available: [
"//apex_available:platform",
- "com.android.permission",
"com.android.adservices",
+ "com.android.extservices",
+ "com.android.permission",
],
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 6330848f..e9000a8 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -27,6 +27,7 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
+ "com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
],
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 825e6ac..33aa985 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -25,6 +25,7 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
+ "com.android.extservices",
"com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 09691f1..d26ad1c 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -9,18 +9,14 @@
android_library {
name: "SettingsLibSettingsTheme",
-
resource_dirs: ["res"],
-
- static_libs: [
- "androidx.preference_preference",
- ],
-
+ static_libs: ["androidx.preference_preference"],
sdk_version: "system_current",
min_sdk_version: "21",
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
+ "com.android.extservices",
"com.android.permission",
"com.android.adservices",
"com.android.healthfitness",
diff --git a/packages/SettingsLib/SettingsTransition/Android.bp b/packages/SettingsLib/SettingsTransition/Android.bp
index 7f9014c..0f9f781 100644
--- a/packages/SettingsLib/SettingsTransition/Android.bp
+++ b/packages/SettingsLib/SettingsTransition/Android.bp
@@ -22,6 +22,7 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
+ "com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
],
diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp
index 644e990..33ba64a 100644
--- a/packages/SettingsLib/Utils/Android.bp
+++ b/packages/SettingsLib/Utils/Android.bp
@@ -24,8 +24,9 @@
"//apex_available:platform",
"com.android.adservices",
- "com.android.permission",
"com.android.cellbroadcast",
+ "com.android.extservices",
"com.android.healthfitness",
+ "com.android.permission",
],
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0f67124..82ca63d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -819,6 +819,9 @@
<!-- Permission required for CTS test - ActivityCaptureCallbackTests -->
<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
+ <!-- Permission required for CTS test - CtsTelephonyProviderTestCases -->
+ <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index addae72..13e2bca 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -683,7 +683,10 @@
public void onTrustManagedChanged(boolean managed, int userId) {
Assert.isMainThread();
mUserTrustIsManaged.put(userId, managed);
- mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+ boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+ mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+ trustUsuallyManaged, "onTrustManagedChanged");
+ mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -2350,8 +2353,12 @@
updateSecondaryLockscreenRequirement(user);
List<UserInfo> allUsers = mUserManager.getUsers();
for (UserInfo userInfo : allUsers) {
+ boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userInfo.id);
+ mLogger.logTrustUsuallyManagedUpdated(userInfo.id,
+ mUserTrustIsUsuallyManaged.get(userInfo.id),
+ trustUsuallyManaged, "init from constructor");
mUserTrustIsUsuallyManaged.put(userInfo.id,
- mTrustManager.isTrustUsuallyManaged(userInfo.id));
+ trustUsuallyManaged);
}
updateAirplaneModeState();
@@ -2391,9 +2398,11 @@
}
private void updateFaceEnrolled(int userId) {
- mIsFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty()
+ Boolean isFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty()
&& mBiometricEnabledForUser.get(userId)
&& mAuthController.isFaceAuthEnrolled(userId);
+ mIsFaceEnrolled = isFaceEnrolled;
+ mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
}
public boolean isFaceSupported() {
@@ -3052,9 +3061,13 @@
@VisibleForTesting
boolean isUnlockWithFingerprintPossible(int userId) {
// TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
- mIsUnlockWithFingerprintPossible.put(userId, mFpm != null
+ boolean fpEnrolled = mFpm != null
&& !mFingerprintSensorProperties.isEmpty()
- && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
+ && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId);
+ mLogger.logFpEnrolledUpdated(userId,
+ mIsUnlockWithFingerprintPossible.getOrDefault(userId, false),
+ fpEnrolled);
+ mIsUnlockWithFingerprintPossible.put(userId, fpEnrolled);
return mIsUnlockWithFingerprintPossible.get(userId);
}
@@ -3170,7 +3183,10 @@
void handleUserSwitching(int userId, IRemoteCallback reply) {
Assert.isMainThread();
clearBiometricRecognized();
- mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+ boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+ mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+ trustUsuallyManaged, "userSwitching");
+ mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index c414c08..7707e1f 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -26,6 +26,7 @@
import com.android.keyguard.KeyguardListenModel
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.TrustGrantFlags
+import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.log.LogLevel.DEBUG
@@ -33,18 +34,15 @@
import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.plugins.log.LogLevel.VERBOSE
import com.android.systemui.plugins.log.LogLevel.WARNING
-import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
private const val TAG = "KeyguardUpdateMonitorLog"
-/**
- * Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor]
- */
-class KeyguardUpdateMonitorLogger @Inject constructor(
- @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer
-) {
+/** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */
+class KeyguardUpdateMonitorLogger
+@Inject
+constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG)
fun e(@CompileTimeConstant msg: String) = log(msg, ERROR)
@@ -56,15 +54,16 @@
fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg)
fun logActiveUnlockTriggered(reason: String?) {
- logBuffer.log("ActiveUnlock", DEBUG,
- { str1 = reason },
- { "initiate active unlock triggerReason=$str1" })
+ logBuffer.log(
+ "ActiveUnlock",
+ DEBUG,
+ { str1 = reason },
+ { "initiate active unlock triggerReason=$str1" }
+ )
}
fun logAuthInterruptDetected(active: Boolean) {
- logBuffer.log(TAG, DEBUG,
- { bool1 = active },
- { "onAuthInterruptDetected($bool1)" })
+ logBuffer.log(TAG, DEBUG, { bool1 = active }, { "onAuthInterruptDetected($bool1)" })
}
fun logBroadcastReceived(action: String?) {
@@ -72,9 +71,12 @@
}
fun logDeviceProvisionedState(deviceProvisioned: Boolean) {
- logBuffer.log(TAG, DEBUG,
- { bool1 = deviceProvisioned },
- { "DEVICE_PROVISIONED state = $bool1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { bool1 = deviceProvisioned },
+ { "DEVICE_PROVISIONED state = $bool1" }
+ )
}
fun logException(ex: Exception, @CompileTimeConstant logMsg: String) {
@@ -82,46 +84,56 @@
}
fun logFaceAcquired(acquireInfo: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = acquireInfo },
- { "Face acquired acquireInfo=$int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = acquireInfo }, { "Face acquired acquireInfo=$int1" })
}
fun logFaceAuthDisabledForUser(userId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = userId },
- { "Face authentication disabled by DPM for userId: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = userId },
+ { "Face authentication disabled by DPM for userId: $int1" }
+ )
}
fun logFaceAuthError(msgId: Int, originalErrMsg: String) {
- logBuffer.log(TAG, DEBUG, {
- str1 = originalErrMsg
- int1 = msgId
- }, { "Face error received: $str1 msgId= $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = originalErrMsg
+ int1 = msgId
+ },
+ { "Face error received: $str1 msgId= $int1" }
+ )
}
fun logFaceAuthForWrongUser(authUserId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = authUserId },
- { "Face authenticated for wrong user: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = authUserId },
+ { "Face authenticated for wrong user: $int1" }
+ )
}
fun logFaceAuthHelpMsg(msgId: Int, helpMsg: String?) {
- logBuffer.log(TAG, DEBUG, {
- int1 = msgId
- str1 = helpMsg
- }, { "Face help received, msgId: $int1 msg: $str1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = msgId
+ str1 = helpMsg
+ },
+ { "Face help received, msgId: $int1 msg: $str1" }
+ )
}
fun logFaceAuthRequested(reason: String?) {
- logBuffer.log(TAG, DEBUG, {
- str1 = reason
- }, { "requestFaceAuth() reason=$str1" })
+ logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" })
}
fun logFaceAuthSuccess(userId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = userId },
- { "Face auth succeeded for user $int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" })
}
fun logFaceLockoutReset(@LockoutMode mode: Int) {
@@ -133,21 +145,30 @@
}
fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) {
- logBuffer.log(TAG, DEBUG,
- { bool1 = isFaceUnlockPossible },
- {"isUnlockWithFacePossible: $bool1"})
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { bool1 = isFaceUnlockPossible },
+ { "isUnlockWithFacePossible: $bool1" }
+ )
}
fun logFingerprintAuthForWrongUser(authUserId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = authUserId },
- { "Fingerprint authenticated for wrong user: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = authUserId },
+ { "Fingerprint authenticated for wrong user: $int1" }
+ )
}
fun logFingerprintDisabledForUser(userId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = userId },
- { "Fingerprint disabled by DPM for userId: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = userId },
+ { "Fingerprint disabled by DPM for userId: $int1" }
+ )
}
fun logFingerprintLockoutReset(@LockoutMode mode: Int) {
@@ -155,42 +176,63 @@
}
fun logFingerprintRunningState(fingerprintRunningState: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = fingerprintRunningState },
- { "fingerprintRunningState: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = fingerprintRunningState },
+ { "fingerprintRunningState: $int1" }
+ )
}
fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) {
- logBuffer.log(TAG, DEBUG, {
- int1 = userId
- bool1 = isStrongBiometric
- }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = isStrongBiometric
+ },
+ { "Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1" }
+ )
}
fun logFingerprintError(msgId: Int, originalErrMsg: String) {
- logBuffer.log(TAG, DEBUG, {
- str1 = originalErrMsg
- int1 = msgId
- }, { "Fingerprint error received: $str1 msgId= $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = originalErrMsg
+ int1 = msgId
+ },
+ { "Fingerprint error received: $str1 msgId= $int1" }
+ )
}
fun logInvalidSubId(subId: Int) {
- logBuffer.log(TAG, INFO,
- { int1 = subId },
- { "Previously active sub id $int1 is now invalid, will remove" })
+ logBuffer.log(
+ TAG,
+ INFO,
+ { int1 = subId },
+ { "Previously active sub id $int1 is now invalid, will remove" }
+ )
}
fun logPrimaryKeyguardBouncerChanged(
- primaryBouncerIsOrWillBeShowing: Boolean,
- primaryBouncerFullyShown: Boolean
+ primaryBouncerIsOrWillBeShowing: Boolean,
+ primaryBouncerFullyShown: Boolean
) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = primaryBouncerIsOrWillBeShowing
- bool2 = primaryBouncerFullyShown
- }, {
- "handlePrimaryBouncerChanged " +
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = primaryBouncerIsOrWillBeShowing
+ bool2 = primaryBouncerFullyShown
+ },
+ {
+ "handlePrimaryBouncerChanged " +
"primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2"
- })
+ }
+ )
}
fun logKeyguardListenerModel(model: KeyguardListenModel) {
@@ -198,98 +240,134 @@
}
fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = showing
- bool2 = occluded
- bool3 = visible
- }, {
- "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)"
- })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = showing
+ bool2 = occluded
+ bool3 = visible
+ },
+ { "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" }
+ )
}
fun logMissingSupervisorAppError(userId: Int) {
- logBuffer.log(TAG, ERROR,
- { int1 = userId },
- { "No Profile Owner or Device Owner supervision app found for User $int1" })
+ logBuffer.log(
+ TAG,
+ ERROR,
+ { int1 = userId },
+ { "No Profile Owner or Device Owner supervision app found for User $int1" }
+ )
}
fun logPhoneStateChanged(newState: String?) {
- logBuffer.log(TAG, DEBUG,
- { str1 = newState },
- { "handlePhoneStateChanged($str1)" })
+ logBuffer.log(TAG, DEBUG, { str1 = newState }, { "handlePhoneStateChanged($str1)" })
}
fun logRegisterCallback(callback: KeyguardUpdateMonitorCallback?) {
- logBuffer.log(TAG, VERBOSE,
- { str1 = "$callback" },
- { "*** register callback for $str1" })
+ logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" })
}
fun logRetryingAfterFaceHwUnavailable(retryCount: Int) {
- logBuffer.log(TAG, WARNING,
- { int1 = retryCount },
- { "Retrying face after HW unavailable, attempt $int1" })
+ logBuffer.log(
+ TAG,
+ WARNING,
+ { int1 = retryCount },
+ { "Retrying face after HW unavailable, attempt $int1" }
+ )
}
fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) {
- logBuffer.log(TAG, DEBUG, {
- int1 = msgId
- int2 = delay
- str1 = "$errString"
- }, {
- "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1"
- })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = msgId
+ int2 = delay
+ str1 = "$errString"
+ },
+ { "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" }
+ )
}
fun logRetryAfterFpHwUnavailable(retryCount: Int) {
- logBuffer.log(TAG, WARNING,
- { int1 = retryCount },
- { "Retrying fingerprint attempt: $int1" })
+ logBuffer.log(
+ TAG,
+ WARNING,
+ { int1 = retryCount },
+ { "Retrying fingerprint attempt: $int1" }
+ )
}
fun logSendPrimaryBouncerChanged(
primaryBouncerIsOrWillBeShowing: Boolean,
primaryBouncerFullyShown: Boolean,
) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = primaryBouncerIsOrWillBeShowing
- bool2 = primaryBouncerFullyShown
- }, {
- "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = primaryBouncerIsOrWillBeShowing
+ bool2 = primaryBouncerFullyShown
+ },
+ {
+ "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
"primaryBouncerFullyShown=$bool2"
- })
+ }
+ )
}
fun logServiceStateChange(subId: Int, serviceState: ServiceState?) {
- logBuffer.log(TAG, DEBUG, {
- int1 = subId
- str1 = "$serviceState"
- }, { "handleServiceStateChange(subId=$int1, serviceState=$str1)" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = subId
+ str1 = "$serviceState"
+ },
+ { "handleServiceStateChange(subId=$int1, serviceState=$str1)" }
+ )
}
fun logServiceStateIntent(action: String?, serviceState: ServiceState?, subId: Int) {
- logBuffer.log(TAG, VERBOSE, {
- str1 = action
- str2 = "$serviceState"
- int1 = subId
- }, { "action $str1 serviceState=$str2 subId=$int1" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = action
+ str2 = "$serviceState"
+ int1 = subId
+ },
+ { "action $str1 serviceState=$str2 subId=$int1" }
+ )
}
fun logSimState(subId: Int, slotId: Int, state: Int) {
- logBuffer.log(TAG, DEBUG, {
- int1 = subId
- int2 = slotId
- long1 = state.toLong()
- }, { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = subId
+ int2 = slotId
+ long1 = state.toLong()
+ },
+ { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" }
+ )
}
fun logSimStateFromIntent(action: String?, extraSimState: String?, slotId: Int, subId: Int) {
- logBuffer.log(TAG, VERBOSE, {
- str1 = action
- str2 = extraSimState
- int1 = slotId
- int2 = subId
- }, { "action $str1 state: $str2 slotId: $int1 subid: $int2" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = action
+ str2 = extraSimState
+ int1 = slotId
+ int2 = subId
+ },
+ { "action $str1 state: $str2 slotId: $int1 subid: $int2" }
+ )
}
fun logSimUnlocked(subId: Int) {
@@ -297,78 +375,98 @@
}
fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) {
- logBuffer.log(TAG, VERBOSE, {
- int1 = faceRunningState
- str1 = faceAuthUiEvent.reason
- str2 = faceAuthUiEvent.extraInfoToString()
- }, { "startListeningForFace(): $int1, reason: $str1 $str2" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = faceRunningState
+ str1 = faceAuthUiEvent.reason
+ str2 = faceAuthUiEvent.extraInfoToString()
+ },
+ { "startListeningForFace(): $int1, reason: $str1 $str2" }
+ )
}
fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) {
- logBuffer.log(TAG, VERBOSE, {
- int1 = faceRunningState
- str1 = PowerManager.wakeReasonToString(pmWakeReason)
- }, { "startListeningForFace(): $int1, reason: wakeUp-$str1" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = faceRunningState
+ str1 = PowerManager.wakeReasonToString(pmWakeReason)
+ },
+ { "startListeningForFace(): $int1, reason: wakeUp-$str1" }
+ )
}
fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
- logBuffer.log(TAG, VERBOSE, {
- int1 = faceRunningState
- str1 = faceAuthReason
- }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = faceRunningState
+ str1 = faceAuthReason
+ },
+ { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }
+ )
}
fun logSubInfo(subInfo: SubscriptionInfo?) {
- logBuffer.log(TAG, VERBOSE,
- { str1 = "$subInfo" },
- { "SubInfo:$str1" })
+ logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" })
}
fun logTimeFormatChanged(newTimeFormat: String?) {
- logBuffer.log(TAG, DEBUG,
- { str1 = newTimeFormat },
- { "handleTimeFormatUpdate timeFormat=$str1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = newTimeFormat },
+ { "handleTimeFormatUpdate timeFormat=$str1" }
+ )
}
fun logUdfpsPointerDown(sensorId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = sensorId },
- { "onUdfpsPointerDown, sensorId: $int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerDown, sensorId: $int1" })
}
fun logUdfpsPointerUp(sensorId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = sensorId },
- { "onUdfpsPointerUp, sensorId: $int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" })
}
fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) {
- logBuffer.log(TAG, ERROR, {
- int1 = faceRunningState
- bool1 = unlockPossible
- }, {
- "Cancellation signal is not null, high chance of bug in " +
- "face auth lifecycle management. " +
- "Face state: $int1, unlockPossible: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ ERROR,
+ {
+ int1 = faceRunningState
+ bool1 = unlockPossible
+ },
+ {
+ "Cancellation signal is not null, high chance of bug in " +
+ "face auth lifecycle management. " +
+ "Face state: $int1, unlockPossible: $bool1"
+ }
+ )
}
fun logUnexpectedFpCancellationSignalState(
fingerprintRunningState: Int,
unlockPossible: Boolean
) {
- logBuffer.log(TAG, ERROR, {
- int1 = fingerprintRunningState
- bool1 = unlockPossible
- }, {
- "Cancellation signal is not null, high chance of bug in " +
- "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ ERROR,
+ {
+ int1 = fingerprintRunningState
+ bool1 = unlockPossible
+ },
+ {
+ "Cancellation signal is not null, high chance of bug in " +
+ "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
+ }
+ )
}
fun logUnregisterCallback(callback: KeyguardUpdateMonitorCallback?) {
- logBuffer.log(TAG, VERBOSE,
- { str1 = "$callback" },
- { "*** unregister callback for $str1" })
+ logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** unregister callback for $str1" })
}
fun logUserRequestedUnlock(
@@ -376,75 +474,149 @@
reason: String?,
dismissKeyguard: Boolean
) {
- logBuffer.log("ActiveUnlock", DEBUG, {
- str1 = requestOrigin?.name
- str2 = reason
- bool1 = dismissKeyguard
- }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
+ logBuffer.log(
+ "ActiveUnlock",
+ DEBUG,
+ {
+ str1 = requestOrigin?.name
+ str2 = reason
+ bool1 = dismissKeyguard
+ },
+ { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" }
+ )
}
fun logTrustGrantedWithFlags(
- flags: Int,
- newlyUnlocked: Boolean,
- userId: Int,
- message: String?
+ flags: Int,
+ newlyUnlocked: Boolean,
+ userId: Int,
+ message: String?
) {
- logBuffer.log(TAG, DEBUG, {
- int1 = flags
- bool1 = newlyUnlocked
- int2 = userId
- str1 = message
- }, { "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
- "flags=${TrustGrantFlags(int1)} message=$str1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = flags
+ bool1 = newlyUnlocked
+ int2 = userId
+ str1 = message
+ },
+ {
+ "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
+ "flags=${TrustGrantFlags(int1)} message=$str1"
+ }
+ )
}
- fun logTrustChanged(
- wasTrusted: Boolean,
- isNowTrusted: Boolean,
- userId: Int
- ) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = wasTrusted
- bool2 = isNowTrusted
- int1 = userId
- }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+ fun logTrustChanged(wasTrusted: Boolean, isNowTrusted: Boolean, userId: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = wasTrusted
+ bool2 = isNowTrusted
+ int1 = userId
+ },
+ { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" }
+ )
}
fun logKeyguardStateUpdate(
- secure: Boolean,
- canDismissLockScreen: Boolean,
- trusted: Boolean,
- trustManaged: Boolean
-
+ secure: Boolean,
+ canDismissLockScreen: Boolean,
+ trusted: Boolean,
+ trustManaged: Boolean
) {
- logBuffer.log("KeyguardState", DEBUG, {
- bool1 = secure
- bool2 = canDismissLockScreen
- bool3 = trusted
- bool4 = trustManaged
- }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
- " trusted=$bool3 trustManaged=$bool4" })
+ logBuffer.log(
+ "KeyguardState",
+ DEBUG,
+ {
+ bool1 = secure
+ bool2 = canDismissLockScreen
+ bool3 = trusted
+ bool4 = trustManaged
+ },
+ {
+ "#update secure=$bool1 canDismissKeyguard=$bool2" +
+ " trusted=$bool3 trustManaged=$bool4"
+ }
+ )
}
fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) {
- logBuffer.log(TAG, VERBOSE, {
- str1 = PowerManager.wakeReasonToString(pmWakeReason)
- }, { "Skip updating face listening state on wakeup from $str1"})
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ { str1 = PowerManager.wakeReasonToString(pmWakeReason) },
+ { "Skip updating face listening state on wakeup from $str1" }
+ )
}
fun logTaskStackChangedForAssistant(assistantVisible: Boolean) {
- logBuffer.log(TAG, VERBOSE, {
- bool1 = assistantVisible
- }, {
- "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ { bool1 = assistantVisible },
+ { "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" }
+ )
}
fun logAssistantVisible(assistantVisible: Boolean) {
- logBuffer.log(TAG, VERBOSE, {
- bool1 = assistantVisible
- }, {
- "Updating mAssistantVisible to new value: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ { bool1 = assistantVisible },
+ { "Updating mAssistantVisible to new value: $bool1" }
+ )
+ }
+
+ fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = oldValue
+ bool2 = newValue
+ },
+ { "Face enrolled state changed: old: $bool1, new: $bool2" }
+ )
+ }
+
+ fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = oldValue
+ bool2 = newValue
+ },
+ { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" }
+ )
+ }
+
+ fun logTrustUsuallyManagedUpdated(
+ userId: Int,
+ oldValue: Boolean,
+ newValue: Boolean,
+ context: String
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = oldValue
+ bool2 = newValue
+ str1 = context
+ },
+ {
+ "trustUsuallyManaged changed for " +
+ "userId: $int1 " +
+ "old: $bool1, " +
+ "new: $bool2 " +
+ "context: $str1"
+ }
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index fa4caaf..4a900aa 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -588,8 +588,7 @@
@JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag(2201, "udfps_ellipse_detection")
// 2300 - stylus
- @JvmField
- val TRACK_STYLUS_EVER_USED = unreleasedFlag(2300, "track_stylus_ever_used", teamfood = true)
+ @JvmField val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
@JvmField
val ENABLE_STYLUS_CHARGING_UI =
unreleasedFlag(2301, "enable_stylus_charging_ui", teamfood = true)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 12d6b7c..2af0269 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -36,6 +36,7 @@
import androidx.core.graphics.drawable.IconCompat;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.qrcode.QrCodeGenerator;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastSender;
@@ -49,7 +50,7 @@
*/
@SysUISingleton
public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
- private static final String TAG = "BroadcastDialog";
+ private static final String TAG = "MediaOutputBroadcastDialog";
private ViewStub mBroadcastInfoArea;
private ImageView mBroadcastQrCodeView;
@@ -217,7 +218,8 @@
refreshUi();
}
- private void refreshUi() {
+ @VisibleForTesting
+ void refreshUi() {
setQrCodeView();
mCurrentBroadcastName = getBroadcastMetadataInfo(METADATA_BROADCAST_NAME);
@@ -256,7 +258,8 @@
mIsPasswordHide = !mIsPasswordHide;
}
- private void launchBroadcastUpdatedDialog(boolean isBroadcastCode, String editString) {
+ @VisibleForTesting
+ void launchBroadcastUpdatedDialog(boolean isBroadcastCode, String editString) {
final View layout = LayoutInflater.from(mContext).inflate(
R.layout.media_output_broadcast_update_dialog, null);
final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
@@ -286,7 +289,8 @@
return mMediaOutputController.getBroadcastMetadata();
}
- private void updateBroadcastInfo(boolean isBroadcastCode, String updatedString) {
+ @VisibleForTesting
+ void updateBroadcastInfo(boolean isBroadcastCode, String updatedString) {
Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
if (positiveBtn != null) {
positiveBtn.setEnabled(false);
@@ -377,16 +381,35 @@
}
private void handleUpdateFailedUi() {
- final Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
- mBroadcastErrorMessage.setVisibility(View.VISIBLE);
+ if (mAlertDialog == null) {
+ Log.d(TAG, "handleUpdateFailedUi: mAlertDialog is null");
+ return;
+ }
+ int errorMessageStringId = -1;
+ boolean enablePositiveBtn = false;
if (mRetryCount < MAX_BROADCAST_INFO_UPDATE) {
- if (positiveBtn != null) {
- positiveBtn.setEnabled(true);
- }
- mBroadcastErrorMessage.setText(R.string.media_output_broadcast_update_error);
+ enablePositiveBtn = true;
+ errorMessageStringId = R.string.media_output_broadcast_update_error;
} else {
mRetryCount = 0;
- mBroadcastErrorMessage.setText(R.string.media_output_broadcast_last_update_error);
+ errorMessageStringId = R.string.media_output_broadcast_last_update_error;
}
+
+ // update UI
+ final Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ if (positiveBtn != null && enablePositiveBtn) {
+ positiveBtn.setEnabled(true);
+ }
+ if (mBroadcastErrorMessage != null) {
+ mBroadcastErrorMessage.setVisibility(View.VISIBLE);
+ if (errorMessageStringId > 0) {
+ mBroadcastErrorMessage.setText(errorMessageStringId);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ int getRetryCount() {
+ return mRetryCount;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
index f712629..2b6327f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
@@ -16,7 +16,7 @@
package com.android.systemui.shade;
-import static android.os.Trace.TRACE_TAG_ALWAYS;
+import static android.os.Trace.TRACE_TAG_APP;
import static android.view.WindowInsets.Type.systemBars;
import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG;
@@ -328,7 +328,7 @@
@Override
public void requestLayout() {
- Trace.instant(TRACE_TAG_ALWAYS, "NotificationShadeWindowView#requestLayout");
+ Trace.instant(TRACE_TAG_APP, "NotificationShadeWindowView#requestLayout");
super.requestLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 32b8e09..c9f31ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -166,6 +166,11 @@
private Queue<NotifEvent> mEventQueue = new ArrayDeque<>();
+ private final Runnable mRebuildListRunnable = () -> {
+ if (mBuildListener != null) {
+ mBuildListener.onBuildList(mReadOnlyNotificationSet, "asynchronousUpdate");
+ }
+ };
private boolean mAttached = false;
private boolean mAmDispatchingToOtherCode;
@@ -462,7 +467,7 @@
int modificationType) {
Assert.isMainThread();
mEventQueue.add(new ChannelChangedEvent(pkgName, user, channel, modificationType));
- dispatchEventsAndRebuildList("onNotificationChannelModified");
+ dispatchEventsAndAsynchronouslyRebuildList();
}
private void onNotificationsInitialized() {
@@ -621,15 +626,39 @@
private void dispatchEventsAndRebuildList(String reason) {
Trace.beginSection("NotifCollection.dispatchEventsAndRebuildList");
+ if (mMainHandler.hasCallbacks(mRebuildListRunnable)) {
+ mMainHandler.removeCallbacks(mRebuildListRunnable);
+ }
+
+ dispatchEvents();
+
+ if (mBuildListener != null) {
+ mBuildListener.onBuildList(mReadOnlyNotificationSet, reason);
+ }
+ Trace.endSection();
+ }
+
+ private void dispatchEventsAndAsynchronouslyRebuildList() {
+ Trace.beginSection("NotifCollection.dispatchEventsAndAsynchronouslyRebuildList");
+
+ dispatchEvents();
+
+ if (!mMainHandler.hasCallbacks(mRebuildListRunnable)) {
+ mMainHandler.postDelayed(mRebuildListRunnable, 1000L);
+ }
+
+ Trace.endSection();
+ }
+
+ private void dispatchEvents() {
+ Trace.beginSection("NotifCollection.dispatchEvents");
+
mAmDispatchingToOtherCode = true;
while (!mEventQueue.isEmpty()) {
mEventQueue.remove().dispatchTo(mNotifCollectionListeners);
}
mAmDispatchingToOtherCode = false;
- if (mBuildListener != null) {
- mBuildListener.onBuildList(mReadOnlyNotificationSet, reason);
- }
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1fb7eb5..d2087ba6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.stack;
-import static android.os.Trace.TRACE_TAG_ALWAYS;
+import static android.os.Trace.TRACE_TAG_APP;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL;
@@ -1121,7 +1121,7 @@
@Override
public void requestLayout() {
- Trace.instant(TRACE_TAG_ALWAYS, "NotificationStackScrollLayout#requestLayout");
+ Trace.instant(TRACE_TAG_APP, "NotificationStackScrollLayout#requestLayout");
super.requestLayout();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
new file mode 100644
index 0000000..87f74b5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.KeyguardManager;
+import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.os.PowerExemptionManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class MediaOutputBroadcastDialogTest extends SysuiTestCase {
+
+ private static final String TEST_PACKAGE = "test_package";
+ private static final String BROADCAST_NAME_TEST = "Broadcast_name_test";
+ private static final String BROADCAST_CODE_TEST = "112233";
+ private static final String BROADCAST_CODE_UPDATE_TEST = "11223344";
+
+ // Mock
+ private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
+ private MediaController mMediaController = mock(MediaController.class);
+ private PlaybackState mPlaybackState = mock(PlaybackState.class);
+ private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
+ private final LocalBluetoothProfileManager mLocalBluetoothProfileManager = mock(
+ LocalBluetoothProfileManager.class);
+ private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock(
+ LocalBluetoothLeBroadcast.class);
+ private final ActivityStarter mStarter = mock(ActivityStarter.class);
+ private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
+ private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
+ private final MediaDevice mMediaDevice = mock(MediaDevice.class);
+ private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
+ private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
+ NearbyMediaDevicesManager.class);
+ private final AudioManager mAudioManager = mock(AudioManager.class);
+ private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
+ private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
+ private final LocalBluetoothLeBroadcastMetadata mLocalBluetoothLeBroadcastMetadata =
+ mock(LocalBluetoothLeBroadcastMetadata.class);
+ private FeatureFlags mFlags = mock(FeatureFlags.class);
+
+ private List<MediaController> mMediaControllers = new ArrayList<>();
+ private MediaOutputBroadcastDialog mMediaOutputBroadcastDialog;
+ private MediaOutputController mMediaOutputController;
+ private final List<String> mFeatures = new ArrayList<>();
+
+ @Before
+ public void setUp() {
+ when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile())
+ .thenReturn(mLocalBluetoothLeBroadcast);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+ when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_NONE);
+ when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE);
+ mMediaControllers.add(mMediaController);
+ when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
+ when(mLocalBluetoothLeBroadcast.getLocalBluetoothLeBroadcastMetaData()).thenReturn(
+ mLocalBluetoothLeBroadcastMetadata);
+ when(mLocalBluetoothLeBroadcastMetadata.convertToQrCodeString())
+ .thenReturn("metadata_test_convert");
+ when(mLocalBluetoothLeBroadcast.getProgramInfo()).thenReturn(BROADCAST_NAME_TEST);
+ when(mLocalBluetoothLeBroadcast.getBroadcastCode())
+ .thenReturn(BROADCAST_CODE_TEST.getBytes(StandardCharsets.UTF_8));
+
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager, mFlags);
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(false);
+
+ mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
+ mMediaOutputBroadcastDialog = new MediaOutputBroadcastDialog(mContext, false,
+ mBroadcastSender, mMediaOutputController);
+ mMediaOutputBroadcastDialog.show();
+
+ when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
+ when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
+ }
+
+ @After
+ public void tearDown() {
+ mMediaOutputBroadcastDialog.dismissDialog();
+ }
+
+ @Test
+ public void refreshUi_checkBroadcastQrCodeView() {
+ mMediaOutputBroadcastDialog.refreshUi();
+ final ImageView broadcastQrCodeView = mMediaOutputBroadcastDialog.mDialogView
+ .requireViewById(R.id.qrcode_view);
+
+ assertThat(broadcastQrCodeView.getDrawable()).isNotNull();
+ }
+
+ @Test
+ public void refreshUi_checkBroadcastName() {
+ mMediaOutputBroadcastDialog.refreshUi();
+ final TextView broadcastName = mMediaOutputBroadcastDialog.mDialogView
+ .requireViewById(R.id.broadcast_name_summary);
+
+ assertThat(broadcastName.getText().toString()).isEqualTo(BROADCAST_NAME_TEST);
+ }
+
+ @Test
+ public void refreshUi_checkBroadcastCode() {
+ mMediaOutputBroadcastDialog.refreshUi();
+ final TextView broadcastCode = mMediaOutputBroadcastDialog.mDialogView
+ .requireViewById(R.id.broadcast_code_summary);
+
+ assertThat(broadcastCode.getText().toString()).isEqualTo(BROADCAST_CODE_TEST);
+ }
+
+ @Test
+ public void updateBroadcastInfo_stopBroadcastFailed_handleFailedUI() {
+ mMediaOutputBroadcastDialog.launchBroadcastUpdatedDialog(true, BROADCAST_CODE_UPDATE_TEST);
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile())
+ .thenReturn(null);
+
+ mMediaOutputBroadcastDialog.updateBroadcastInfo(true, BROADCAST_CODE_UPDATE_TEST);
+ assertThat(mMediaOutputBroadcastDialog.getRetryCount()).isEqualTo(1);
+
+ mMediaOutputBroadcastDialog.updateBroadcastInfo(true, BROADCAST_CODE_UPDATE_TEST);
+ assertThat(mMediaOutputBroadcastDialog.getRetryCount()).isEqualTo(2);
+
+ // It will be the MAX Retry Count = 3
+ mMediaOutputBroadcastDialog.updateBroadcastInfo(true, BROADCAST_CODE_UPDATE_TEST);
+ assertThat(mMediaOutputBroadcastDialog.getRetryCount()).isEqualTo(0);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 005c80a..540bda6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -106,6 +106,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
import java.util.Arrays;
import java.util.Collection;
@@ -378,6 +379,90 @@
}
@Test
+ public void testScheduleBuildNotificationListWhenChannelChanged() {
+ // GIVEN
+ final NotificationEntryBuilder neb = buildNotif(TEST_PACKAGE, 48);
+ final NotificationChannel channel = new NotificationChannel(
+ "channelId",
+ "channelName",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ neb.setChannel(channel);
+
+ final NotifEvent notif = mNoMan.postNotif(neb);
+ final NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ when(mMainHandler.hasCallbacks(any())).thenReturn(false);
+
+ clearInvocations(mBuildListener);
+
+ // WHEN
+ mNotifHandler.onNotificationChannelModified(TEST_PACKAGE,
+ entry.getSbn().getUser(), channel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ // THEN
+ verify(mMainHandler).postDelayed(any(), eq(1000L));
+ }
+
+ @Test
+ public void testCancelScheduledBuildNotificationListEventWhenNotifUpdatedSynchronously() {
+ // GIVEN
+ final NotificationEntry entry1 = buildNotif(TEST_PACKAGE, 1)
+ .setGroup(mContext, "group_1")
+ .build();
+ final NotificationEntry entry2 = buildNotif(TEST_PACKAGE, 2)
+ .setGroup(mContext, "group_1")
+ .setContentTitle(mContext, "New version")
+ .build();
+ final NotificationEntry entry3 = buildNotif(TEST_PACKAGE, 3)
+ .setGroup(mContext, "group_1")
+ .build();
+
+ final List<CoalescedEvent> entriesToBePosted = Arrays.asList(
+ new CoalescedEvent(entry1.getKey(), 0, entry1.getSbn(), entry1.getRanking(), null),
+ new CoalescedEvent(entry2.getKey(), 1, entry2.getSbn(), entry2.getRanking(), null),
+ new CoalescedEvent(entry3.getKey(), 2, entry3.getSbn(), entry3.getRanking(), null)
+ );
+
+ when(mMainHandler.hasCallbacks(any())).thenReturn(true);
+
+ // WHEN
+ mNotifHandler.onNotificationBatchPosted(entriesToBePosted);
+
+ // THEN
+ verify(mMainHandler).removeCallbacks(any());
+ }
+
+ @Test
+ public void testBuildNotificationListWhenChannelChanged() {
+ // GIVEN
+ final NotificationEntryBuilder neb = buildNotif(TEST_PACKAGE, 48);
+ final NotificationChannel channel = new NotificationChannel(
+ "channelId",
+ "channelName",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ neb.setChannel(channel);
+
+ final NotifEvent notif = mNoMan.postNotif(neb);
+ final NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ when(mMainHandler.hasCallbacks(any())).thenReturn(false);
+ when(mMainHandler.postDelayed(any(), eq(1000L))).thenAnswer((Answer) invocation -> {
+ final Runnable runnable = invocation.getArgument(0);
+ runnable.run();
+ return null;
+ });
+
+ clearInvocations(mBuildListener);
+
+ // WHEN
+ mNotifHandler.onNotificationChannelModified(TEST_PACKAGE,
+ entry.getSbn().getUser(), channel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ // THEN
+ verifyBuiltList(List.of(entry));
+ }
+
+ @Test
public void testRankingsAreUpdatedForOtherNotifs() {
// GIVEN a collection with one notif
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 328b971..cde820a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4577,6 +4577,17 @@
return false;
}
+ /**
+ * Called when always on magnification feature flag flips to check if the feature should be
+ * enabled for current user state.
+ */
+ public void updateAlwaysOnMagnification() {
+ synchronized (mLock) {
+ readAlwaysOnMagnificationLocked(getCurrentUserState());
+ }
+ }
+
+ @GuardedBy("mLock")
boolean readAlwaysOnMagnificationLocked(AccessibilityUserState userState) {
final boolean isSettingsAlwaysOnEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java b/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java
index ed45e7b..16d2e6b 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java
@@ -16,10 +16,13 @@
package com.android.server.accessibility.magnification;
+import android.annotation.NonNull;
import android.provider.DeviceConfig;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.concurrent.Executor;
+
/**
* Encapsulates the feature flags for always on magnification. {@see DeviceConfig}
*
@@ -50,4 +53,39 @@
Boolean.toString(isEnabled),
/* makeDefault= */ false);
}
+
+ /**
+ * Adds a listener for when the feature flag changes.
+ *
+ * <p>{@see DeviceConfig#addOnPropertiesChangedListener(
+ * String, Executor, DeviceConfig.OnPropertiesChangedListener)}
+ */
+ @NonNull
+ public static DeviceConfig.OnPropertiesChangedListener addOnChangedListener(
+ @NonNull Executor executor, @NonNull Runnable listener) {
+ DeviceConfig.OnPropertiesChangedListener onChangedListener =
+ properties -> {
+ if (properties.getKeyset().contains(
+ FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION)) {
+ listener.run();
+ }
+ };
+ DeviceConfig.addOnPropertiesChangedListener(
+ NAMESPACE,
+ executor,
+ onChangedListener);
+
+ return onChangedListener;
+ }
+
+ /**
+ * Remove a listener for when the feature flag changes.
+ *
+ * <p>{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor,
+ * DeviceConfig.OnPropertiesChangedListener)}
+ */
+ public static void removeOnChangedListener(
+ @NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) {
+ DeviceConfig.removeOnPropertiesChangedListener(onChangedListener);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index a6e6bd7..4753a54 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -48,6 +48,7 @@
import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ConcurrentUtils;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.wm.WindowManagerInternal;
@@ -149,6 +150,9 @@
.getAccessibilityController().setUiChangesForAccessibilityCallbacks(this);
mSupportWindowMagnification = context.getPackageManager().hasSystemFeature(
FEATURE_WINDOW_MAGNIFICATION);
+
+ AlwaysOnMagnificationFeatureFlag.addOnChangedListener(
+ ConcurrentUtils.DIRECT_EXECUTOR, mAms::updateAlwaysOnMagnification);
}
@VisibleForTesting
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index df5e37c..21b51b1 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -242,7 +242,7 @@
private void closeInputDeviceDescriptorLocked(IBinder token,
InputDeviceDescriptor inputDeviceDescriptor) {
token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0);
- mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());
+ mNativeWrapper.closeUinput(inputDeviceDescriptor.getNativePointer());
String phys = inputDeviceDescriptor.getPhys();
InputManager.getInstance().removeUniqueIdAssociation(phys);
// Type associations are added in the case of navigation touchpads. Those should be removed
@@ -366,7 +366,7 @@
throw new IllegalArgumentException(
"Could not send key event to input device for given token");
}
- return mNativeWrapper.writeDpadKeyEvent(inputDeviceDescriptor.getFileDescriptor(),
+ return mNativeWrapper.writeDpadKeyEvent(inputDeviceDescriptor.getNativePointer(),
event.getKeyCode(), event.getAction());
}
}
@@ -379,7 +379,7 @@
throw new IllegalArgumentException(
"Could not send key event to input device for given token");
}
- return mNativeWrapper.writeKeyEvent(inputDeviceDescriptor.getFileDescriptor(),
+ return mNativeWrapper.writeKeyEvent(inputDeviceDescriptor.getNativePointer(),
event.getKeyCode(), event.getAction());
}
}
@@ -397,7 +397,7 @@
throw new IllegalStateException(
"Display id associated with this mouse is not currently targetable");
}
- return mNativeWrapper.writeButtonEvent(inputDeviceDescriptor.getFileDescriptor(),
+ return mNativeWrapper.writeButtonEvent(inputDeviceDescriptor.getNativePointer(),
event.getButtonCode(), event.getAction());
}
}
@@ -410,7 +410,7 @@
throw new IllegalArgumentException(
"Could not send touch event to input device for given token");
}
- return mNativeWrapper.writeTouchEvent(inputDeviceDescriptor.getFileDescriptor(),
+ return mNativeWrapper.writeTouchEvent(inputDeviceDescriptor.getNativePointer(),
event.getPointerId(), event.getToolType(), event.getAction(), event.getX(),
event.getY(), event.getPressure(), event.getMajorAxisSize());
}
@@ -429,7 +429,7 @@
throw new IllegalStateException(
"Display id associated with this mouse is not currently targetable");
}
- return mNativeWrapper.writeRelativeEvent(inputDeviceDescriptor.getFileDescriptor(),
+ return mNativeWrapper.writeRelativeEvent(inputDeviceDescriptor.getNativePointer(),
event.getRelativeX(), event.getRelativeY());
}
}
@@ -447,7 +447,7 @@
throw new IllegalStateException(
"Display id associated with this mouse is not currently targetable");
}
- return mNativeWrapper.writeScrollEvent(inputDeviceDescriptor.getFileDescriptor(),
+ return mNativeWrapper.writeScrollEvent(inputDeviceDescriptor.getNativePointer(),
event.getXAxisMovement(), event.getYAxisMovement());
}
}
@@ -474,7 +474,7 @@
synchronized (mLock) {
fout.println(" Active descriptors: ");
for (InputDeviceDescriptor inputDeviceDescriptor : mInputDeviceDescriptors.values()) {
- fout.println(" fd: " + inputDeviceDescriptor.getFileDescriptor());
+ fout.println(" ptr: " + inputDeviceDescriptor.getNativePointer());
fout.println(" displayId: " + inputDeviceDescriptor.getDisplayId());
fout.println(" creationOrder: "
+ inputDeviceDescriptor.getCreationOrderNumber());
@@ -487,10 +487,10 @@
}
@VisibleForTesting
- void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId, String phys,
+ void addDeviceForTesting(IBinder deviceToken, long ptr, int type, int displayId, String phys,
String deviceName, int inputDeviceId) {
synchronized (mLock) {
- mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, () -> {
+ mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(ptr, () -> {
}, type, displayId, phys, deviceName, inputDeviceId));
}
}
@@ -504,75 +504,76 @@
return inputDeviceDescriptors;
}
- private static native int nativeOpenUinputDpad(String deviceName, int vendorId, int productId,
+ private static native long nativeOpenUinputDpad(String deviceName, int vendorId, int productId,
String phys);
- private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId,
+ private static native long nativeOpenUinputKeyboard(String deviceName, int vendorId,
int productId, String phys);
- private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
+ private static native long nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
String phys);
- private static native int nativeOpenUinputTouchscreen(String deviceName, int vendorId,
+ private static native long nativeOpenUinputTouchscreen(String deviceName, int vendorId,
int productId, String phys, int height, int width);
- private static native boolean nativeCloseUinput(int fd);
- private static native boolean nativeWriteDpadKeyEvent(int fd, int androidKeyCode, int action);
- private static native boolean nativeWriteKeyEvent(int fd, int androidKeyCode, int action);
- private static native boolean nativeWriteButtonEvent(int fd, int buttonCode, int action);
- private static native boolean nativeWriteTouchEvent(int fd, int pointerId, int toolType,
+ private static native void nativeCloseUinput(long ptr);
+ private static native boolean nativeWriteDpadKeyEvent(long ptr, int androidKeyCode, int action);
+ private static native boolean nativeWriteKeyEvent(long ptr, int androidKeyCode, int action);
+ private static native boolean nativeWriteButtonEvent(long ptr, int buttonCode, int action);
+ private static native boolean nativeWriteTouchEvent(long ptr, int pointerId, int toolType,
int action, float locationX, float locationY, float pressure, float majorAxisSize);
- private static native boolean nativeWriteRelativeEvent(int fd, float relativeX,
+ private static native boolean nativeWriteRelativeEvent(long ptr, float relativeX,
float relativeY);
- private static native boolean nativeWriteScrollEvent(int fd, float xAxisMovement,
+ private static native boolean nativeWriteScrollEvent(long ptr, float xAxisMovement,
float yAxisMovement);
/** Wrapper around the static native methods for tests. */
@VisibleForTesting
protected static class NativeWrapper {
- public int openUinputDpad(String deviceName, int vendorId, int productId, String phys) {
+ public long openUinputDpad(String deviceName, int vendorId, int productId, String phys) {
return nativeOpenUinputDpad(deviceName, vendorId, productId, phys);
}
- public int openUinputKeyboard(String deviceName, int vendorId, int productId, String phys) {
+ public long openUinputKeyboard(String deviceName, int vendorId, int productId,
+ String phys) {
return nativeOpenUinputKeyboard(deviceName, vendorId, productId, phys);
}
- public int openUinputMouse(String deviceName, int vendorId, int productId, String phys) {
+ public long openUinputMouse(String deviceName, int vendorId, int productId, String phys) {
return nativeOpenUinputMouse(deviceName, vendorId, productId, phys);
}
- public int openUinputTouchscreen(String deviceName, int vendorId,
+ public long openUinputTouchscreen(String deviceName, int vendorId,
int productId, String phys, int height, int width) {
return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, phys, height,
width);
}
- public boolean closeUinput(int fd) {
- return nativeCloseUinput(fd);
+ public void closeUinput(long ptr) {
+ nativeCloseUinput(ptr);
}
- public boolean writeDpadKeyEvent(int fd, int androidKeyCode, int action) {
- return nativeWriteDpadKeyEvent(fd, androidKeyCode, action);
+ public boolean writeDpadKeyEvent(long ptr, int androidKeyCode, int action) {
+ return nativeWriteDpadKeyEvent(ptr, androidKeyCode, action);
}
- public boolean writeKeyEvent(int fd, int androidKeyCode, int action) {
- return nativeWriteKeyEvent(fd, androidKeyCode, action);
+ public boolean writeKeyEvent(long ptr, int androidKeyCode, int action) {
+ return nativeWriteKeyEvent(ptr, androidKeyCode, action);
}
- public boolean writeButtonEvent(int fd, int buttonCode, int action) {
- return nativeWriteButtonEvent(fd, buttonCode, action);
+ public boolean writeButtonEvent(long ptr, int buttonCode, int action) {
+ return nativeWriteButtonEvent(ptr, buttonCode, action);
}
- public boolean writeTouchEvent(int fd, int pointerId, int toolType, int action,
+ public boolean writeTouchEvent(long ptr, int pointerId, int toolType, int action,
float locationX, float locationY, float pressure, float majorAxisSize) {
- return nativeWriteTouchEvent(fd, pointerId, toolType,
+ return nativeWriteTouchEvent(ptr, pointerId, toolType,
action, locationX, locationY,
pressure, majorAxisSize);
}
- public boolean writeRelativeEvent(int fd, float relativeX, float relativeY) {
- return nativeWriteRelativeEvent(fd, relativeX, relativeY);
+ public boolean writeRelativeEvent(long ptr, float relativeX, float relativeY) {
+ return nativeWriteRelativeEvent(ptr, relativeX, relativeY);
}
- public boolean writeScrollEvent(int fd, float xAxisMovement, float yAxisMovement) {
- return nativeWriteScrollEvent(fd, xAxisMovement,
+ public boolean writeScrollEvent(long ptr, float xAxisMovement, float yAxisMovement) {
+ return nativeWriteScrollEvent(ptr, xAxisMovement,
yAxisMovement);
}
}
@@ -597,7 +598,8 @@
private static final AtomicLong sNextCreationOrderNumber = new AtomicLong(1);
- private final int mFd;
+ // Pointer to the native input device object.
+ private final long mPtr;
private final IBinder.DeathRecipient mDeathRecipient;
private final @Type int mType;
private final int mDisplayId;
@@ -611,9 +613,9 @@
// Monotonically increasing number; devices with lower numbers were created earlier.
private final long mCreationOrderNumber;
- InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type,
+ InputDeviceDescriptor(long ptr, IBinder.DeathRecipient deathRecipient, @Type int type,
int displayId, String phys, String name, int inputDeviceId) {
- mFd = fd;
+ mPtr = ptr;
mDeathRecipient = deathRecipient;
mType = type;
mDisplayId = displayId;
@@ -623,8 +625,8 @@
mCreationOrderNumber = sNextCreationOrderNumber.getAndIncrement();
}
- public int getFileDescriptor() {
- return mFd;
+ public long getNativePointer() {
+ return mPtr;
}
public int getType() {
@@ -767,7 +769,7 @@
*/
private void createDeviceInternal(@InputDeviceDescriptor.Type int type, String deviceName,
int vendorId, int productId, IBinder deviceToken, int displayId, String phys,
- Supplier<Integer> deviceOpener)
+ Supplier<Long> deviceOpener)
throws DeviceCreationException {
if (!mThreadVerifier.isValidThread()) {
throw new IllegalStateException(
@@ -776,19 +778,22 @@
}
validateDeviceName(deviceName);
- final int fd;
+ final long ptr;
final BinderDeathRecipient binderDeathRecipient;
final int inputDeviceId;
setUniqueIdAssociation(displayId, phys);
try (WaitForDevice waiter = new WaitForDevice(deviceName, vendorId, productId)) {
- fd = deviceOpener.get();
- if (fd < 0) {
+ ptr = deviceOpener.get();
+ // See INVALID_PTR in libs/input/VirtualInputDevice.cpp.
+ if (ptr == 0) {
throw new DeviceCreationException(
- "A native error occurred when creating touchscreen: " + -fd);
+ "A native error occurred when creating virtual input device: "
+ + deviceName);
}
- // The fd is valid from here, so ensure that all failures close the fd after this point.
+ // The pointer to the native input device is valid from here, so ensure that all
+ // failures close the device after this point.
try {
inputDeviceId = waiter.waitForDeviceCreation();
@@ -800,7 +805,7 @@
"Client died before virtual device could be created.", e);
}
} catch (DeviceCreationException e) {
- mNativeWrapper.closeUinput(fd);
+ mNativeWrapper.closeUinput(ptr);
throw e;
}
} catch (DeviceCreationException e) {
@@ -810,7 +815,7 @@
synchronized (mLock) {
mInputDeviceDescriptors.put(deviceToken,
- new InputDeviceDescriptor(fd, binderDeathRecipient, type, displayId, phys,
+ new InputDeviceDescriptor(ptr, binderDeathRecipient, type, displayId, phys,
deviceName, inputDeviceId));
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 44f475f..9e95e5f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -129,6 +129,7 @@
static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
"kill_bg_restricted_cached_idle_settle_time";
+ static final String KEY_MAX_PREVIOUS_TIME = "max_previous_time";
/**
* Note this key is on {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS}.
* @see #mEnableComponentAlias
@@ -145,6 +146,9 @@
*/
static final String KEY_NETWORK_ACCESS_TIMEOUT_MS = "network_access_timeout_ms";
+ static final String KEY_USE_TIERED_CACHED_ADJ = "use_tiered_cached_adj";
+ static final String KEY_TIERED_CACHED_ADJ_DECAY_TIME = "tiered_cached_adj_decay_time";
+
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -192,6 +196,7 @@
private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
private static final long DEFAULT_PROCESS_KILL_TIMEOUT_MS = 10 * 1000;
private static final long DEFAULT_NETWORK_ACCESS_TIMEOUT_MS = 200; // 0.2 sec
+ private static final long DEFAULT_MAX_PREVIOUS_TIME = 60 * 1000; // 60s
static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
@@ -199,6 +204,9 @@
static final int DEFAULT_MAX_SERVICE_CONNECTIONS_PER_PROCESS = 3000;
+ private static final boolean DEFAULT_USE_TIERED_CACHED_ADJ = false;
+ private static final long DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME = 60 * 1000;
+
/**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
@@ -534,6 +542,9 @@
public long TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION =
DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION;
+ // How long a process can remain at previous oom_adj before dropping to cached
+ public static long MAX_PREVIOUS_TIME = DEFAULT_MAX_PREVIOUS_TIME;
+
/**
* The minimum time we allow between crashes, for us to consider this
* application to be bad and stop its services and reject broadcasts.
@@ -1006,6 +1017,12 @@
public volatile long mShortFgsAnrExtraWaitDuration =
DEFAULT_SHORT_FGS_ANR_EXTRA_WAIT_DURATION;
+ /** @see #KEY_USE_TIERED_CACHED_ADJ */
+ public boolean USE_TIERED_CACHED_ADJ = DEFAULT_USE_TIERED_CACHED_ADJ;
+
+ /** @see #KEY_TIERED_CACHED_ADJ_DECAY_TIME */
+ public long TIERED_CACHED_ADJ_DECAY_TIME = DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME;
+
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
new OnPropertiesChangedListener() {
@Override
@@ -1171,6 +1188,13 @@
case KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION:
updateEnableWaitForFinishAttachApplication();
break;
+ case KEY_MAX_PREVIOUS_TIME:
+ updateMaxPreviousTime();
+ break;
+ case KEY_USE_TIERED_CACHED_ADJ:
+ case KEY_TIERED_CACHED_ADJ_DECAY_TIME:
+ updateUseTieredCachedAdj();
+ break;
default:
break;
}
@@ -1825,6 +1849,7 @@
DEFAULT_LOW_SWAP_THRESHOLD_PERCENT);
}
+
private void updateTopToFgsGraceDuration() {
TOP_TO_FGS_GRACE_DURATION = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1832,6 +1857,13 @@
DEFAULT_TOP_TO_FGS_GRACE_DURATION);
}
+ private void updateMaxPreviousTime() {
+ MAX_PREVIOUS_TIME = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_MAX_PREVIOUS_TIME,
+ DEFAULT_MAX_PREVIOUS_TIME);
+ }
+
private void updateMinAssocLogDuration() {
MIN_ASSOC_LOG_DURATION = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MIN_ASSOC_LOG_DURATION,
@@ -1908,6 +1940,17 @@
DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION);
}
+ private void updateUseTieredCachedAdj() {
+ USE_TIERED_CACHED_ADJ = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_USE_TIERED_CACHED_ADJ,
+ DEFAULT_USE_TIERED_CACHED_ADJ);
+ TIERED_CACHED_ADJ_DECAY_TIME = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_TIERED_CACHED_ADJ_DECAY_TIME,
+ DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME);
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
@@ -2092,6 +2135,11 @@
pw.print(" "); pw.print(KEY_SHORT_FGS_ANR_EXTRA_WAIT_DURATION);
pw.print("="); pw.println(mShortFgsAnrExtraWaitDuration);
+ pw.print(" "); pw.print(KEY_USE_TIERED_CACHED_ADJ);
+ pw.print("="); pw.println(USE_TIERED_CACHED_ADJ);
+ pw.print(" "); pw.print(KEY_TIERED_CACHED_ADJ_DECAY_TIME);
+ pw.print("="); pw.println(TIERED_CACHED_ADJ_DECAY_TIME);
+
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 96d5f38..ba0f607 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8603,7 +8603,7 @@
// On Automotive / Headless System User Mode, at this point the system user has already been
// started and unlocked, and some of the tasks we do here have already been done. So skip
// those in that case. The duplicate system user start is guarded in SystemServiceManager.
- // TODO(b/242195409): this workaround shouldn't be necessary once we move the headless-user
+ // TODO(b/266158156): this workaround shouldn't be necessary once we move the headless-user
// start logic to UserManager-land.
mUserController.onSystemUserStarting();
@@ -8636,7 +8636,7 @@
// Some systems - like automotive - will explicitly unlock system user then switch
// to a secondary user.
- // TODO(b/242195409): this workaround shouldn't be necessary once we move
+ // TODO(b/266158156): this workaround shouldn't be necessary once we move
// the headless-user start logic to UserManager-land.
if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
t.traceBegin("startHomeOnAllDisplays");
@@ -8659,26 +8659,10 @@
final int callingPid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
- Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
- broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
- currentUserId);
- intent = new Intent(Intent.ACTION_USER_STARTING);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
- broadcastIntentLocked(null, null, null, intent, null,
- new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered, boolean sticky,
- int sendingUser) {}
- }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, null,
- OP_NONE, null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
- UserHandle.USER_ALL);
+ mUserController.sendUserStartedBroadcast(
+ currentUserId, callingUid, callingPid);
+ mUserController.sendUserStartingBroadcast(
+ currentUserId, callingUid, callingPid);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
} finally {
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 5c7fde7..361f8bb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1620,6 +1620,18 @@
*/
private void notifyFinishReceiver(@Nullable BroadcastProcessQueue queue,
@NonNull BroadcastRecord r, int index, @NonNull Object receiver) {
+ if (r.wasDeliveryAttempted(index)) {
+ logBroadcastDeliveryEventReported(queue, r, index, receiver);
+ }
+
+ final boolean recordFinished = (r.terminalCount == r.receivers.size());
+ if (recordFinished) {
+ notifyFinishBroadcast(r);
+ }
+ }
+
+ private void logBroadcastDeliveryEventReported(@Nullable BroadcastProcessQueue queue,
+ @NonNull BroadcastRecord r, int index, @NonNull Object receiver) {
// Report statistics for each individual receiver
final int uid = getReceiverUid(receiver);
final int senderUid = (r.callingUid == -1) ? Process.SYSTEM_UID : r.callingUid;
@@ -1647,11 +1659,6 @@
FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, uid, senderUid, actionName,
receiverType, type, dispatchDelay, receiveDelay, finishDelay, packageState);
}
-
- final boolean recordFinished = (r.terminalCount == r.receivers.size());
- if (recordFinished) {
- notifyFinishBroadcast(r);
- }
}
private void notifyFinishBroadcast(@NonNull BroadcastRecord r) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 67783be..f793c50 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -632,6 +632,18 @@
return delivery[index];
}
+ boolean wasDeliveryAttempted(int index) {
+ final int deliveryState = getDeliveryState(index);
+ switch (deliveryState) {
+ case DELIVERY_DELIVERED:
+ case DELIVERY_TIMEOUT:
+ case DELIVERY_FAILURE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
void copyEnqueueTimeFrom(@NonNull BroadcastRecord replacedBroadcast) {
originalEnqueueClockTime = enqueueClockTime;
enqueueTime = replacedBroadcast.enqueueTime;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 913f151..f4685f0 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1921,9 +1921,26 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case SET_FROZEN_PROCESS_MSG:
+ {
+ ProcessRecord proc = (ProcessRecord) msg.obj;
+ int pid = proc.getPid();
+ final String name = proc.processName;
synchronized (mAm) {
- freezeProcess((ProcessRecord) msg.obj);
+ freezeProcess(proc);
}
+ try {
+ // post-check to prevent deadlock
+ mProcLocksReader.handleBlockingFileLocks(this);
+ } catch (Exception e) {
+ Slog.e(TAG_AM, "Unable to check file locks for "
+ + name + "(" + pid + "): " + e);
+ synchronized (mAm) {
+ synchronized (mProcLock) {
+ unfreezeAppLSP(proc, OomAdjuster.OOM_ADJ_REASON_NONE);
+ }
+ }
+ }
+ }
break;
case REPORT_UNFREEZE_MSG:
int pid = msg.arg1;
@@ -2057,16 +2074,6 @@
}
});
}
-
- try {
- // post-check to prevent deadlock
- mProcLocksReader.handleBlockingFileLocks(this);
- } catch (Exception e) {
- Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e);
- synchronized (mProcLock) {
- unfreezeAppLSP(proc, OomAdjuster.OOM_ADJ_REASON_NONE);
- }
- }
}
private void reportUnfreeze(int pid, int frozenDuration, String processName,
@@ -2123,22 +2130,25 @@
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, "Blocking file lock found: " + pids);
}
- synchronized (mProcLock) {
- int pid = pids.get(0);
- ProcessRecord app = mFrozenProcesses.get(pid);
- ProcessRecord pr;
- if (app != null) {
- for (int i = 1; i < pids.size(); i++) {
- int blocked = pids.get(i);
- synchronized (mAm.mPidsSelfLocked) {
- pr = mAm.mPidsSelfLocked.get(blocked);
- }
- if (pr != null && pr.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ) {
- Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks "
- + pr.processName + " (" + blocked + ")");
- // Found at least one blocked non-cached process
- unfreezeAppLSP(app, OomAdjuster.OOM_ADJ_REASON_NONE);
- break;
+ synchronized (mAm) {
+ synchronized (mProcLock) {
+ int pid = pids.get(0);
+ ProcessRecord app = mFrozenProcesses.get(pid);
+ ProcessRecord pr;
+ if (app != null) {
+ for (int i = 1; i < pids.size(); i++) {
+ int blocked = pids.get(i);
+ synchronized (mAm.mPidsSelfLocked) {
+ pr = mAm.mPidsSelfLocked.get(blocked);
+ }
+ if (pr != null
+ && pr.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ) {
+ Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks "
+ + pr.processName + " (" + blocked + ")");
+ // Found at least one blocked non-cached process
+ unfreezeAppLSP(app, OomAdjuster.OOM_ADJ_REASON_NONE);
+ break;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 32db33d..b68d993 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1073,135 +1073,165 @@
@GuardedBy({"mService", "mProcLock"})
private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
+ if (mConstants.USE_TIERED_CACHED_ADJ) {
+ final long now = SystemClock.uptimeMillis();
+ for (int i = numLru - 1; i >= 0; i--) {
+ ProcessRecord app = lruList.get(i);
+ final ProcessStateRecord state = app.mState;
+ final ProcessCachedOptimizerRecord opt = app.mOptRecord;
+ if (!app.isKilledByAm() && app.getThread() != null && state.getCurAdj()
+ >= UNKNOWN_ADJ) {
+ final ProcessServiceRecord psr = app.mServices;
+ int targetAdj = CACHED_APP_MIN_ADJ;
- // First update the OOM adjustment for each of the
- // application processes based on their current state.
- int curCachedAdj = CACHED_APP_MIN_ADJ;
- int nextCachedAdj = curCachedAdj + (CACHED_APP_IMPORTANCE_LEVELS * 2);
- int curCachedImpAdj = 0;
- int curEmptyAdj = CACHED_APP_MIN_ADJ + CACHED_APP_IMPORTANCE_LEVELS;
- int nextEmptyAdj = curEmptyAdj + (CACHED_APP_IMPORTANCE_LEVELS * 2);
+ if (opt != null && opt.isFreezeExempt()) {
+ // BIND_WAIVE_PRIORITY and the like get oom_adj 900
+ targetAdj += 0;
+ } else if ((state.getSetAdj() >= CACHED_APP_MIN_ADJ)
+ && (state.getLastStateTime()
+ + mConstants.TIERED_CACHED_ADJ_DECAY_TIME) < now) {
+ // Older cached apps get 950
+ targetAdj += 50;
+ } else {
+ // Newer cached apps get 910
+ targetAdj += 10;
+ }
+ state.setCurRawAdj(targetAdj);
+ state.setCurAdj(psr.modifyRawOomAdj(targetAdj));
+ }
+ }
+ } else {
+ // First update the OOM adjustment for each of the
+ // application processes based on their current state.
+ int curCachedAdj = CACHED_APP_MIN_ADJ;
+ int nextCachedAdj = curCachedAdj + (CACHED_APP_IMPORTANCE_LEVELS * 2);
+ int curCachedImpAdj = 0;
+ int curEmptyAdj = CACHED_APP_MIN_ADJ + CACHED_APP_IMPORTANCE_LEVELS;
+ int nextEmptyAdj = curEmptyAdj + (CACHED_APP_IMPORTANCE_LEVELS * 2);
- final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
- final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
- - emptyProcessLimit;
- // Let's determine how many processes we have running vs.
- // how many slots we have for background processes; we may want
- // to put multiple processes in a slot of there are enough of
- // them.
- int numEmptyProcs = numLru - mNumNonCachedProcs - mNumCachedHiddenProcs;
- if (numEmptyProcs > cachedProcessLimit) {
- // If there are more empty processes than our limit on cached
- // processes, then use the cached process limit for the factor.
- // This ensures that the really old empty processes get pushed
- // down to the bottom, so if we are running low on memory we will
- // have a better chance at keeping around more cached processes
- // instead of a gazillion empty processes.
- numEmptyProcs = cachedProcessLimit;
- }
- int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)
- / mNumSlots;
- if (cachedFactor < 1) cachedFactor = 1;
+ final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
+ final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
+ - emptyProcessLimit;
+ // Let's determine how many processes we have running vs.
+ // how many slots we have for background processes; we may want
+ // to put multiple processes in a slot of there are enough of
+ // them.
+ int numEmptyProcs = numLru - mNumNonCachedProcs - mNumCachedHiddenProcs;
+ if (numEmptyProcs > cachedProcessLimit) {
+ // If there are more empty processes than our limit on cached
+ // processes, then use the cached process limit for the factor.
+ // This ensures that the really old empty processes get pushed
+ // down to the bottom, so if we are running low on memory we will
+ // have a better chance at keeping around more cached processes
+ // instead of a gazillion empty processes.
+ numEmptyProcs = cachedProcessLimit;
+ }
+ int cachedFactor = (mNumCachedHiddenProcs > 0
+ ? (mNumCachedHiddenProcs + mNumSlots - 1) : 1)
+ / mNumSlots;
+ if (cachedFactor < 1) cachedFactor = 1;
- int emptyFactor = (numEmptyProcs + mNumSlots - 1) / mNumSlots;
- if (emptyFactor < 1) emptyFactor = 1;
+ int emptyFactor = (numEmptyProcs + mNumSlots - 1) / mNumSlots;
+ if (emptyFactor < 1) emptyFactor = 1;
- int stepCached = -1;
- int stepEmpty = -1;
- int lastCachedGroup = 0;
- int lastCachedGroupImportance = 0;
- int lastCachedGroupUid = 0;
+ int stepCached = -1;
+ int stepEmpty = -1;
+ int lastCachedGroup = 0;
+ int lastCachedGroupImportance = 0;
+ int lastCachedGroupUid = 0;
- for (int i = numLru - 1; i >= 0; i--) {
- ProcessRecord app = lruList.get(i);
- final ProcessStateRecord state = app.mState;
- // If we haven't yet assigned the final cached adj
- // to the process, do that now.
- if (!app.isKilledByAm() && app.getThread() != null && state.getCurAdj()
+
+ for (int i = numLru - 1; i >= 0; i--) {
+ ProcessRecord app = lruList.get(i);
+ final ProcessStateRecord state = app.mState;
+ // If we haven't yet assigned the final cached adj
+ // to the process, do that now.
+ if (!app.isKilledByAm() && app.getThread() != null && state.getCurAdj()
>= UNKNOWN_ADJ) {
- final ProcessServiceRecord psr = app.mServices;
- switch (state.getCurProcState()) {
- case PROCESS_STATE_CACHED_ACTIVITY:
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- case ActivityManager.PROCESS_STATE_CACHED_RECENT:
- // Figure out the next cached level, taking into account groups.
- boolean inGroup = false;
- final int connectionGroup = psr.getConnectionGroup();
- if (connectionGroup != 0) {
- final int connectionImportance = psr.getConnectionImportance();
- if (lastCachedGroupUid == app.uid
+ final ProcessServiceRecord psr = app.mServices;
+ switch (state.getCurProcState()) {
+ case PROCESS_STATE_CACHED_ACTIVITY:
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ case ActivityManager.PROCESS_STATE_CACHED_RECENT:
+ // Figure out the next cached level, taking into account groups.
+ boolean inGroup = false;
+ final int connectionGroup = psr.getConnectionGroup();
+ if (connectionGroup != 0) {
+ final int connectionImportance = psr.getConnectionImportance();
+ if (lastCachedGroupUid == app.uid
&& lastCachedGroup == connectionGroup) {
- // This is in the same group as the last process, just tweak
- // adjustment by importance.
- if (connectionImportance > lastCachedGroupImportance) {
- lastCachedGroupImportance = connectionImportance;
- if (curCachedAdj < nextCachedAdj
+ // This is in the same group as the last process, just tweak
+ // adjustment by importance.
+ if (connectionImportance > lastCachedGroupImportance) {
+ lastCachedGroupImportance = connectionImportance;
+ if (curCachedAdj < nextCachedAdj
&& curCachedAdj < CACHED_APP_MAX_ADJ) {
- curCachedImpAdj++;
+ curCachedImpAdj++;
+ }
+ }
+ inGroup = true;
+ } else {
+ lastCachedGroupUid = app.uid;
+ lastCachedGroup = connectionGroup;
+ lastCachedGroupImportance = connectionImportance;
+ }
+ }
+ if (!inGroup && curCachedAdj != nextCachedAdj) {
+ stepCached++;
+ curCachedImpAdj = 0;
+ if (stepCached >= cachedFactor) {
+ stepCached = 0;
+ curCachedAdj = nextCachedAdj;
+ nextCachedAdj += CACHED_APP_IMPORTANCE_LEVELS * 2;
+ if (nextCachedAdj > CACHED_APP_MAX_ADJ) {
+ nextCachedAdj = CACHED_APP_MAX_ADJ;
}
}
- inGroup = true;
- } else {
- lastCachedGroupUid = app.uid;
- lastCachedGroup = connectionGroup;
- lastCachedGroupImportance = connectionImportance;
}
- }
- if (!inGroup && curCachedAdj != nextCachedAdj) {
- stepCached++;
- curCachedImpAdj = 0;
- if (stepCached >= cachedFactor) {
- stepCached = 0;
- curCachedAdj = nextCachedAdj;
- nextCachedAdj += CACHED_APP_IMPORTANCE_LEVELS * 2;
- if (nextCachedAdj > CACHED_APP_MAX_ADJ) {
- nextCachedAdj = CACHED_APP_MAX_ADJ;
+ // This process is a cached process holding activities...
+ // assign it the next cached value for that type, and then
+ // step that cached level.
+ state.setCurRawAdj(curCachedAdj + curCachedImpAdj);
+ state.setCurAdj(psr.modifyRawOomAdj(curCachedAdj + curCachedImpAdj));
+ if (DEBUG_LRU) {
+ Slog.d(TAG_LRU, "Assigning activity LRU #" + i
+ + " adj: " + state.getCurAdj()
+ + " (curCachedAdj=" + curCachedAdj
+ + " curCachedImpAdj=" + curCachedImpAdj + ")");
+ }
+ break;
+ default:
+ // Figure out the next cached level.
+ if (curEmptyAdj != nextEmptyAdj) {
+ stepEmpty++;
+ if (stepEmpty >= emptyFactor) {
+ stepEmpty = 0;
+ curEmptyAdj = nextEmptyAdj;
+ nextEmptyAdj += CACHED_APP_IMPORTANCE_LEVELS * 2;
+ if (nextEmptyAdj > CACHED_APP_MAX_ADJ) {
+ nextEmptyAdj = CACHED_APP_MAX_ADJ;
+ }
}
}
- }
- // This process is a cached process holding activities...
- // assign it the next cached value for that type, and then
- // step that cached level.
- state.setCurRawAdj(curCachedAdj + curCachedImpAdj);
- state.setCurAdj(psr.modifyRawOomAdj(curCachedAdj + curCachedImpAdj));
- if (DEBUG_LRU) {
- Slog.d(TAG_LRU, "Assigning activity LRU #" + i
- + " adj: " + state.getCurAdj()
- + " (curCachedAdj=" + curCachedAdj
- + " curCachedImpAdj=" + curCachedImpAdj + ")");
- }
- break;
- default:
- // Figure out the next cached level.
- if (curEmptyAdj != nextEmptyAdj) {
- stepEmpty++;
- if (stepEmpty >= emptyFactor) {
- stepEmpty = 0;
- curEmptyAdj = nextEmptyAdj;
- nextEmptyAdj += CACHED_APP_IMPORTANCE_LEVELS * 2;
- if (nextEmptyAdj > CACHED_APP_MAX_ADJ) {
- nextEmptyAdj = CACHED_APP_MAX_ADJ;
- }
+ // For everything else, assign next empty cached process
+ // level and bump that up. Note that this means that
+ // long-running services that have dropped down to the
+ // cached level will be treated as empty (since their process
+ // state is still as a service), which is what we want.
+ state.setCurRawAdj(curEmptyAdj);
+ state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj));
+ if (DEBUG_LRU) {
+ Slog.d(TAG_LRU, "Assigning empty LRU #" + i
+ + " adj: " + state.getCurAdj()
+ + " (curEmptyAdj=" + curEmptyAdj
+ + ")");
}
- }
- // For everything else, assign next empty cached process
- // level and bump that up. Note that this means that
- // long-running services that have dropped down to the
- // cached level will be treated as empty (since their process
- // state is still as a service), which is what we want.
- state.setCurRawAdj(curEmptyAdj);
- state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj));
- if (DEBUG_LRU) {
- Slog.d(TAG_LRU, "Assigning empty LRU #" + i
- + " adj: " + state.getCurAdj() + " (curEmptyAdj=" + curEmptyAdj
- + ")");
- }
- break;
+ break;
+ }
}
}
}
}
-
private long mNextNoKillDebugMessageTime;
private double mLastFreeSwapPercent = 1.00;
@@ -2018,25 +2048,37 @@
}
}
}
-
if (state.getCachedIsPreviousProcess() && state.getCachedHasActivities()) {
- if (adj > PREVIOUS_APP_ADJ) {
- // This was the previous process that showed UI to the user.
- // We want to try to keep it around more aggressively, to give
- // a good experience around switching between two apps.
- adj = PREVIOUS_APP_ADJ;
- schedGroup = SCHED_GROUP_BACKGROUND;
- state.setCached(false);
- state.setAdjType("previous");
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
- }
- }
- if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+ // This was the previous process that showed UI to the user. We want to
+ // try to keep it around more aggressively, to give a good experience
+ // around switching between two apps. However, we don't want to keep the
+ // process in this privileged state indefinitely. Eventually, allow the
+ // app to be demoted to cached.
+ if ((state.getSetProcState() == PROCESS_STATE_LAST_ACTIVITY
+ && (state.getLastStateTime() + mConstants.MAX_PREVIOUS_TIME) < now)) {
procState = PROCESS_STATE_LAST_ACTIVITY;
- state.setAdjType("previous");
+ schedGroup = SCHED_GROUP_BACKGROUND;
+ state.setAdjType("previous-expired");
+ adj = CACHED_APP_MIN_ADJ;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Expire prev adj: " + app);
+ }
+ } else {
+ if (adj > PREVIOUS_APP_ADJ) {
+ adj = PREVIOUS_APP_ADJ;
+ schedGroup = SCHED_GROUP_BACKGROUND;
+ state.setCached(false);
+ state.setAdjType("previous");
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
+ }
+ }
+ if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+ procState = PROCESS_STATE_LAST_ACTIVITY;
+ state.setAdjType("previous");
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 14ecf9f..daf227c 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -69,7 +69,8 @@
@Overridable
private static final long DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER = 244637991;
private static final String ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER =
- "enable_default_rescind_bal_privileges_from_pending_intent_sender";
+ "DefaultRescindBalPrivilegesFromPendingIntentSender__"
+ + "enable_default_rescind_bal_privileges_from_pending_intent_sender";
public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
public static final int FLAG_BROADCAST_SENDER = 1 << 1;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 0e49c66..1b37883 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -365,13 +365,13 @@
private volatile ArraySet<String> mCurWaitingUserSwitchCallbacks;
/**
- * Messages for for switching from {@link android.os.UserHandle#SYSTEM}.
+ * Messages for switching from {@link android.os.UserHandle#SYSTEM}.
*/
@GuardedBy("mLock")
private String mSwitchingFromSystemUserMessage;
/**
- * Messages for for switching to {@link android.os.UserHandle#SYSTEM}.
+ * Messages for switching to {@link android.os.UserHandle#SYSTEM}.
*/
@GuardedBy("mLock")
private String mSwitchingToSystemUserMessage;
@@ -384,6 +384,16 @@
private final LockPatternUtils mLockPatternUtils;
+ // TODO(b/266158156): remove this once we improve/refactor the way broadcasts are sent for
+ // the system user in HSUM.
+ @GuardedBy("mLock")
+ private boolean mIsBroadcastSentForSystemUserStarted;
+
+ // TODO(b/266158156): remove this once we improve/refactor the way broadcasts are sent for
+ // the system user in HSUM.
+ @GuardedBy("mLock")
+ private boolean mIsBroadcastSentForSystemUserStarting;
+
volatile boolean mBootCompleted;
/**
@@ -635,7 +645,7 @@
// user transitions to RUNNING_LOCKED. However, in "headless system user mode", the
// system user is explicitly started before the device has finished booting. In
// that case, we need to wait until onBootComplete() to send the broadcast.
- if (!(UserManager.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
+ if (!(mInjector.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
// ACTION_LOCKED_BOOT_COMPLETED
sendLockedBootCompletedBroadcast(resultTo, userId);
}
@@ -1823,15 +1833,17 @@
needStart = false;
}
- if (needStart) {
- // Send USER_STARTED broadcast
- Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mInjector.broadcastIntent(intent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
+ // In most cases, broadcast for the system user starting/started is sent by
+ // ActivityManagerService#systemReady(). However on some HSUM devices (e.g. tablets)
+ // the user switches from the system user to a secondary user while running
+ // ActivityManagerService#systemReady(), thus broadcast is not sent for the system user.
+ // Therefore we send the broadcast for the system user here as well in HSUM.
+ // TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
+ // in HSUM. Ideally it'd be best to have one single place that sends this notification.
+ final boolean isSystemUserInHeadlessMode = (userId == UserHandle.USER_SYSTEM)
+ && mInjector.isHeadlessSystemUserMode();
+ if (needStart || isSystemUserInHeadlessMode) {
+ sendUserStartedBroadcast(userId, callingUid, callingPid);
}
t.traceEnd();
@@ -1845,23 +1857,9 @@
t.traceEnd();
}
- if (needStart) {
+ if (needStart || isSystemUserInHeadlessMode) {
t.traceBegin("sendRestartBroadcast");
- Intent intent = new Intent(Intent.ACTION_USER_STARTING);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mInjector.broadcastIntent(intent,
- null, new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered,
- boolean sticky,
- int sendingUser) throws RemoteException {
- }
- }, 0, null, null,
- new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
- UserHandle.USER_ALL);
+ sendUserStartingBroadcast(userId, callingUid, callingPid);
t.traceEnd();
}
} finally {
@@ -2283,6 +2281,62 @@
EventLogTags.writeAmSwitchUser(newUserId);
}
+ // The two methods sendUserStartedBroadcast() and sendUserStartingBroadcast()
+ // could be merged for better reuse. However, the params they are calling broadcastIntent()
+ // with are different - resultCode receiver, permissions, ordered, and userId, etc. Therefore,
+ // we decided to keep two separate methods for better code readability/clarity.
+ // TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
+ // in HSUM. Ideally it'd be best to have one single place that sends this notification.
+ /** Sends {@code ACTION_USER_STARTED} broadcast. */
+ void sendUserStartedBroadcast(@UserIdInt int userId, int callingUid, int callingPid) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ synchronized (mLock) {
+ // Make sure that the broadcast is sent only once for the system user.
+ if (mIsBroadcastSentForSystemUserStarted) {
+ return;
+ }
+ mIsBroadcastSentForSystemUserStarted = true;
+ }
+ }
+ final Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ mInjector.broadcastIntent(intent, /* resolvedType= */ null, /* resultTo= */ null,
+ /* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */ null,
+ /* requiredPermissions= */ null, AppOpsManager.OP_NONE, /* bOptions= */ null,
+ /* ordered= */ false, /* sticky= */ false, MY_PID, SYSTEM_UID,
+ callingUid, callingPid, userId);
+ }
+
+ /** Sends {@code ACTION_USER_STARTING} broadcast. */
+ void sendUserStartingBroadcast(@UserIdInt int userId, int callingUid, int callingPid) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ synchronized (mLock) {
+ // Make sure that the broadcast is sent only once for the system user.
+ if (mIsBroadcastSentForSystemUserStarting) {
+ return;
+ }
+ mIsBroadcastSentForSystemUserStarting = true;
+ }
+ }
+ final Intent intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ mInjector.broadcastIntent(intent, /* resolvedType= */ null,
+ new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky,
+ int sendingUser) throws RemoteException {
+ }
+ }, /* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */ null,
+ new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, /* bOptions= */ null,
+ /* ordered= */ true, /* sticky= */ false, MY_PID, SYSTEM_UID,
+ callingUid, callingPid, UserHandle.USER_ALL);
+ }
+
void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -2568,7 +2622,7 @@
for (int i = 0; i < startedUsers.size(); i++) {
int userId = startedUsers.keyAt(i);
UserState uss = startedUsers.valueAt(i);
- if (!UserManager.isHeadlessSystemUserMode()) {
+ if (!mInjector.isHeadlessSystemUserMode()) {
finishUserBoot(uss, resultTo);
} else {
if (userId == UserHandle.USER_SYSTEM) {
@@ -2589,9 +2643,9 @@
mInjector.reportCurWakefulnessUsageEvent();
}
- // TODO(b/242195409): remove this method if initial system user boot logic is refactored?
+ // TODO(b/266158156): remove this method if initial system user boot logic is refactored?
void onSystemUserStarting() {
- if (!UserManager.isHeadlessSystemUserMode()) {
+ if (!mInjector.isHeadlessSystemUserMode()) {
// Don't need to call on HSUM because it will be called when the system user is
// restarted on background
mInjector.onUserStarting(UserHandle.USER_SYSTEM);
@@ -3059,6 +3113,10 @@
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
pw.println(" mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
pw.println(" mInitialized:" + mInitialized);
+ pw.println(" mIsBroadcastSentForSystemUserStarted:"
+ + mIsBroadcastSentForSystemUserStarted);
+ pw.println(" mIsBroadcastSentForSystemUserStarting:"
+ + mIsBroadcastSentForSystemUserStarting);
if (mSwitchingFromSystemUserMessage != null) {
pw.println(" mSwitchingFromSystemUserMessage: " + mSwitchingFromSystemUserMessage);
}
@@ -3749,6 +3807,10 @@
}, /* message= */ null);
}
+ boolean isHeadlessSystemUserMode() {
+ return UserManager.isHeadlessSystemUserMode();
+ }
+
boolean isUsersOnSecondaryDisplaysEnabled() {
return UserManager.isVisibleBackgroundUsersEnabled();
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 3304fb0..1268156 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1567,6 +1567,7 @@
case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE:
if (msg.arg1 != BluetoothProfile.HEADSET) {
synchronized (mDeviceStateLock) {
+ mBtHelper.onBtProfileDisconnected(msg.arg1);
mDeviceInventory.onBtProfileDisconnected(msg.arg1);
}
} else {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index df65dbd..2dcdc54 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -278,7 +278,11 @@
}
AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent(
AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index));
- mA2dp.setAvrcpAbsoluteVolume(index);
+ try {
+ mA2dp.setAvrcpAbsoluteVolume(index);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while changing abs volume", e);
+ }
}
/*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getA2dpCodec(
@@ -286,7 +290,12 @@
if (mA2dp == null) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
- final BluetoothCodecStatus btCodecStatus = mA2dp.getCodecStatus(device);
+ BluetoothCodecStatus btCodecStatus = null;
+ try {
+ btCodecStatus = mA2dp.getCodecStatus(device);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting status of " + device, e);
+ }
if (btCodecStatus == null) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
@@ -420,7 +429,11 @@
}
AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent(
AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex));
- mLeAudio.setVolume(volume);
+ try {
+ mLeAudio.setVolume(volume);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while setting LE volume", e);
+ }
}
/*package*/ synchronized void setHearingAidVolume(int index, int streamType,
@@ -446,7 +459,11 @@
AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent(
AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
}
- mHearingAid.setVolume(gainDB);
+ try {
+ mHearingAid.setVolume(gainDB);
+ } catch (Exception e) {
+ Log.i(TAG, "Exception while setting hearing aid volume", e);
+ }
}
/*package*/ synchronized void onBroadcastScoConnectionState(int state) {
@@ -471,7 +488,7 @@
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
- @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void resetBluetoothSco() {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -486,6 +503,35 @@
mBluetoothHeadset = null;
}
+ //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ /*package*/ synchronized void onBtProfileDisconnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ mA2dp = null;
+ break;
+ case BluetoothProfile.HEARING_AID:
+ mHearingAid = null;
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudio = null;
+ break;
+
+ case BluetoothProfile.A2DP_SINK:
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ // shouldn't be received here as profile doesn't involve BtHelper
+ Log.e(TAG, "onBtProfileDisconnected: Not a profile handled by BtHelper "
+ + BluetoothProfile.getProfileName(profile));
+ break;
+
+ default:
+ // Not a valid profile to disconnect
+ Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect "
+ + BluetoothProfile.getProfileName(profile));
+ break;
+ }
+ }
+
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
onHeadsetProfileConnected((BluetoothHeadset) proxy);
@@ -671,7 +717,6 @@
public void onServiceConnected(int profile, BluetoothProfile proxy) {
switch(profile) {
case BluetoothProfile.A2DP:
- case BluetoothProfile.A2DP_SINK:
case BluetoothProfile.HEADSET:
case BluetoothProfile.HEARING_AID:
case BluetoothProfile.LE_AUDIO:
@@ -681,6 +726,10 @@
mDeviceBroker.postBtProfileConnected(profile, proxy);
break;
+ case BluetoothProfile.A2DP_SINK:
+ // no A2DP sink functionality handled by BtHelper
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ // no broadcast functionality handled by BtHelper
default:
break;
}
@@ -689,14 +738,19 @@
switch (profile) {
case BluetoothProfile.A2DP:
- case BluetoothProfile.A2DP_SINK:
case BluetoothProfile.HEADSET:
case BluetoothProfile.HEARING_AID:
case BluetoothProfile.LE_AUDIO:
- case BluetoothProfile.LE_AUDIO_BROADCAST:
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "BT profile service: disconnecting "
+ + BluetoothProfile.getProfileName(profile) + " profile"));
mDeviceBroker.postBtProfileDisconnected(profile);
break;
+ case BluetoothProfile.A2DP_SINK:
+ // no A2DP sink functionality handled by BtHelper
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ // no broadcast functionality handled by BtHelper
default:
break;
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 850f6da..81e550e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -466,6 +466,8 @@
private boolean mIsDocked;
private boolean mIsDreaming;
+ private boolean mBootCompleted = false;
+
private final BroadcastReceiver mIdleModeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -602,6 +604,12 @@
}
}
} else if (phase == PHASE_BOOT_COMPLETED) {
+ synchronized (mSyncRoot) {
+ mBootCompleted = true;
+ for (int i = 0; i < mDisplayPowerControllers.size(); i++) {
+ mDisplayPowerControllers.valueAt(i).onBootCompleted();
+ }
+ }
mDisplayModeDirector.onBootCompleted();
mLogicalDisplayMapper.onBootCompleted();
}
@@ -2998,12 +3006,12 @@
displayPowerController = new DisplayPowerController2(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display), hbmMetadata);
+ () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted);
} else {
displayPowerController = new DisplayPowerController(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display), hbmMetadata);
+ () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted);
}
mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 82e6e30..d4877eb 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -139,6 +139,7 @@
private static final int MSG_BRIGHTNESS_RAMP_DONE = 12;
private static final int MSG_STATSD_HBM_BRIGHTNESS = 13;
private static final int MSG_SWITCH_USER = 14;
+ private static final int MSG_BOOT_COMPLETED = 15;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -518,6 +519,8 @@
private final SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers =
new SparseArray<>();
+ private boolean mBootCompleted;
+
/**
* Creates the display power controller.
*/
@@ -525,7 +528,8 @@
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
- Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) {
+ Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata,
+ boolean bootCompleted) {
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
@@ -662,6 +666,7 @@
mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mBootCompleted = bootCompleted;
}
private void applyReduceBrightColorsSplineAdjustment() {
@@ -1188,17 +1193,15 @@
}
loadScreenOffBrightnessSensor();
int[] sensorValueToLux = mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux();
- // TODO (b/265793751): Don't instantiate ScreenOffBrightnessSensorController if this is
- // a complementary display
if (mScreenOffBrightnessSensor != null && sensorValueToLux != null) {
- mScreenOffBrightnessSensorController = new ScreenOffBrightnessSensorController(
- mSensorManager,
- mScreenOffBrightnessSensor,
- mHandler,
- SystemClock::uptimeMillis,
- sensorValueToLux,
- mInteractiveModeBrightnessMapper
- );
+ mScreenOffBrightnessSensorController =
+ mInjector.getScreenOffBrightnessSensorController(
+ mSensorManager,
+ mScreenOffBrightnessSensor,
+ mHandler,
+ SystemClock::uptimeMillis,
+ sensorValueToLux,
+ mInteractiveModeBrightnessMapper);
}
} else {
mUseSoftwareAutoBrightnessConfig = false;
@@ -1390,8 +1393,9 @@
if (mScreenOffBrightnessSensorController != null) {
mScreenOffBrightnessSensorController.setLightSensorEnabled(mUseAutoBrightness
- && (state == Display.STATE_OFF || (state == Display.STATE_DOZE
- && !mAllowAutoBrightnessWhileDozingConfig)));
+ && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE
+ && !mAllowAutoBrightnessWhileDozingConfig))
+ && mLeadDisplayId == Layout.NO_LEAD_DISPLAY);
}
boolean skipRampBecauseOfProximityChangeToNegative = false;
@@ -1448,7 +1452,7 @@
// Initialize things the first time the power state is changed.
if (mustInitialize) {
- initialize(state);
+ initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN);
}
// Animate the screen state change unless already animating.
@@ -2154,7 +2158,8 @@
}
}
- if (!reportOnly && mPowerState.getScreenState() != state) {
+ if (!reportOnly && mPowerState.getScreenState() != state
+ && readyToUpdateDisplayState()) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state);
// TODO(b/153319140) remove when we can get this from the above trace invocation
SystemProperties.set("debug.tracing.screen_state", String.valueOf(state));
@@ -2538,11 +2543,11 @@
mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
- mHandler.post(() -> {
+ mHandler.postAtTime(() -> {
mUseAutoBrightness = screenBrightnessModeSetting
== Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
updatePowerState();
- });
+ }, mClock.uptimeMillis());
}
private float getAutoBrightnessAdjustmentSetting() {
@@ -2567,6 +2572,12 @@
mBrightnessSetting.setBrightness(brightnessValue);
}
+ @Override
+ public void onBootCompleted() {
+ Message msg = mHandler.obtainMessage(MSG_BOOT_COMPLETED);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
+ }
+
private void updateScreenBrightnessSetting(float brightnessValue) {
if (!isValidBrightnessValue(brightnessValue)
|| brightnessValue == mCurrentScreenBrightnessSetting) {
@@ -2712,6 +2723,17 @@
}
};
+ /**
+ * Indicates whether the display state is ready to update. If this is the default display, we
+ * want to update it right away so that we can draw the boot animation on it. If it is not
+ * the default display, drawing the boot animation on it would look incorrect, so we need
+ * to wait until boot is completed.
+ * @return True if the display state is ready to update
+ */
+ private boolean readyToUpdateDisplayState() {
+ return mDisplayId == Display.DEFAULT_DISPLAY || mBootCompleted;
+ }
+
@Override
public void dump(final PrintWriter pw) {
synchronized (mLock) {
@@ -3235,6 +3257,11 @@
case MSG_SWITCH_USER:
handleOnSwitchUser(msg.arg1);
break;
+
+ case MSG_BOOT_COMPLETED:
+ mBootCompleted = true;
+ updatePowerState();
+ break;
}
}
}
@@ -3418,6 +3445,23 @@
darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold,
potentialOldBrightnessRange);
}
+
+ ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController(
+ SensorManager sensorManager,
+ Sensor lightSensor,
+ Handler handler,
+ ScreenOffBrightnessSensorController.Clock clock,
+ int[] sensorValueToLux,
+ BrightnessMappingStrategy brightnessMapper) {
+ return new ScreenOffBrightnessSensorController(
+ sensorManager,
+ lightSensor,
+ handler,
+ clock,
+ sensorValueToLux,
+ brightnessMapper
+ );
+ }
}
static class CachedBrightnessInfo {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 0861a37..a928777 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -137,6 +137,7 @@
private static final int MSG_BRIGHTNESS_RAMP_DONE = 10;
private static final int MSG_STATSD_HBM_BRIGHTNESS = 11;
private static final int MSG_SWITCH_USER = 12;
+ private static final int MSG_BOOT_COMPLETED = 13;
private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500;
@@ -425,6 +426,8 @@
private SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers =
new SparseArray();
+ private boolean mBootCompleted;
+
/**
* Creates the display power controller.
*/
@@ -432,7 +435,8 @@
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
- Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) {
+ Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata,
+ boolean bootCompleted) {
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
@@ -555,6 +559,7 @@
mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mBootCompleted = bootCompleted;
}
private void applyReduceBrightColorsSplineAdjustment() {
@@ -1025,17 +1030,15 @@
loadScreenOffBrightnessSensor();
int[] sensorValueToLux = mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux();
- // TODO (b/265793751): Don't instantiate ScreenOffBrightnessSensorController if this is
- // a complementary display
if (mScreenOffBrightnessSensor != null && sensorValueToLux != null) {
- mScreenOffBrightnessSensorController = new ScreenOffBrightnessSensorController(
- mSensorManager,
- mScreenOffBrightnessSensor,
- mHandler,
- SystemClock::uptimeMillis,
- sensorValueToLux,
- mInteractiveModeBrightnessMapper
- );
+ mScreenOffBrightnessSensorController =
+ mInjector.getScreenOffBrightnessSensorController(
+ mSensorManager,
+ mScreenOffBrightnessSensor,
+ mHandler,
+ SystemClock::uptimeMillis,
+ sensorValueToLux,
+ mInteractiveModeBrightnessMapper);
}
} else {
mUseSoftwareAutoBrightnessConfig = false;
@@ -1184,13 +1187,14 @@
if (mScreenOffBrightnessSensorController != null) {
mScreenOffBrightnessSensorController.setLightSensorEnabled(mUseAutoBrightness
- && (state == Display.STATE_OFF || (state == Display.STATE_DOZE
- && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig())));
+ && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE
+ && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()))
+ && mLeadDisplayId == Layout.NO_LEAD_DISPLAY);
}
// Initialize things the first time the power state is changed.
if (mustInitialize) {
- initialize(state);
+ initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN);
}
// Animate the screen state change unless already animating.
@@ -1720,6 +1724,12 @@
}
}
+ @Override
+ public void onBootCompleted() {
+ Message msg = mHandler.obtainMessage(MSG_BOOT_COMPLETED);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
+ }
+
private boolean saveBrightnessInfo(float brightness) {
return saveBrightnessInfo(brightness, brightness);
}
@@ -1861,7 +1871,8 @@
}
}
- if (!reportOnly && mPowerState.getScreenState() != state) {
+ if (!reportOnly && mPowerState.getScreenState() != state
+ && readyToUpdateDisplayState()) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state);
// TODO(b/153319140) remove when we can get this from the above trace invocation
SystemProperties.set("debug.tracing.screen_state", String.valueOf(state));
@@ -2138,11 +2149,11 @@
mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
- mHandler.post(() -> {
+ mHandler.postAtTime(() -> {
mUseAutoBrightness = screenBrightnessModeSetting
== Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
updatePowerState();
- });
+ }, mClock.uptimeMillis());
}
private float getAutoBrightnessAdjustmentSetting() {
@@ -2519,6 +2530,17 @@
}
}
+ /**
+ * Indicates whether the display state is ready to update. If this is the default display, we
+ * want to update it right away so that we can draw the boot animation on it. If it is not
+ * the default display, drawing the boot animation on it would look incorrect, so we need
+ * to wait until boot is completed.
+ * @return True if the display state is ready to update
+ */
+ private boolean readyToUpdateDisplayState() {
+ return mDisplayId == Display.DEFAULT_DISPLAY || mBootCompleted;
+ }
+
// Return bucket index of range_[left]_[right] where
// left <= nits < right
private int nitsToRangeIndex(float nits) {
@@ -2738,6 +2760,11 @@
case MSG_SWITCH_USER:
handleOnSwitchUser(msg.arg1);
break;
+
+ case MSG_BOOT_COMPLETED:
+ mBootCompleted = true;
+ updatePowerState();
+ break;
}
}
}
@@ -2896,6 +2923,23 @@
darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold,
potentialOldBrightnessRange);
}
+
+ ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController(
+ SensorManager sensorManager,
+ Sensor lightSensor,
+ Handler handler,
+ ScreenOffBrightnessSensorController.Clock clock,
+ int[] sensorValueToLux,
+ BrightnessMappingStrategy brightnessMapper) {
+ return new ScreenOffBrightnessSensorController(
+ sensorManager,
+ lightSensor,
+ handler,
+ clock,
+ sensorValueToLux,
+ brightnessMapper
+ );
+ }
}
static class CachedBrightnessInfo {
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index 0bc8154..73edb97 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -206,4 +206,9 @@
* @param follower The DPC to remove from the followers list
*/
void removeDisplayBrightnessFollower(DisplayPowerControllerInterface follower);
+
+ /**
+ * Indicate that boot has been completed and the screen is ready to update.
+ */
+ void onBootCompleted();
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 8f65775..25fd5ea 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -370,11 +370,6 @@
mLastRestartTimestampMap.put(contextHubId,
new AtomicLong(SystemClock.elapsedRealtimeNanos()));
- IContextHubClient client = mClientManager.registerClient(
- contextHubInfo, createDefaultClientCallback(contextHubId),
- /* attributionTag= */ null, mTransactionManager, mContext.getPackageName());
- defaultClientMap.put(contextHubId, client);
-
try {
mContextHubWrapper.registerCallback(contextHubId,
new ContextHubServiceCallback(contextHubId));
@@ -383,6 +378,11 @@
+ contextHubId + ")", e);
}
+ IContextHubClient client = mClientManager.registerClient(
+ contextHubInfo, createDefaultClientCallback(contextHubId),
+ /* attributionTag= */ null, mTransactionManager, mContext.getPackageName());
+ defaultClientMap.put(contextHubId, client);
+
// Do a query to initialize the service cache list of nanoapps
// TODO(b/194289715): Remove this when old API is deprecated
queryNanoAppsInternal(contextHubId);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 11efd41..58ae955 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3938,22 +3938,22 @@
@GuardedBy({"mPackagesLock"})
private void fallbackToSingleUserLP() {
- int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN
- | UserInfo.FLAG_PRIMARY;
// Create the system user
- String systemUserType = isDefaultHeadlessSystemUserMode()
+ final String systemUserType = isDefaultHeadlessSystemUserMode()
? UserManager.USER_TYPE_SYSTEM_HEADLESS
: UserManager.USER_TYPE_FULL_SYSTEM;
- flags |= mUserTypes.get(systemUserType).getDefaultUserInfoFlags();
- UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags, systemUserType);
- UserData userData = putUserInfo(system);
+ final int flags = mUserTypes.get(systemUserType).getDefaultUserInfoFlags()
+ | UserInfo.FLAG_INITIALIZED;
+ final UserInfo system = new UserInfo(UserHandle.USER_SYSTEM,
+ /* name= */ null, /* iconPath= */ null, flags, systemUserType);
+ final UserData userData = putUserInfo(system);
userData.userProperties = new UserProperties(
mUserTypes.get(userData.info.userType).getDefaultUserPropertiesReference());
mNextSerialNumber = MIN_USER_ID;
mUserVersion = USER_VERSION;
mUserTypeVersion = UserTypeFactory.getUserTypeVersion();
- Bundle restrictions = new Bundle();
+ final Bundle restrictions = new Bundle();
try {
final String[] defaultFirstUserRestrictions = mContext.getResources().getStringArray(
com.android.internal.R.array.config_defaultFirstUserRestrictions);
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index f86ee90..6065372 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -76,7 +76,7 @@
private final @UserInfoFlag int mBaseType;
// TODO(b/143784345): Update doc/name when we clean up UserInfo.
- /** The {@link UserInfo.UserInfoFlag}s that all users of this type will automatically have. */
+ /** The {@link UserInfoFlag}s to apply by default to newly created users of this type. */
private final @UserInfoFlag int mDefaultUserInfoPropertyFlags;
/**
@@ -224,7 +224,7 @@
}
// TODO(b/143784345): Update comment when UserInfo is reorganized.
- /** The {@link UserInfo.UserInfoFlag}s that all users of this type will automatically have. */
+ /** The {@link UserInfoFlag}s to apply by default to newly created users of this type. */
public int getDefaultUserInfoFlags() {
return mDefaultUserInfoPropertyFlags | mBaseType;
}
@@ -526,6 +526,7 @@
Preconditions.checkArgument(hasValidPropertyFlags(),
"UserTypeDetails " + mName + " has invalid flags: "
+ Integer.toHexString(mDefaultUserInfoPropertyFlags));
+ checkSystemAndMainUserPreconditions();
if (hasBadge()) {
Preconditions.checkArgument(mBadgeLabels != null && mBadgeLabels.length != 0,
"UserTypeDetails " + mName + " has badge but no badgeLabels.");
@@ -578,8 +579,6 @@
// TODO(b/143784345): Refactor this when we clean up UserInfo.
private boolean hasValidPropertyFlags() {
final int forbiddenMask =
- UserInfo.FLAG_PRIMARY |
- UserInfo.FLAG_ADMIN |
UserInfo.FLAG_INITIALIZED |
UserInfo.FLAG_QUIET_MODE |
UserInfo.FLAG_FULL |
@@ -587,6 +586,18 @@
UserInfo.FLAG_PROFILE;
return (mDefaultUserInfoPropertyFlags & forbiddenMask) == 0;
}
+
+ private void checkSystemAndMainUserPreconditions() {
+ // Primary must be synonymous with System.
+ Preconditions.checkArgument(
+ ((mBaseType & UserInfo.FLAG_SYSTEM) != 0) ==
+ ((mDefaultUserInfoPropertyFlags & UserInfo.FLAG_PRIMARY) != 0),
+ "UserTypeDetails " + mName + " cannot be SYSTEM xor PRIMARY.");
+ // At most one MainUser is ever allowed at a time.
+ Preconditions.checkArgument(
+ ((mDefaultUserInfoPropertyFlags & UserInfo.FLAG_MAIN) == 0) || mMaxAllowed == 1,
+ "UserTypeDetails " + mName + " must not sanction more than one MainUser.");
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 4cf8c09..b7a2b86 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -16,11 +16,14 @@
package com.android.server.pm;
+import static android.content.pm.UserInfo.FLAG_ADMIN;
import static android.content.pm.UserInfo.FLAG_DEMO;
import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
import static android.content.pm.UserInfo.FLAG_FULL;
import static android.content.pm.UserInfo.FLAG_GUEST;
+import static android.content.pm.UserInfo.FLAG_MAIN;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_PROFILE;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.content.pm.UserInfo.FLAG_SYSTEM;
@@ -62,7 +65,7 @@
* This class is responsible both for defining the AOSP use types, as well as reading in customized
* user types from {@link com.android.internal.R.xml#config_user_types}.
*
- * Tests are located in UserManagerServiceUserTypeTest.java.
+ * Tests are located in {@link UserManagerServiceUserTypeTest}.
* @hide
*/
public final class UserTypeFactory {
@@ -277,7 +280,8 @@
return new UserTypeDetails.Builder()
.setName(USER_TYPE_FULL_SYSTEM)
.setBaseType(FLAG_SYSTEM | FLAG_FULL)
- .setDefaultUserInfoPropertyFlags(UserInfo.FLAG_MAIN);
+ .setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN | FLAG_MAIN)
+ .setMaxAllowed(1);
}
/**
@@ -287,7 +291,9 @@
private static UserTypeDetails.Builder getDefaultTypeSystemHeadless() {
return new UserTypeDetails.Builder()
.setName(USER_TYPE_SYSTEM_HEADLESS)
- .setBaseType(FLAG_SYSTEM);
+ .setBaseType(FLAG_SYSTEM)
+ .setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN)
+ .setMaxAllowed(1);
}
private static Bundle getDefaultSecondaryUserRestrictions() {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 78761bd..cc2c9ad 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -3673,9 +3673,9 @@
isAppOpPermission = bp.isAppOp();
}
+ final int flags = getPermissionFlagsInternal(pkg.getPackageName(), permission,
+ myUid, userId);
if (shouldGrantRuntimePermission) {
- final int flags = getPermissionFlagsInternal(pkg.getPackageName(), permission,
- myUid, userId);
if (supportsRuntimePermissions) {
// Installer cannot change immutable permissions.
if ((flags & immutableFlags) == 0) {
@@ -3693,6 +3693,9 @@
} else if (isAppOpPermission
&& PackageInstallerService.INSTALLER_CHANGEABLE_APP_OP_PERMISSIONS
.contains(permission)) {
+ if ((flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0) {
+ continue;
+ }
int mode =
permissionState == PERMISSION_STATE_GRANTED ? MODE_ALLOWED : MODE_ERRORED;
int uid = UserHandle.getUid(userId, pkg.getUid());
diff --git a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
index 0809297..4a6c794 100644
--- a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
@@ -115,7 +115,7 @@
TimeDetectorInternal timeDetectorInternal =
LocalServices.getService(TimeDetectorInternal.class);
// Broadcast alarms sent by system are immutable
- Intent pollIntent = new Intent(ACTION_POLL, null);
+ Intent pollIntent = new Intent(ACTION_POLL, null).setPackage("android");
PendingIntent pendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST,
pollIntent, PendingIntent.FLAG_IMMUTABLE);
mRefreshCallbacks = new Engine.RefreshCallbacks() {
@@ -228,16 +228,14 @@
}
private void onPollNetworkTime(@NonNull String reason) {
- // If we don't have any default network, don't bother.
Network network;
synchronized (mLock) {
network = mDefaultNetwork;
}
- if (network == null) return;
mWakeLock.acquire();
try {
- mEngine.refreshIfRequiredAndReschedule(network, reason, mRefreshCallbacks);
+ mEngine.refreshAndRescheduleIfRequired(network, reason, mRefreshCallbacks);
} finally {
mWakeLock.release();
}
@@ -338,10 +336,10 @@
* Attempts to refresh the network time if required, i.e. if there isn't a recent-enough
* network time available. It must also schedule the next call. This is a blocking call.
*
- * @param network the network to use
+ * @param network the network to use, or null if no network is available
* @param reason the reason for the refresh (for logging)
*/
- void refreshIfRequiredAndReschedule(@NonNull Network network, @NonNull String reason,
+ void refreshAndRescheduleIfRequired(@Nullable Network network, @NonNull String reason,
@NonNull RefreshCallbacks refreshCallbacks);
void dump(@NonNull PrintWriter pw);
@@ -391,7 +389,7 @@
/**
* Records the time of the last refresh attempt (successful or otherwise) by this service.
* This is used when scheduling the next refresh attempt. In cases where {@link
- * #refreshIfRequiredAndReschedule} is called too frequently, this will prevent each call
+ * #refreshAndRescheduleIfRequired} is called too frequently, this will prevent each call
* resulting in a network request. See also {@link #mShortPollingIntervalMillis}.
*
* <p>Time servers are a shared resource and so Android should avoid loading them.
@@ -443,9 +441,19 @@
}
@Override
- public void refreshIfRequiredAndReschedule(
- @NonNull Network network, @NonNull String reason,
+ public void refreshAndRescheduleIfRequired(
+ @Nullable Network network, @NonNull String reason,
@NonNull RefreshCallbacks refreshCallbacks) {
+ if (network == null) {
+ // If we don't have any default network, don't do anything: When a new network
+ // is available then this method will be called again.
+ logToDebugAndDumpsys("refreshIfRequiredAndReschedule:"
+ + " reason=" + reason
+ + ": No default network available. No refresh attempted and no next"
+ + " attempt scheduled.");
+ return;
+ }
+
// Attempt to refresh the network time if there is no latest time result, or if the
// latest time result is considered too old.
NtpTrustedTime.TimeResult initialTimeResult = mNtpTrustedTime.getCachedTimeResult();
diff --git a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java
index 410b50f..afc0bdd 100644
--- a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java
@@ -157,7 +157,7 @@
SET_SERVER_CONFIG_SERVER_ARG, SET_SERVER_CONFIG_SERVER_ARG,
SET_SERVER_CONFIG_TIMEOUT_ARG);
pw.printf(" NTP server URIs must be in the form \"ntp://hostname\" or"
- + " \"ntp://hostname:port\"");
+ + " \"ntp://hostname:port\"\n");
pw.printf(" %s\n", SHELL_COMMAND_RESET_SERVER_CONFIG);
pw.printf(" Resets/clears the NTP server config set via %s.\n",
SHELL_COMMAND_SET_SERVER_CONFIG);
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index 6782229..28d34c2 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -304,7 +304,7 @@
/**
* Returns an {@link Instant} from {@link DeviceConfig} from the system_time
- * namespace, returns the {@code defaultValue} if the value is missing or invalid.
+ * namespace, returns {@link Optional#empty()} if there is no explicit value set.
*/
@NonNull
public Optional<Instant> getOptionalInstant(@DeviceConfigKey String key) {
@@ -341,16 +341,17 @@
}
/**
- * Returns a boolean value from {@link DeviceConfig} from the system_time
- * namespace, or {@code defaultValue} if there is no explicit value set.
+ * Returns a boolean value from {@link DeviceConfig} from the system_time namespace, or
+ * {@code defaultValue} if there is no explicit value set.
*/
public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) {
return DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
}
/**
- * Returns a positive duration from {@link DeviceConfig} from the system_time
- * namespace, or {@code defaultValue} if there is no explicit value set.
+ * Returns a positive duration from {@link DeviceConfig} from the system_time namespace,
+ * or {@code defaultValue} if there is no explicit value set or if the value is not a number or
+ * is negative.
*/
@Nullable
public Duration getDurationFromMillis(
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d7829c8..357d3f5 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -772,7 +772,7 @@
DisplayConnector connector =
targetWallpaper.connection.getDisplayConnectorOrCreate(displayId);
if (connector == null) return;
- connector.disconnectLocked();
+ connector.disconnectLocked(targetWallpaper.connection);
targetWallpaper.connection.removeDisplayConnector(displayId);
mWallpaperDisplayHelper.removeDisplayData(displayId);
}
@@ -859,7 +859,7 @@
if (fallbackConnection.mDisplayConnector.size() != 0) {
fallbackConnection.forEachDisplayConnector(connector -> {
if (connector.mEngine != null) {
- connector.disconnectLocked();
+ connector.disconnectLocked(fallbackConnection);
}
});
fallbackConnection.mDisplayConnector.clear();
@@ -940,16 +940,14 @@
t.traceEnd();
}
- void disconnectLocked() {
+ void disconnectLocked(WallpaperConnection connection) {
if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken);
mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */,
mDisplayId);
try {
- if (mEngine != null) {
- mEngine.destroy();
- }
+ connection.mService.detach(mToken);
} catch (RemoteException e) {
- Slog.w(TAG, "Engine.destroy() threw a RemoteException");
+ Slog.w(TAG, "connection.mService.destroy() threw a RemoteException");
}
mEngine = null;
}
@@ -1249,12 +1247,7 @@
synchronized (mLock) {
final DisplayConnector connector = getDisplayConnectorOrCreate(displayId);
if (connector == null) {
- try {
- engine.destroy();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to destroy engine", e);
- }
- return;
+ throw new IllegalStateException("Connector has already been destroyed");
}
connector.mEngine = engine;
connector.ensureStatusHandled();
@@ -3261,20 +3254,8 @@
}
wallpaper.connection.mReply = null;
}
- try {
- // It can be null if user switching happens before service connection.
- if (wallpaper.connection.mService != null) {
- wallpaper.connection.mService.detach();
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed detaching wallpaper service ", e);
- }
- try {
- mContext.unbindService(wallpaper.connection);
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Attempted to unbind unregistered service");
- }
- wallpaper.connection.forEachDisplayConnector(DisplayConnector::disconnectLocked);
+ wallpaper.connection.forEachDisplayConnector(
+ connector -> connector.disconnectLocked(wallpaper.connection));
wallpaper.connection.mService = null;
wallpaper.connection.mDisplayConnector.clear();
@@ -3284,6 +3265,7 @@
mContext.getMainThreadHandler().removeCallbacks(
wallpaper.connection.mTryToRebindRunnable);
+ mContext.unbindService(wallpaper.connection);
wallpaper.connection = null;
if (wallpaper == mLastWallpaper) {
mLastWallpaper = null;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3545747..89b7968 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2159,7 +2159,7 @@
boolean appActivityEmbeddingEnabled = false;
try {
- appActivityEmbeddingEnabled = WindowManagerService.sWindowExtensionsEnabled
+ appActivityEmbeddingEnabled = WindowManager.hasWindowExtensionsEnabled()
&& mAtmService.mContext.getPackageManager()
.getProperty(PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED, packageName)
.getBoolean();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d5bf9f9..c30aef4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -442,16 +442,6 @@
static final boolean ENABLE_FIXED_ROTATION_TRANSFORM =
SystemProperties.getBoolean("persist.wm.fixed_rotation_transform", true);
- /**
- * Whether the device supports the WindowManager Extensions.
- * OEMs can enable this by having their device config to inherit window_extensions.mk, such as:
- * <pre>
- * $(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)
- * </pre>
- */
- static final boolean sWindowExtensionsEnabled =
- SystemProperties.getBoolean("persist.wm.extensions.enabled", false);
-
// Enums for animation scale update types.
@Retention(RetentionPolicy.SOURCE)
@IntDef({WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE, ANIMATION_DURATION_SCALE})
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index f9592cc..080af7e 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -18,7 +18,7 @@
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.isStartResultSuccessful;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
@@ -532,9 +532,9 @@
// setWindowingMode call in force-hidden.
boolean forceHiddenForPip = false;
if (wc.asTask() != null && wc.inPinnedWindowingMode()
- && entry.getValue().getWindowingMode() == WINDOWING_MODE_UNDEFINED) {
- // We are in pip and going to undefined. Now search hierarchy ops to determine
- // whether we are removing pip or expanding pip.
+ && entry.getValue().getWindowingMode() != WINDOWING_MODE_PINNED) {
+ // We are going out of pip. Now search hierarchy ops to determine whether we
+ // are removing pip or expanding pip.
for (int i = 0; i < hopSize; ++i) {
final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
if (hop.getType() != HIERARCHY_OP_TYPE_REORDER) continue;
@@ -670,7 +670,7 @@
+ " windowing mode during locked task mode.");
}
- if (windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED) {
+ if (windowingMode == WINDOWING_MODE_PINNED) {
// Do not directly put the container into PINNED mode as it may not support it or
// the app may not want to enter it. Instead, send a signal to request PIP
// mode to the app if they wish to support it below in #applyTaskChanges.
@@ -722,7 +722,7 @@
tr.mDisplayContent.mPinnedTaskController.setEnterPipBounds(enterPipBounds);
}
- if (c.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_PINNED
+ if (c.getWindowingMode() == WINDOWING_MODE_PINNED
&& !tr.inPinnedWindowingMode()) {
final ActivityRecord activity = tr.getTopNonFinishingActivity();
if (activity != null) {
diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
index dd757bc..4898d95 100644
--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
@@ -22,6 +22,7 @@
#include <errno.h>
#include <fcntl.h>
#include <input/Input.h>
+#include <input/VirtualInputDevice.h>
#include <linux/uinput.h>
#include <math.h>
#include <nativehelper/JNIHelp.h>
@@ -32,16 +33,12 @@
#include <set>
#include <string>
-/**
- * Log debug messages about native virtual input devices.
- * Enable this via "adb shell setprop log.tag.InputController DEBUG"
- */
-static bool isDebug() {
- return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
-}
+using android::base::unique_fd;
namespace android {
+static constexpr jlong INVALID_PTR = 0;
+
enum class DeviceType {
KEYBOARD,
MOUSE,
@@ -49,176 +46,18 @@
DPAD,
};
-enum class UinputAction {
- RELEASE = 0,
- PRESS = 1,
- MOVE = 2,
- CANCEL = 3,
-};
-
-static std::map<int, UinputAction> BUTTON_ACTION_MAPPING = {
- {AMOTION_EVENT_ACTION_BUTTON_PRESS, UinputAction::PRESS},
- {AMOTION_EVENT_ACTION_BUTTON_RELEASE, UinputAction::RELEASE},
-};
-
-static std::map<int, UinputAction> KEY_ACTION_MAPPING = {
- {AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
- {AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
-};
-
-static std::map<int, UinputAction> TOUCH_ACTION_MAPPING = {
- {AMOTION_EVENT_ACTION_DOWN, UinputAction::PRESS},
- {AMOTION_EVENT_ACTION_UP, UinputAction::RELEASE},
- {AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
- {AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
-};
-
-// Button code mapping from https://source.android.com/devices/input/touch-devices
-static std::map<int, int> BUTTON_CODE_MAPPING = {
- {AMOTION_EVENT_BUTTON_PRIMARY, BTN_LEFT}, {AMOTION_EVENT_BUTTON_SECONDARY, BTN_RIGHT},
- {AMOTION_EVENT_BUTTON_TERTIARY, BTN_MIDDLE}, {AMOTION_EVENT_BUTTON_BACK, BTN_BACK},
- {AMOTION_EVENT_BUTTON_FORWARD, BTN_FORWARD},
-};
-
-// Tool type mapping from https://source.android.com/devices/input/touch-devices
-static std::map<int, int> TOOL_TYPE_MAPPING = {
- {AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
- {AMOTION_EVENT_TOOL_TYPE_PALM, MT_TOOL_PALM},
-};
-
-// Dpad keycode mapping from https://source.android.com/devices/input/keyboard-devices
-static std::map<int, int> DPAD_KEY_CODE_MAPPING = {
- {AKEYCODE_DPAD_DOWN, KEY_DOWN}, {AKEYCODE_DPAD_UP, KEY_UP},
- {AKEYCODE_DPAD_LEFT, KEY_LEFT}, {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
- {AKEYCODE_DPAD_CENTER, KEY_SELECT}, {AKEYCODE_BACK, KEY_BACK},
-};
-
-// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
-static std::map<int, int> KEY_CODE_MAPPING = {
- {AKEYCODE_0, KEY_0},
- {AKEYCODE_1, KEY_1},
- {AKEYCODE_2, KEY_2},
- {AKEYCODE_3, KEY_3},
- {AKEYCODE_4, KEY_4},
- {AKEYCODE_5, KEY_5},
- {AKEYCODE_6, KEY_6},
- {AKEYCODE_7, KEY_7},
- {AKEYCODE_8, KEY_8},
- {AKEYCODE_9, KEY_9},
- {AKEYCODE_A, KEY_A},
- {AKEYCODE_B, KEY_B},
- {AKEYCODE_C, KEY_C},
- {AKEYCODE_D, KEY_D},
- {AKEYCODE_E, KEY_E},
- {AKEYCODE_F, KEY_F},
- {AKEYCODE_G, KEY_G},
- {AKEYCODE_H, KEY_H},
- {AKEYCODE_I, KEY_I},
- {AKEYCODE_J, KEY_J},
- {AKEYCODE_K, KEY_K},
- {AKEYCODE_L, KEY_L},
- {AKEYCODE_M, KEY_M},
- {AKEYCODE_N, KEY_N},
- {AKEYCODE_O, KEY_O},
- {AKEYCODE_P, KEY_P},
- {AKEYCODE_Q, KEY_Q},
- {AKEYCODE_R, KEY_R},
- {AKEYCODE_S, KEY_S},
- {AKEYCODE_T, KEY_T},
- {AKEYCODE_U, KEY_U},
- {AKEYCODE_V, KEY_V},
- {AKEYCODE_W, KEY_W},
- {AKEYCODE_X, KEY_X},
- {AKEYCODE_Y, KEY_Y},
- {AKEYCODE_Z, KEY_Z},
- {AKEYCODE_GRAVE, KEY_GRAVE},
- {AKEYCODE_MINUS, KEY_MINUS},
- {AKEYCODE_EQUALS, KEY_EQUAL},
- {AKEYCODE_LEFT_BRACKET, KEY_LEFTBRACE},
- {AKEYCODE_RIGHT_BRACKET, KEY_RIGHTBRACE},
- {AKEYCODE_BACKSLASH, KEY_BACKSLASH},
- {AKEYCODE_SEMICOLON, KEY_SEMICOLON},
- {AKEYCODE_APOSTROPHE, KEY_APOSTROPHE},
- {AKEYCODE_COMMA, KEY_COMMA},
- {AKEYCODE_PERIOD, KEY_DOT},
- {AKEYCODE_SLASH, KEY_SLASH},
- {AKEYCODE_ALT_LEFT, KEY_LEFTALT},
- {AKEYCODE_ALT_RIGHT, KEY_RIGHTALT},
- {AKEYCODE_CTRL_LEFT, KEY_LEFTCTRL},
- {AKEYCODE_CTRL_RIGHT, KEY_RIGHTCTRL},
- {AKEYCODE_SHIFT_LEFT, KEY_LEFTSHIFT},
- {AKEYCODE_SHIFT_RIGHT, KEY_RIGHTSHIFT},
- {AKEYCODE_META_LEFT, KEY_LEFTMETA},
- {AKEYCODE_META_RIGHT, KEY_RIGHTMETA},
- {AKEYCODE_CAPS_LOCK, KEY_CAPSLOCK},
- {AKEYCODE_SCROLL_LOCK, KEY_SCROLLLOCK},
- {AKEYCODE_NUM_LOCK, KEY_NUMLOCK},
- {AKEYCODE_ENTER, KEY_ENTER},
- {AKEYCODE_TAB, KEY_TAB},
- {AKEYCODE_SPACE, KEY_SPACE},
- {AKEYCODE_DPAD_DOWN, KEY_DOWN},
- {AKEYCODE_DPAD_UP, KEY_UP},
- {AKEYCODE_DPAD_LEFT, KEY_LEFT},
- {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
- {AKEYCODE_MOVE_END, KEY_END},
- {AKEYCODE_MOVE_HOME, KEY_HOME},
- {AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN},
- {AKEYCODE_PAGE_UP, KEY_PAGEUP},
- {AKEYCODE_DEL, KEY_BACKSPACE},
- {AKEYCODE_FORWARD_DEL, KEY_DELETE},
- {AKEYCODE_INSERT, KEY_INSERT},
- {AKEYCODE_ESCAPE, KEY_ESC},
- {AKEYCODE_BREAK, KEY_PAUSE},
- {AKEYCODE_F1, KEY_F1},
- {AKEYCODE_F2, KEY_F2},
- {AKEYCODE_F3, KEY_F3},
- {AKEYCODE_F4, KEY_F4},
- {AKEYCODE_F5, KEY_F5},
- {AKEYCODE_F6, KEY_F6},
- {AKEYCODE_F7, KEY_F7},
- {AKEYCODE_F8, KEY_F8},
- {AKEYCODE_F9, KEY_F9},
- {AKEYCODE_F10, KEY_F10},
- {AKEYCODE_F11, KEY_F11},
- {AKEYCODE_F12, KEY_F12},
- {AKEYCODE_BACK, KEY_BACK},
- {AKEYCODE_FORWARD, KEY_FORWARD},
- {AKEYCODE_NUMPAD_1, KEY_KP1},
- {AKEYCODE_NUMPAD_2, KEY_KP2},
- {AKEYCODE_NUMPAD_3, KEY_KP3},
- {AKEYCODE_NUMPAD_4, KEY_KP4},
- {AKEYCODE_NUMPAD_5, KEY_KP5},
- {AKEYCODE_NUMPAD_6, KEY_KP6},
- {AKEYCODE_NUMPAD_7, KEY_KP7},
- {AKEYCODE_NUMPAD_8, KEY_KP8},
- {AKEYCODE_NUMPAD_9, KEY_KP9},
- {AKEYCODE_NUMPAD_0, KEY_KP0},
- {AKEYCODE_NUMPAD_ADD, KEY_KPPLUS},
- {AKEYCODE_NUMPAD_SUBTRACT, KEY_KPMINUS},
- {AKEYCODE_NUMPAD_MULTIPLY, KEY_KPASTERISK},
- {AKEYCODE_NUMPAD_DIVIDE, KEY_KPSLASH},
- {AKEYCODE_NUMPAD_DOT, KEY_KPDOT},
- {AKEYCODE_NUMPAD_ENTER, KEY_KPENTER},
- {AKEYCODE_NUMPAD_EQUALS, KEY_KPEQUAL},
- {AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
-};
-
-/*
- * Map from the uinput touchscreen fd to the pointers present in the previous touch events that
- * hasn't been lifted.
- * We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual
- * touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id to go
- * up to MAX_POINTERS_ID.
- */
-static std::map<int32_t, std::bitset<MAX_POINTERS>> unreleasedTouches;
+static unique_fd invalidFd() {
+ return unique_fd(-1);
+}
/** Creates a new uinput device and assigns a file descriptor. */
-static int openUinput(const char* readableName, jint vendorId, jint productId, const char* phys,
- DeviceType deviceType, jint screenHeight, jint screenWidth) {
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
+static unique_fd openUinput(const char* readableName, jint vendorId, jint productId,
+ const char* phys, DeviceType deviceType, jint screenHeight,
+ jint screenWidth) {
+ unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
if (fd < 0) {
ALOGE("Error creating uinput device: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
ioctl(fd, UI_SET_PHYS, phys);
@@ -227,12 +66,12 @@
ioctl(fd, UI_SET_EVBIT, EV_SYN);
switch (deviceType) {
case DeviceType::DPAD:
- for (const auto& [_, keyCode] : DPAD_KEY_CODE_MAPPING) {
+ for (const auto& [_, keyCode] : VirtualDpad::DPAD_KEY_CODE_MAPPING) {
ioctl(fd, UI_SET_KEYBIT, keyCode);
}
break;
case DeviceType::KEYBOARD:
- for (const auto& [_, keyCode] : KEY_CODE_MAPPING) {
+ for (const auto& [_, keyCode] : VirtualKeyboard::KEY_CODE_MAPPING) {
ioctl(fd, UI_SET_KEYBIT, keyCode);
}
break;
@@ -277,7 +116,7 @@
xAbsSetup.absinfo.minimum = 0;
if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
ALOGE("Error creating touchscreen uinput x axis: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
uinput_abs_setup yAbsSetup;
yAbsSetup.code = ABS_MT_POSITION_Y;
@@ -285,7 +124,7 @@
yAbsSetup.absinfo.minimum = 0;
if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
ALOGE("Error creating touchscreen uinput y axis: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
uinput_abs_setup majorAbsSetup;
majorAbsSetup.code = ABS_MT_TOUCH_MAJOR;
@@ -293,7 +132,7 @@
majorAbsSetup.absinfo.minimum = 0;
if (ioctl(fd, UI_ABS_SETUP, &majorAbsSetup) != 0) {
ALOGE("Error creating touchscreen uinput major axis: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
uinput_abs_setup pressureAbsSetup;
pressureAbsSetup.code = ABS_MT_PRESSURE;
@@ -301,7 +140,7 @@
pressureAbsSetup.absinfo.minimum = 0;
if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
uinput_abs_setup slotAbsSetup;
slotAbsSetup.code = ABS_MT_SLOT;
@@ -309,12 +148,12 @@
slotAbsSetup.absinfo.minimum = 0;
if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
}
if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
ALOGE("Error creating uinput device: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
} else {
// UI_DEV_SETUP was not introduced until version 5. Try setting up manually.
@@ -338,255 +177,118 @@
}
if (TEMP_FAILURE_RETRY(write(fd, &fallback, sizeof(fallback))) != sizeof(fallback)) {
ALOGE("Error creating uinput device: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
}
if (ioctl(fd, UI_DEV_CREATE) != 0) {
ALOGE("Error creating uinput device: %s", strerror(errno));
- return -errno;
+ return invalidFd();
}
- return fd.release();
+ return fd;
}
-static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, jstring phys,
- DeviceType deviceType, int screenHeight, int screenWidth) {
+static unique_fd openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId,
+ jstring phys, DeviceType deviceType, int screenHeight,
+ int screenWidth) {
ScopedUtfChars readableName(env, name);
ScopedUtfChars readablePhys(env, phys);
return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType,
screenHeight, screenWidth);
}
-static int nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
- jint productId, jstring phys) {
- return openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
- /* screenHeight */ 0, /* screenWidth */ 0);
+static jlong nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
+ jint productId, jstring phys) {
+ auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
+ /* screenHeight= */ 0, /* screenWidth= */ 0);
+ return fd.ok() ? reinterpret_cast<jlong>(new VirtualDpad(std::move(fd))) : INVALID_PTR;
}
-static int nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
- jint productId, jstring phys) {
- return openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
- /* screenHeight */ 0, /* screenWidth */ 0);
+static jlong nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
+ jint productId, jstring phys) {
+ auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
+ /* screenHeight= */ 0, /* screenWidth= */ 0);
+ return fd.ok() ? reinterpret_cast<jlong>(new VirtualKeyboard(std::move(fd))) : INVALID_PTR;
}
-static int nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
- jint productId, jstring phys) {
- return openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
- /* screenHeight */ 0, /* screenWidth */ 0);
+static jlong nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
+ jint productId, jstring phys) {
+ auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
+ /* screenHeight= */ 0, /* screenWidth= */ 0);
+ return fd.ok() ? reinterpret_cast<jlong>(new VirtualMouse(std::move(fd))) : INVALID_PTR;
}
-static int nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
- jint productId, jstring phys, jint height, jint width) {
- return openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
- width);
+static jlong nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
+ jint productId, jstring phys, jint height, jint width) {
+ auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
+ width);
+ return fd.ok() ? reinterpret_cast<jlong>(new VirtualTouchscreen(std::move(fd))) : INVALID_PTR;
}
-static bool nativeCloseUinput(JNIEnv* env, jobject thiz, jint fd) {
- ioctl(fd, UI_DEV_DESTROY);
- if (auto touchesOnFd = unreleasedTouches.find(fd); touchesOnFd != unreleasedTouches.end()) {
- const size_t remainingPointers = touchesOnFd->second.size();
- unreleasedTouches.erase(touchesOnFd);
- ALOGW_IF(remainingPointers > 0, "Closing touchscreen %d, erased %zu unreleased pointers.",
- fd, remainingPointers);
- }
- return close(fd);
+static void nativeCloseUinput(JNIEnv* env, jobject thiz, jlong ptr) {
+ VirtualInputDevice* virtualInputDevice = reinterpret_cast<VirtualInputDevice*>(ptr);
+ delete virtualInputDevice;
}
-static bool writeInputEvent(int fd, uint16_t type, uint16_t code, int32_t value) {
- struct input_event ev = {.type = type, .code = code, .value = value};
- return TEMP_FAILURE_RETRY(write(fd, &ev, sizeof(struct input_event))) == sizeof(ev);
-}
-
-static bool writeKeyEvent(jint fd, jint androidKeyCode, jint action,
- const std::map<int, int>& keyCodeMapping) {
- auto keyCodeIterator = keyCodeMapping.find(androidKeyCode);
- if (keyCodeIterator == keyCodeMapping.end()) {
- ALOGE("Unsupported native keycode for androidKeyCode %d", androidKeyCode);
- return false;
- }
- auto actionIterator = KEY_ACTION_MAPPING.find(action);
- if (actionIterator == KEY_ACTION_MAPPING.end()) {
- return false;
- }
- if (!writeInputEvent(fd, EV_KEY, static_cast<uint16_t>(keyCodeIterator->second),
- static_cast<int32_t>(actionIterator->second))) {
- return false;
- }
- if (!writeInputEvent(fd, EV_SYN, SYN_REPORT, 0)) {
- return false;
- }
- return true;
-}
-
-static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
+// Native methods for VirtualDpad
+static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
jint action) {
- return writeKeyEvent(fd, androidKeyCode, action, DPAD_KEY_CODE_MAPPING);
+ VirtualDpad* virtualDpad = reinterpret_cast<VirtualDpad*>(ptr);
+ return virtualDpad->writeDpadKeyEvent(androidKeyCode, action);
}
-static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
+// Native methods for VirtualKeyboard
+static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
jint action) {
- return writeKeyEvent(fd, androidKeyCode, action, KEY_CODE_MAPPING);
+ VirtualKeyboard* virtualKeyboard = reinterpret_cast<VirtualKeyboard*>(ptr);
+ return virtualKeyboard->writeKeyEvent(androidKeyCode, action);
}
-static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jint fd, jint buttonCode,
+// Native methods for VirtualTouchscreen
+static bool nativeWriteTouchEvent(JNIEnv* env, jobject thiz, jlong ptr, jint pointerId,
+ jint toolType, jint action, jfloat locationX, jfloat locationY,
+ jfloat pressure, jfloat majorAxisSize) {
+ VirtualTouchscreen* virtualTouchscreen = reinterpret_cast<VirtualTouchscreen*>(ptr);
+ return virtualTouchscreen->writeTouchEvent(pointerId, toolType, action, locationX, locationY,
+ pressure, majorAxisSize);
+}
+
+// Native methods for VirtualMouse
+static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jlong ptr, jint buttonCode,
jint action) {
- auto buttonCodeIterator = BUTTON_CODE_MAPPING.find(buttonCode);
- if (buttonCodeIterator == BUTTON_CODE_MAPPING.end()) {
- return false;
- }
- auto actionIterator = BUTTON_ACTION_MAPPING.find(action);
- if (actionIterator == BUTTON_ACTION_MAPPING.end()) {
- return false;
- }
- if (!writeInputEvent(fd, EV_KEY, static_cast<uint16_t>(buttonCodeIterator->second),
- static_cast<int32_t>(actionIterator->second))) {
- return false;
- }
- if (!writeInputEvent(fd, EV_SYN, SYN_REPORT, 0)) {
- return false;
- }
- return true;
+ VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
+ return virtualMouse->writeButtonEvent(buttonCode, action);
}
-static bool handleTouchUp(int fd, int pointerId) {
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(-1))) {
- return false;
- }
- auto touchesOnFd = unreleasedTouches.find(fd);
- if (touchesOnFd == unreleasedTouches.end()) {
- ALOGE("PointerId %d action UP received with no prior events on touchscreen %d.", pointerId,
- fd);
- return false;
- }
- ALOGD_IF(isDebug(), "Unreleased touches found for touchscreen %d in the map", fd);
-
- // When a pointer is no longer in touch, remove the pointer id from the corresponding
- // entry in the unreleased touches map.
- if (pointerId < 0 || pointerId >= MAX_POINTERS) {
- ALOGE("Virtual touch event has invalid pointer id %d; value must be between 0 and %zu",
- pointerId, MAX_POINTERS - 1);
- return false;
- }
- if (!touchesOnFd->second.test(pointerId)) {
- ALOGE("PointerId %d action UP received with no prior action DOWN on touchscreen %d.",
- pointerId, fd);
- return false;
- }
- touchesOnFd->second.reset(pointerId);
- ALOGD_IF(isDebug(), "Pointer %d erased from the touchscreen %d", pointerId, fd);
-
- // Only sends the BTN UP event when there's no pointers on the touchscreen.
- if (touchesOnFd->second.none()) {
- unreleasedTouches.erase(touchesOnFd);
- if (!writeInputEvent(fd, EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE))) {
- return false;
- }
- ALOGD_IF(isDebug(), "No pointers on touchscreen %d, BTN UP event sent.", fd);
- }
- return true;
-}
-
-static bool handleTouchDown(int fd, int pointerId) {
- // When a new pointer is down on the touchscreen, add the pointer id in the corresponding
- // entry in the unreleased touches map.
- auto touchesOnFd = unreleasedTouches.find(fd);
- if (touchesOnFd == unreleasedTouches.end()) {
- // Only sends the BTN Down event when the first pointer on the touchscreen is down.
- if (!writeInputEvent(fd, EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS))) {
- return false;
- }
- touchesOnFd = unreleasedTouches.insert({fd, {}}).first;
- ALOGD_IF(isDebug(), "New touchscreen with fd %d added in the unreleased touches map.", fd);
- }
- if (touchesOnFd->second.test(pointerId)) {
- ALOGE("Repetitive action DOWN event received on a pointer %d that is already down.",
- pointerId);
- return false;
- }
- touchesOnFd->second.set(pointerId);
- ALOGD_IF(isDebug(), "Added pointer %d under touchscreen %d in the map", pointerId, fd);
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(pointerId))) {
- return false;
- }
- return true;
-}
-
-static bool nativeWriteTouchEvent(JNIEnv* env, jobject thiz, jint fd, jint pointerId, jint toolType,
- jint action, jfloat locationX, jfloat locationY, jfloat pressure,
- jfloat majorAxisSize) {
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_SLOT, pointerId)) {
- return false;
- }
- auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
- if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
- return false;
- }
- if (toolType != -1) {
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_TOOL_TYPE,
- static_cast<int32_t>(toolTypeIterator->second))) {
- return false;
- }
- }
- auto actionIterator = TOUCH_ACTION_MAPPING.find(action);
- if (actionIterator == TOUCH_ACTION_MAPPING.end()) {
- return false;
- }
- UinputAction uinputAction = actionIterator->second;
- if (uinputAction == UinputAction::PRESS && !handleTouchDown(fd, pointerId)) {
- return false;
- } else if (uinputAction == UinputAction::RELEASE && !handleTouchUp(fd, pointerId)) {
- return false;
- }
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_POSITION_X, locationX)) {
- return false;
- }
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_POSITION_Y, locationY)) {
- return false;
- }
- if (!isnan(pressure)) {
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_PRESSURE, pressure)) {
- return false;
- }
- }
- if (!isnan(majorAxisSize)) {
- if (!writeInputEvent(fd, EV_ABS, ABS_MT_TOUCH_MAJOR, majorAxisSize)) {
- return false;
- }
- }
- return writeInputEvent(fd, EV_SYN, SYN_REPORT, 0);
-}
-
-static bool nativeWriteRelativeEvent(JNIEnv* env, jobject thiz, jint fd, jfloat relativeX,
+static bool nativeWriteRelativeEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat relativeX,
jfloat relativeY) {
- return writeInputEvent(fd, EV_REL, REL_X, relativeX) &&
- writeInputEvent(fd, EV_REL, REL_Y, relativeY) &&
- writeInputEvent(fd, EV_SYN, SYN_REPORT, 0);
+ VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
+ return virtualMouse->writeRelativeEvent(relativeX, relativeY);
}
-static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jint fd, jfloat xAxisMovement,
+static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat xAxisMovement,
jfloat yAxisMovement) {
- return writeInputEvent(fd, EV_REL, REL_HWHEEL, xAxisMovement) &&
- writeInputEvent(fd, EV_REL, REL_WHEEL, yAxisMovement) &&
- writeInputEvent(fd, EV_SYN, SYN_REPORT, 0);
+ VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
+ return virtualMouse->writeScrollEvent(xAxisMovement, yAxisMovement);
}
static JNINativeMethod methods[] = {
- {"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)I",
+ {"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)J",
(void*)nativeOpenUinputDpad},
- {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)I",
+ {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)J",
(void*)nativeOpenUinputKeyboard},
- {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)I",
+ {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)J",
(void*)nativeOpenUinputMouse},
- {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)I",
+ {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)J",
(void*)nativeOpenUinputTouchscreen},
- {"nativeCloseUinput", "(I)Z", (void*)nativeCloseUinput},
- {"nativeWriteDpadKeyEvent", "(III)Z", (void*)nativeWriteDpadKeyEvent},
- {"nativeWriteKeyEvent", "(III)Z", (void*)nativeWriteKeyEvent},
- {"nativeWriteButtonEvent", "(III)Z", (void*)nativeWriteButtonEvent},
- {"nativeWriteTouchEvent", "(IIIIFFFF)Z", (void*)nativeWriteTouchEvent},
- {"nativeWriteRelativeEvent", "(IFF)Z", (void*)nativeWriteRelativeEvent},
- {"nativeWriteScrollEvent", "(IFF)Z", (void*)nativeWriteScrollEvent},
+ {"nativeCloseUinput", "(J)V", (void*)nativeCloseUinput},
+ {"nativeWriteDpadKeyEvent", "(JII)Z", (void*)nativeWriteDpadKeyEvent},
+ {"nativeWriteKeyEvent", "(JII)Z", (void*)nativeWriteKeyEvent},
+ {"nativeWriteButtonEvent", "(JII)Z", (void*)nativeWriteButtonEvent},
+ {"nativeWriteTouchEvent", "(JIIIFFFF)Z", (void*)nativeWriteTouchEvent},
+ {"nativeWriteRelativeEvent", "(JFF)Z", (void*)nativeWriteRelativeEvent},
+ {"nativeWriteScrollEvent", "(JFF)Z", (void*)nativeWriteScrollEvent},
};
int register_android_server_companion_virtual_InputController(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index e16b0f7..c42a457 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -71,6 +71,10 @@
import java.util.stream.Collectors;
class ActiveAdmin {
+
+ private final int userId;
+ public final boolean isPermissionBased;
+
private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin";
private static final String TAG_DISABLE_CAMERA = "disable-camera";
@@ -356,8 +360,20 @@
String mSmsPackage;
ActiveAdmin(DeviceAdminInfo info, boolean isParent) {
+ this.userId = -1;
this.info = info;
this.isParent = isParent;
+ this.isPermissionBased = false;
+ }
+
+ ActiveAdmin(int userId, boolean permissionBased) {
+ if (permissionBased == false) {
+ throw new IllegalArgumentException("Can only pass true for permissionBased admin");
+ }
+ this.userId = userId;
+ this.isPermissionBased = permissionBased;
+ this.isParent = false;
+ this.info = null;
}
ActiveAdmin getParentActiveAdmin() {
@@ -374,10 +390,16 @@
}
int getUid() {
+ if (isPermissionBased) {
+ return -1;
+ }
return info.getActivityInfo().applicationInfo.uid;
}
public UserHandle getUserHandle() {
+ if (isPermissionBased) {
+ return UserHandle.of(userId);
+ }
return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index a5b9d43..6d51bd7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -133,9 +133,9 @@
// Create or get the permission-based admin. The permission-based admin will not have a
// DeviceAdminInfo or ComponentName.
- ActiveAdmin createOrGetPermissionBasedAdmin() {
+ ActiveAdmin createOrGetPermissionBasedAdmin(int userId) {
if (mPermissionBasedAdmin == null) {
- mPermissionBasedAdmin = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+ mPermissionBasedAdmin = new ActiveAdmin(userId, /* permissionBased= */ true);
}
return mPermissionBasedAdmin;
}
@@ -509,7 +509,7 @@
Slogf.w(TAG, e, "Failed loading admin %s", name);
}
} else if ("permission-based-admin".equals(tag)) {
- ActiveAdmin ap = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+ ActiveAdmin ap = new ActiveAdmin(policy.mUserId, /* permissionBased= */ true);
ap.readFromXml(parser, /* overwritePolicies= */ false);
policy.mPermissionBasedAdmin = ap;
} else if ("delegation".equals(tag)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 821a5f6..34094e4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3616,7 +3616,7 @@
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
- if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
+ if ((admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD))
&& admin.passwordExpirationTimeout > 0L
&& now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
&& admin.passwordExpirationDate > 0L) {
@@ -4296,15 +4296,26 @@
}
}
+ @GuardedBy("getLockObject()")
private List<ActiveAdmin> getActiveAdminsForLockscreenPoliciesLocked(int userHandle) {
if (isSeparateProfileChallengeEnabled(userHandle)) {
+
+ if (isPermissionCheckFlagEnabled()) {
+ return getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(userHandle);
+ }
// If this user has a separate challenge, only return its restrictions.
return getUserDataUnchecked(userHandle).mAdminList;
}
// If isSeparateProfileChallengeEnabled is false and userHandle points to a managed profile
// we need to query the parent user who owns the credential.
- return getActiveAdminsForUserAndItsManagedProfilesLocked(getProfileParentId(userHandle),
- (user) -> !mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id));
+ if (isPermissionCheckFlagEnabled()) {
+ return getActiveAdminsForUserAndItsManagedProfilesInclPermissionBasedAdminLocked(getProfileParentId(userHandle),
+ (user) -> !mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id));
+ } else {
+ return getActiveAdminsForUserAndItsManagedProfilesLocked(getProfileParentId(userHandle),
+ (user) -> !mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id));
+ }
+
}
/**
@@ -4340,7 +4351,14 @@
@GuardedBy("getLockObject()")
private List<ActiveAdmin> getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
int userHandle) {
- List<ActiveAdmin> list = getActiveAdminsForAffectedUserLocked(userHandle);
+ List<ActiveAdmin> list;
+
+ if (isManagedProfile(userHandle)) {
+ list = getUserDataUnchecked(userHandle).mAdminList;
+ }
+ list = getActiveAdminsForUserAndItsManagedProfilesInclPermissionBasedAdminLocked(userHandle,
+ /* shouldIncludeProfileAdmins */ (user) -> false);
+
if (getUserData(userHandle).mPermissionBasedAdmin != null) {
list.add(getUserData(userHandle).mPermissionBasedAdmin);
}
@@ -4378,6 +4396,44 @@
return admins;
}
+ /**
+ * Returns the list of admins on the given user, as well as parent admins for each managed
+ * profile associated with the given user. Optionally also include the admin of each managed
+ * profile.
+ * <p> Should not be called on a profile user.
+ */
+ @GuardedBy("getLockObject()")
+ private List<ActiveAdmin> getActiveAdminsForUserAndItsManagedProfilesInclPermissionBasedAdminLocked(int userHandle,
+ Predicate<UserInfo> shouldIncludeProfileAdmins) {
+ ArrayList<ActiveAdmin> admins = new ArrayList<>();
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+ DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
+ if (userInfo.id == userHandle) {
+ admins.addAll(policy.mAdminList);
+ if (policy.mPermissionBasedAdmin != null) {
+ admins.add(policy.mPermissionBasedAdmin);
+ }
+ } else if (userInfo.isManagedProfile()) {
+ for (int i = 0; i < policy.mAdminList.size(); i++) {
+ ActiveAdmin admin = policy.mAdminList.get(i);
+ if (admin.hasParentActiveAdmin()) {
+ admins.add(admin.getParentActiveAdmin());
+ }
+ if (shouldIncludeProfileAdmins.test(userInfo)) {
+ admins.add(admin);
+ }
+ }
+ if (policy.mPermissionBasedAdmin != null
+ && shouldIncludeProfileAdmins.test(userInfo)) {
+ admins.add(policy.mPermissionBasedAdmin);
+ }
+ }
+ }
+ });
+ return admins;
+ }
+
private boolean isSeparateProfileChallengeEnabled(int userHandle) {
return mInjector.binderWithCleanCallingIdentity(() ->
mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle));
@@ -4697,6 +4753,7 @@
* Return a single admin's expiration date/time, or the min (soonest) for all admins.
* Returns 0 if not configured.
*/
+ @GuardedBy("getLockObject()")
private long getPasswordExpirationLocked(ComponentName who, int userHandle, boolean parent) {
long timeout = 0L;
@@ -5282,11 +5339,12 @@
adminPackageName, userId, affectedUserId, complexity);
}
}
-
+ @GuardedBy("getLockObject()")
private int getAggregatedPasswordComplexityLocked(@UserIdInt int userHandle) {
return getAggregatedPasswordComplexityLocked(userHandle, false);
}
+ @GuardedBy("getLockObject()")
private int getAggregatedPasswordComplexityLocked(@UserIdInt int userHandle,
boolean deviceWideOnly) {
ensureLocked();
@@ -5469,6 +5527,7 @@
* profile.
* Returns {@code null} if no participating admin has that policy set.
*/
+ @GuardedBy("getLockObject()")
private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(
int userHandle, boolean parent) {
int count = 0;
@@ -5699,6 +5758,7 @@
}
}
+ @GuardedBy("getLockObject()")
private void updateMaximumTimeToLockLocked(@UserIdInt int userId) {
// Update the profile's timeout
if (isManagedProfile(userId)) {
@@ -5727,6 +5787,7 @@
});
}
+ @GuardedBy("getLockObject()")
private void updateProfileLockTimeoutLocked(@UserIdInt int userId) {
final long timeMs;
if (isSeparateProfileChallengeEnabled(userId)) {
@@ -7459,9 +7520,15 @@
final String adminName;
final ComponentName adminComp;
if (admin != null) {
- adminComp = admin.info.getComponent();
- adminName = adminComp.flattenToShortString();
- event.setAdmin(adminComp);
+ if (admin.isPermissionBased) {
+ adminComp = null;
+ adminName = caller.getPackageName();
+ event.setAdmin(adminName);
+ } else {
+ adminComp = admin.info.getComponent();
+ adminName = adminComp.flattenToShortString();
+ event.setAdmin(adminComp);
+ }
} else {
adminComp = null;
adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
@@ -7750,13 +7817,7 @@
|| hasCallingPermission(permission.MASTER_CLEAR)
|| hasCallingPermission(MANAGE_DEVICE_POLICY_FACTORY_RESET),
"Must be called by the FRP management agent on device");
- // TODO(b/261999445): Remove
- if (isHeadlessFlagEnabled()) {
- admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
- } else {
- admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
- UserHandle.getUserId(frpManagementAgentUid));
- }
+ admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceOrSystemPermissionBasedAdminLocked();
} else {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
@@ -7927,12 +7988,13 @@
*
* @return the set of user IDs that have been affected
*/
+ @GuardedBy("getLockObject()")
private Set<Integer> updatePasswordExpirationsLocked(int userHandle) {
final ArraySet<Integer> affectedUserIds = new ArraySet<>();
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
for (int i = 0; i < admins.size(); i++) {
ActiveAdmin admin = admins.get(i);
- if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+ if (admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
affectedUserIds.add(admin.getUserHandle().getIdentifier());
long timeout = admin.passwordExpirationTimeout;
admin.passwordExpirationDate =
@@ -8026,6 +8088,9 @@
*/
private int getUserIdToWipeForFailedPasswords(ActiveAdmin admin) {
final int userId = admin.getUserHandle().getIdentifier();
+ if (admin.isPermissionBased) {
+ return userId;
+ }
final ComponentName component = admin.info.getComponent();
return isProfileOwnerOfOrganizationOwnedDevice(component, userId)
? getProfileParentId(userId) : userId;
@@ -9653,6 +9718,15 @@
return admin;
}
+ ActiveAdmin getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceOrSystemPermissionBasedAdminLocked() {
+ ensureLocked();
+ ActiveAdmin doOrPo = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
+ if (isPermissionCheckFlagEnabled() && doOrPo == null) {
+ return getUserData(0).mPermissionBasedAdmin;
+ }
+ return doOrPo;
+ }
+
ActiveAdmin getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceParentLocked(int userId) {
ensureLocked();
ActiveAdmin admin = getDeviceOwnerAdminLocked();
@@ -10659,9 +10733,12 @@
return false;
}
- final ComponentName profileOwner = getProfileOwnerAsUser(userId);
- if (profileOwner == null) {
- return false;
+ if (!isPermissionCheckFlagEnabled()) {
+ // TODO: Figure out if something like this needs to be restored for policy engine
+ final ComponentName profileOwner = getProfileOwnerAsUser(userId);
+ if (profileOwner == null) {
+ return false;
+ }
}
// Managed profiles are not allowed to use lock task
@@ -11884,7 +11961,7 @@
synchronized (getLockObject()) {
List<String> result = null;
// Only device or profile owners can have permitted lists set.
- List<ActiveAdmin> admins = getActiveAdminsForAffectedUserLocked(userId);
+ List<ActiveAdmin> admins = getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(userId);
for (ActiveAdmin admin: admins) {
List<String> fromAdmin = admin.permittedInputMethods;
if (fromAdmin != null) {
@@ -13623,7 +13700,6 @@
new BooleanPolicyValue(uninstallBlocked),
caller.getUserId());
} else {
- Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
|| isFinancedDeviceOwner(caller)))
@@ -14265,7 +14341,7 @@
final int userId = mInjector.userHandleGetCallingUserId();
// Is it ok to just check that no active policies exist currently?
- if (mDevicePolicyEngine.hasActivePolicies()) {
+ if (isDevicePolicyEngineFlagEnabled() && mDevicePolicyEngine.hasActivePolicies()) {
LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.LOCK_TASK, userId);
if (policy == null) {
@@ -15814,7 +15890,7 @@
if (admin.mPasswordPolicy.quality < minPasswordQuality) {
return false;
}
- return admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ return admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
}
@Override
@@ -21451,13 +21527,7 @@
}
synchronized (getLockObject()) {
ActiveAdmin admin;
- // TODO(b/261999445): remove
- if (isHeadlessFlagEnabled()) {
- admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
- } else {
- admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
- UserHandle.USER_SYSTEM);
- }
+ admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceOrSystemPermissionBasedAdminLocked();
return admin != null ? admin.mWifiSsidPolicy : null;
}
}
@@ -22454,7 +22524,7 @@
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
if (admin == null) {
- admin = getUserData(userId).createOrGetPermissionBasedAdmin();
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
}
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
@@ -23014,26 +23084,12 @@
return admins;
}
- // TODO: This can actually accept an EnforcingAdmin that gets created in the permission check
- // method.
private boolean useDevicePolicyEngine(CallerIdentity caller, @Nullable String delegateScope) {
- if (!isCallerActiveAdminOrDelegate(caller, delegateScope)) {
- if (!isDevicePolicyEngineFlagEnabled()) {
- throw new IllegalStateException("Non DPC caller can't set device policies.");
- }
- if (hasDPCsNotSupportingCoexistence()) {
- throw new IllegalStateException("Non DPC caller can't set device policies with "
- + "existing legacy admins on the device.");
- }
- return true;
- } else {
- return isDevicePolicyEngineEnabled();
- }
+ return isDevicePolicyEngineEnabled();
}
private boolean isDevicePolicyEngineEnabled() {
- return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence()
- && isPermissionCheckFlagEnabled();
+ return isDevicePolicyEngineFlagEnabled() && isPermissionCheckFlagEnabled();
}
private boolean isDevicePolicyEngineFlagEnabled() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 68cfe45..dcdee37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -16,6 +16,10 @@
package com.android.server.am;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD;
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_ALARM;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_FOREGROUND;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_INTERACTIVE;
@@ -44,8 +48,12 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import android.annotation.NonNull;
import android.app.Activity;
@@ -70,6 +78,11 @@
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.ExtendedMockitoTestCase;
+import com.android.server.am.BroadcastQueueTest.SyncBarrier;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -86,7 +99,7 @@
@SmallTest
@RunWith(MockitoJUnitRunner.class)
-public class BroadcastQueueModernImplTest {
+public class BroadcastQueueModernImplTest extends ExtendedMockitoTestCase {
private static final int TEST_UID = android.os.Process.FIRST_APPLICATION_UID;
private static final int TEST_UID2 = android.os.Process.FIRST_APPLICATION_UID + 1;
@@ -105,6 +118,11 @@
BroadcastProcessQueue mHead;
+ @Override
+ protected void initializeSession(StaticMockitoSessionBuilder builder) {
+ builder.spyStatic(FrameworkStatsLog.class);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -1081,6 +1099,28 @@
}
}
+ @Test
+ public void testBroadcastDeliveryEventReported() throws Exception {
+ final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
+ final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic();
+ optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
+
+ // Halt all processing so that we get a consistent view
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
+ mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
+ mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
+ }
+ mImpl.waitForIdle(null);
+
+ // Verify that there is only one delivery event reported since one of the broadcasts
+ // should have been skipped.
+ verify(() -> FrameworkStatsLog.write(eq(BROADCAST_DELIVERY_EVENT_REPORTED),
+ eq(getUidForPackage(PACKAGE_GREEN)), anyInt(), eq(Intent.ACTION_TIME_TICK),
+ eq(BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST),
+ eq(BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD),
+ anyLong(), anyLong(), anyLong(), anyInt()), times(1));
+ }
+
private Intent createPackageChangedIntent(int uid, List<String> componentNameList) {
final Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
packageChangedIntent.putExtra(Intent.EXTRA_UID, uid);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index e7b3dd9..f3c2012 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -346,16 +346,18 @@
* Helper that leverages try-with-resources to pause dispatch of
* {@link #mHandlerThread} until released.
*/
- private class SyncBarrier implements AutoCloseable {
+ static class SyncBarrier implements AutoCloseable {
private final int mToken;
+ private HandlerThread mThread;
- public SyncBarrier() {
- mToken = mHandlerThread.getLooper().getQueue().postSyncBarrier();
+ SyncBarrier(HandlerThread thread) {
+ mThread = thread;
+ mToken = mThread.getLooper().getQueue().postSyncBarrier();
}
@Override
public void close() throws Exception {
- mHandlerThread.getLooper().getQueue().removeSyncBarrier(mToken);
+ mThread.getLooper().getQueue().removeSyncBarrier(mToken);
}
}
@@ -1120,7 +1122,7 @@
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, new ArrayList<>(
List.of(makeRegisteredReceiver(receiverApp),
makeManifestReceiver(PACKAGE_GREEN, CLASS_RED),
@@ -1164,7 +1166,7 @@
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final Intent timeZone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, USER_GUEST, new ArrayList<>(
List.of(makeRegisteredReceiver(callerApp),
makeManifestReceiver(PACKAGE_GREEN, CLASS_RED, USER_GUEST),
@@ -1204,7 +1206,7 @@
final ProcessRecord oldApp = makeActiveProcessRecord(PACKAGE_GREEN);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, new ArrayList<>(
List.of(makeRegisteredReceiver(oldApp),
makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)))));
@@ -1585,7 +1587,7 @@
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
enqueueBroadcast(makeBroadcastRecord(timezone, callerApp,
List.of(makeRegisteredReceiver(receiverBlueApp, 10),
makeRegisteredReceiver(receiverGreenApp, 10),
@@ -1638,7 +1640,7 @@
final IIntentReceiver resultToFirst = mock(IIntentReceiver.class);
final IIntentReceiver resultToSecond = mock(IIntentReceiver.class);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
enqueueBroadcast(makeOrderedBroadcastRecord(timezoneFirst, callerApp,
List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE),
makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)),
@@ -1729,7 +1731,7 @@
timeTickFirst.putExtra(Intent.EXTRA_INDEX, "third");
timeTickThird.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
enqueueBroadcast(makeBroadcastRecord(timeTickFirst, callerApp,
List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
enqueueBroadcast(makeBroadcastRecord(timeTickSecond, callerApp,
@@ -1771,7 +1773,7 @@
assertTrue(mQueue.isIdleLocked());
assertTrue(mQueue.isBeyondBarrierLocked(beforeFirst));
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
enqueueBroadcast(makeBroadcastRecord(timezone, callerApp,
List.of(makeRegisteredReceiver(receiverApp))));
@@ -1865,7 +1867,7 @@
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- try (SyncBarrier b = new SyncBarrier()) {
+ try (SyncBarrier b = new SyncBarrier(mHandlerThread)) {
final Object greenReceiver = makeRegisteredReceiver(receiverGreenApp);
final Object blueReceiver = makeRegisteredReceiver(receiverBlueApp);
final Object yellowReceiver = makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index dc7f3cd..485ce33 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -143,8 +143,8 @@
private static final String MOCKAPP5_PROCESSNAME = "test #5";
private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
- private static final int FIRST_CACHED_ADJ = ProcessList.CACHED_APP_MIN_ADJ
- + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+ private static int sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ
+ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
private static Context sContext;
private static PackageManagerInternal sPackageManagerInternal;
private static ActivityManagerService sService;
@@ -208,6 +208,9 @@
new ActiveUids(sService, false));
sService.mOomAdjuster.mAdjSeq = 10000;
sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ if (sService.mConstants.USE_TIERED_CACHED_ADJ) {
+ sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ + 10;
+ }
}
@AfterClass
@@ -834,7 +837,7 @@
updateOomAdj(client, app);
doReturn(null).when(sService).getTopApp();
- assertProcStates(app, PROCESS_STATE_SERVICE, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
+ assertProcStates(app, PROCESS_STATE_SERVICE, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
}
@SuppressWarnings("GuardedBy")
@@ -882,7 +885,7 @@
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
+ assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
}
@SuppressWarnings("GuardedBy")
@@ -1286,7 +1289,7 @@
bindProvider(app, app, null, null, false);
updateOomAdj(app);
- assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
+ assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
}
@SuppressWarnings("GuardedBy")
@@ -1301,7 +1304,7 @@
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client);
- assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FIRST_CACHED_ADJ, SCHED_GROUP_BACKGROUND);
+ assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
}
@SuppressWarnings("GuardedBy")
@@ -2378,8 +2381,12 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
final int userOwner = 0;
final int userOther = 1;
- final int cachedAdj1 = CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+ final int cachedAdj1 = sService.mConstants.USE_TIERED_CACHED_ADJ
+ ? CACHED_APP_MIN_ADJ + 10
+ : CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+ final int cachedAdj2 = sService.mConstants.USE_TIERED_CACHED_ADJ
+ ? CACHED_APP_MIN_ADJ + 10
+ : cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 6e63315..10cfe86 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -26,12 +26,15 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
@@ -44,7 +47,9 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.provider.Settings;
import android.util.FloatProperty;
import android.view.Display;
import android.view.DisplayInfo;
@@ -57,6 +62,7 @@
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.RampAnimator.DualRampAnimator;
+import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
import com.android.server.policy.WindowManagerPolicy;
@@ -122,6 +128,7 @@
.spyStatic(SystemProperties.class)
.spyStatic(LocalServices.class)
.spyStatic(BatteryStatsService.class)
+ .spyStatic(Settings.System.class)
.startMocking();
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
mClock = new OffsettableClock.Stopped();
@@ -139,8 +146,7 @@
ColorDisplayService.ColorDisplayServiceInternal.class));
doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService);
- mProxSensor = setUpProxSensor();
-
+ setUpSensors();
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
}
@@ -169,7 +175,7 @@
advanceTime(1);
// two times, one for unfinished business and one for proximity
- verify(mHolder.wakelockController).acquireWakelock(
+ verify(mHolder.wakelockController, times(2)).acquireWakelock(
WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
verify(mHolder.wakelockController).acquireWakelock(
WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
@@ -177,7 +183,7 @@
mHolder.dpc.stop();
advanceTime(1);
// two times, one for unfinished business and one for proximity
- verify(mHolder.wakelockController).acquireWakelock(
+ verify(mHolder.wakelockController, times(2)).acquireWakelock(
WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
verify(mHolder.wakelockController).acquireWakelock(
WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
@@ -214,12 +220,13 @@
mTestLooper.dispatchAll();
}
- private Sensor setUpProxSensor() throws Exception {
- Sensor proxSensor = TestUtils.createSensor(
+ private void setUpSensors() throws Exception {
+ mProxSensor = TestUtils.createSensor(
Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY);
+ Sensor screenOffBrightnessSensor = TestUtils.createSensor(
+ Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
- .thenReturn(List.of(proxSensor));
- return proxSensor;
+ .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor));
}
private SensorEventListener getSensorEventListener(Sensor sensor) {
@@ -229,14 +236,15 @@
}
private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
- DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock) {
+ DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
+ boolean isEnabled) {
DisplayInfo info = new DisplayInfo();
DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
- when(logicalDisplayMock.isEnabledLocked()).thenReturn(true);
+ when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
@@ -253,7 +261,14 @@
when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn(
new DisplayDeviceConfig.SensorData());
when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn(
- new DisplayDeviceConfig.SensorData());
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = Sensor.STRING_TYPE_LIGHT;
+ name = null;
+ }
+ });
+ when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
+ .thenReturn(new int[0]);
}
@Test
@@ -460,8 +475,164 @@
verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
}
+ @Test
+ public void testDoesNotSetScreenStateForNonDefaultDisplayUntilBootCompleted() {
+ // We should still set screen state for the default display
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1);
+ verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt());
+
+ mHolder = createDisplayPowerController(42, UNIQUE_ID);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1);
+ verify(mHolder.displayPowerState, never()).setScreenState(anyInt());
+
+ mHolder.dpc.onBootCompleted();
+ advanceTime(1);
+ verify(mHolder.displayPowerState).setScreenState(anyInt());
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(true);
+
+ // The display turns on and we use the brightness value recommended by
+ // ScreenOffBrightnessSensorController
+ clearInvocations(mHolder.screenOffBrightnessSensorController);
+ float brightness = 0.14f;
+ when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness())
+ .thenReturn(brightness);
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .getAutomaticScreenBrightness();
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ when(mResourcesMock.getBoolean(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing))
+ .thenReturn(true);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(true);
+
+ // The display turns on and we use the brightness value recommended by
+ // ScreenOffBrightnessSensorController
+ clearInvocations(mHolder.screenOffBrightnessSensorController);
+ float brightness = 0.14f;
+ when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness())
+ .thenReturn(brightness);
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .getAutomaticScreenBrightness();
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_DisplayIsOn() {
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_DisplayIsAFollower() {
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+
+ mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, /* leadDisplayId= */ 42);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
String uniqueId) {
+ return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true);
+ }
+
+ private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
+ String uniqueId, boolean isEnabled) {
final DisplayPowerState displayPowerState = mock(DisplayPowerState.class);
final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class);
final AutomaticBrightnessController automaticBrightnessController =
@@ -470,10 +641,12 @@
final BrightnessMappingStrategy brightnessMappingStrategy =
mock(BrightnessMappingStrategy.class);
final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class);
+ final ScreenOffBrightnessSensorController screenOffBrightnessSensorController =
+ mock(ScreenOffBrightnessSensorController.class);
TestInjector injector = new TestInjector(displayPowerState, animator,
automaticBrightnessController, wakelockController, brightnessMappingStrategy,
- hysteresisLevels);
+ hysteresisLevels, screenOffBrightnessSensorController);
final LogicalDisplay display = mock(LogicalDisplay.class);
final DisplayDevice device = mock(DisplayDevice.class);
@@ -481,16 +654,17 @@
final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class);
final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class);
- setUpDisplay(displayId, uniqueId, display, device, config);
+ setUpDisplay(displayId, uniqueId, display, device, config, isEnabled);
final DisplayPowerController2 dpc = new DisplayPowerController2(
mContextSpy, injector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, display,
mBrightnessTrackerMock, brightnessSetting, () -> {},
- hbmMetadata);
+ hbmMetadata, false);
return new DisplayPowerControllerHolder(dpc, displayPowerState, brightnessSetting, animator,
- automaticBrightnessController, wakelockController);
+ automaticBrightnessController, wakelockController,
+ screenOffBrightnessSensorController, hbmMetadata);
}
/**
@@ -504,18 +678,24 @@
public final DualRampAnimator<DisplayPowerState> animator;
public final AutomaticBrightnessController automaticBrightnessController;
public final WakelockController wakelockController;
+ public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController;
+ public final HighBrightnessModeMetadata hbmMetadata;
DisplayPowerControllerHolder(DisplayPowerController2 dpc,
DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting,
DualRampAnimator<DisplayPowerState> animator,
AutomaticBrightnessController automaticBrightnessController,
- WakelockController wakelockController) {
+ WakelockController wakelockController,
+ ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
+ HighBrightnessModeMetadata hbmMetadata) {
this.dpc = dpc;
this.displayPowerState = displayPowerState;
this.brightnessSetting = brightnessSetting;
this.animator = animator;
this.automaticBrightnessController = automaticBrightnessController;
this.wakelockController = wakelockController;
+ this.screenOffBrightnessSensorController = screenOffBrightnessSensorController;
+ this.hbmMetadata = hbmMetadata;
}
}
@@ -526,18 +706,21 @@
private final WakelockController mWakelockController;
private final BrightnessMappingStrategy mBrightnessMappingStrategy;
private final HysteresisLevels mHysteresisLevels;
+ private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController;
TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator,
AutomaticBrightnessController automaticBrightnessController,
WakelockController wakelockController,
BrightnessMappingStrategy brightnessMappingStrategy,
- HysteresisLevels hysteresisLevels) {
+ HysteresisLevels hysteresisLevels,
+ ScreenOffBrightnessSensorController screenOffBrightnessSensorController) {
mDisplayPowerState = dps;
mAnimator = animator;
mAutomaticBrightnessController = automaticBrightnessController;
mWakelockController = wakelockController;
mBrightnessMappingStrategy = brightnessMappingStrategy;
mHysteresisLevels = hysteresisLevels;
+ mScreenOffBrightnessSensorController = screenOffBrightnessSensorController;
}
@Override
@@ -617,5 +800,13 @@
float minBrighteningThreshold, boolean potentialOldBrightnessRange) {
return mHysteresisLevels;
}
+
+ @Override
+ ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController(
+ SensorManager sensorManager, Sensor lightSensor, Handler handler,
+ ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux,
+ BrightnessMappingStrategy brightnessMapper) {
+ return mScreenOffBrightnessSensorController;
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index a8c3e4e..ebeef2e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -26,12 +26,15 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
@@ -44,7 +47,9 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.provider.Settings;
import android.util.FloatProperty;
import android.view.Display;
import android.view.DisplayInfo;
@@ -57,6 +62,7 @@
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.RampAnimator.DualRampAnimator;
+import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
import com.android.server.policy.WindowManagerPolicy;
@@ -122,6 +128,7 @@
.spyStatic(SystemProperties.class)
.spyStatic(LocalServices.class)
.spyStatic(BatteryStatsService.class)
+ .spyStatic(Settings.System.class)
.startMocking();
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
mClock = new OffsettableClock.Stopped();
@@ -140,8 +147,7 @@
ColorDisplayService.ColorDisplayServiceInternal.class));
doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService);
- mProxSensor = setUpProxSensor();
-
+ setUpSensors();
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
}
@@ -217,12 +223,13 @@
mTestLooper.dispatchAll();
}
- private Sensor setUpProxSensor() throws Exception {
- Sensor proxSensor = TestUtils.createSensor(
+ private void setUpSensors() throws Exception {
+ mProxSensor = TestUtils.createSensor(
Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY);
+ Sensor screenOffBrightnessSensor = TestUtils.createSensor(
+ Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
- .thenReturn(List.of(proxSensor));
- return proxSensor;
+ .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor));
}
private SensorEventListener getSensorEventListener(Sensor sensor) {
@@ -232,14 +239,15 @@
}
private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
- DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock) {
+ DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
+ boolean isEnabled) {
DisplayInfo info = new DisplayInfo();
DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
- when(logicalDisplayMock.isEnabledLocked()).thenReturn(true);
+ when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
@@ -256,7 +264,14 @@
when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn(
new DisplayDeviceConfig.SensorData());
when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn(
- new DisplayDeviceConfig.SensorData());
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = Sensor.STRING_TYPE_LIGHT;
+ name = null;
+ }
+ });
+ when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
+ .thenReturn(new int[0]);
}
@Test
@@ -464,8 +479,164 @@
verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
}
+ @Test
+ public void testDoesNotSetScreenStateForNonDefaultDisplayUntilBootCompleted() {
+ // We should still set screen state for the default display
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1);
+ verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt());
+
+ mHolder = createDisplayPowerController(42, UNIQUE_ID);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1);
+ verify(mHolder.displayPowerState, never()).setScreenState(anyInt());
+
+ mHolder.dpc.onBootCompleted();
+ advanceTime(1);
+ verify(mHolder.displayPowerState).setScreenState(anyInt());
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(true);
+
+ // The display turns on and we use the brightness value recommended by
+ // ScreenOffBrightnessSensorController
+ clearInvocations(mHolder.screenOffBrightnessSensorController);
+ float brightness = 0.14f;
+ when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness())
+ .thenReturn(brightness);
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .getAutomaticScreenBrightness();
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ when(mResourcesMock.getBoolean(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing))
+ .thenReturn(true);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(true);
+
+ // The display turns on and we use the brightness value recommended by
+ // ScreenOffBrightnessSensorController
+ clearInvocations(mHolder.screenOffBrightnessSensorController);
+ float brightness = 0.14f;
+ when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness())
+ .thenReturn(brightness);
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .getAutomaticScreenBrightness();
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_DisplayIsOn() {
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
+ @Test
+ public void testSetScreenOffBrightnessSensorDisabled_DisplayIsAFollower() {
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+
+ mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, /* leadDisplayId= */ 42);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.screenOffBrightnessSensorController, atLeastOnce())
+ .setLightSensorEnabled(false);
+ }
+
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
String uniqueId) {
+ return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true);
+ }
+
+ private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
+ String uniqueId, boolean isEnabled) {
final DisplayPowerState displayPowerState = mock(DisplayPowerState.class);
final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class);
final AutomaticBrightnessController automaticBrightnessController =
@@ -473,9 +644,12 @@
final BrightnessMappingStrategy brightnessMappingStrategy =
mock(BrightnessMappingStrategy.class);
final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class);
+ final ScreenOffBrightnessSensorController screenOffBrightnessSensorController =
+ mock(ScreenOffBrightnessSensorController.class);
DisplayPowerController.Injector injector = new TestInjector(displayPowerState, animator,
- automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels);
+ automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels,
+ screenOffBrightnessSensorController);
final LogicalDisplay display = mock(LogicalDisplay.class);
final DisplayDevice device = mock(DisplayDevice.class);
@@ -483,16 +657,16 @@
final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class);
final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class);
- setUpDisplay(displayId, uniqueId, display, device, config);
+ setUpDisplay(displayId, uniqueId, display, device, config, isEnabled);
final DisplayPowerController dpc = new DisplayPowerController(
mContextSpy, injector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, display,
mBrightnessTrackerMock, brightnessSetting, () -> {},
- hbmMetadata);
+ hbmMetadata, false);
return new DisplayPowerControllerHolder(dpc, displayPowerState, brightnessSetting, animator,
- automaticBrightnessController);
+ automaticBrightnessController, screenOffBrightnessSensorController, hbmMetadata);
}
/**
@@ -505,16 +679,22 @@
public final BrightnessSetting brightnessSetting;
public final DualRampAnimator<DisplayPowerState> animator;
public final AutomaticBrightnessController automaticBrightnessController;
+ public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController;
+ public final HighBrightnessModeMetadata hbmMetadata;
DisplayPowerControllerHolder(DisplayPowerController dpc,
DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting,
DualRampAnimator<DisplayPowerState> animator,
- AutomaticBrightnessController automaticBrightnessController) {
+ AutomaticBrightnessController automaticBrightnessController,
+ ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
+ HighBrightnessModeMetadata hbmMetadata) {
this.dpc = dpc;
this.displayPowerState = displayPowerState;
this.brightnessSetting = brightnessSetting;
this.animator = animator;
this.automaticBrightnessController = automaticBrightnessController;
+ this.screenOffBrightnessSensorController = screenOffBrightnessSensorController;
+ this.hbmMetadata = hbmMetadata;
}
}
@@ -524,16 +704,19 @@
private final AutomaticBrightnessController mAutomaticBrightnessController;
private final BrightnessMappingStrategy mBrightnessMappingStrategy;
private final HysteresisLevels mHysteresisLevels;
+ private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController;
TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator,
AutomaticBrightnessController automaticBrightnessController,
BrightnessMappingStrategy brightnessMappingStrategy,
- HysteresisLevels hysteresisLevels) {
+ HysteresisLevels hysteresisLevels,
+ ScreenOffBrightnessSensorController screenOffBrightnessSensorController) {
mDisplayPowerState = dps;
mAnimator = animator;
mAutomaticBrightnessController = automaticBrightnessController;
mBrightnessMappingStrategy = brightnessMappingStrategy;
mHysteresisLevels = hysteresisLevels;
+ mScreenOffBrightnessSensorController = screenOffBrightnessSensorController;
}
@Override
@@ -597,5 +780,13 @@
float minBrighteningThreshold, boolean potentialOldBrightnessRange) {
return mHysteresisLevels;
}
+
+ @Override
+ ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController(
+ SensorManager sensorManager, Sensor lightSensor, Handler handler,
+ ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux,
+ BrightnessMappingStrategy brightnessMapper) {
+ return mScreenOffBrightnessSensorController;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 89a5b12..8994a48 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -133,6 +133,7 @@
private static final int TEST_USER_ID1 = 101;
private static final int TEST_USER_ID2 = 102;
private static final int TEST_USER_ID3 = 103;
+ private static final int SYSTEM_USER_ID = UserHandle.SYSTEM.getIdentifier();
private static final int NONEXIST_USER_ID = 2;
private static final int TEST_PRE_CREATED_USER_ID = 103;
@@ -231,6 +232,31 @@
}
@Test
+ public void testStartUser_sendsNoBroadcastsForSystemUserInNonHeadlessMode() {
+ setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
+ UserManager.USER_TYPE_FULL_SYSTEM);
+ mockIsHeadlessSystemUserMode(false);
+
+ mUserController.startUser(SYSTEM_USER_ID, USER_START_MODE_FOREGROUND);
+
+ assertWithMessage("Broadcasts for starting the system user in non-headless mode")
+ .that(mInjector.mSentIntents).isEmpty();
+ }
+
+ @Test
+ public void testStartUser_sendsBroadcastsForSystemUserInHeadlessMode() {
+ setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
+ UserManager.USER_TYPE_SYSTEM_HEADLESS);
+ mockIsHeadlessSystemUserMode(true);
+
+ mUserController.startUser(SYSTEM_USER_ID, USER_START_MODE_FOREGROUND);
+
+ assertWithMessage("Broadcasts for starting the system user in headless mode")
+ .that(getActions(mInjector.mSentIntents)).containsExactly(
+ Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING);
+ }
+
+ @Test
public void testStartUser_displayAssignmentFailed() {
doReturn(UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE)
.when(mInjector.mUserManagerInternalMock)
@@ -999,6 +1025,10 @@
}
}
+ private void mockIsHeadlessSystemUserMode(boolean value) {
+ when(mInjector.isHeadlessSystemUserMode()).thenReturn(value);
+ }
+
private void mockIsUsersOnSecondaryDisplaysEnabled(boolean value) {
when(mInjector.isUsersOnSecondaryDisplaysEnabled()).thenReturn(value);
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
index 51bd5b0f..3cc6b01 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
@@ -79,7 +79,7 @@
InputManager.resetInstance(mIInputManagerMock);
}
- private Void handleNativeOpenInputDevice(InvocationOnMock inv) {
+ private long handleNativeOpenInputDevice(InvocationOnMock inv) {
Objects.requireNonNull(mDevicesChangedListener,
"InputController did not register an InputDevicesChangedListener.");
@@ -101,6 +101,7 @@
}
// Process the device added notification.
mTestableLooper.processAllMessages();
- return null;
+ // Return a placeholder pointer to the native input device.
+ return 1L;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
index 1001422..2f431bd 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.time.UnixEpochTime;
@@ -60,7 +61,28 @@
}
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_success() {
+ public void engineImpl_refreshAndRescheduleIfRequired_nullNetwork() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+ // Trigger the engine's logic.
+ engine.refreshAndRescheduleIfRequired(null, "Test", mockCallback);
+
+ // Expect nothing to have happened.
+ verifyNoMoreInteractions(mMockNtpTrustedTime);
+ verifyNoMoreInteractions(mockCallback);
+ }
+
+ @Test
+ public void engineImpl_refreshAndRescheduleIfRequired_success() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -83,7 +105,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -98,7 +120,7 @@
}
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_failThenFailRepeatedly() {
+ public void engineImpl_refreshAndRescheduleIfRequired_failThenFailRepeatedly() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -120,7 +142,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect a refresh attempt each time: there's no currently cached result.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -141,7 +163,7 @@
}
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_successThenFailRepeatedly() {
+ public void engineImpl_refreshAndRescheduleIfRequired_successThenFailRepeatedly() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -168,7 +190,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made: there is no cached network time
// initially.
@@ -182,7 +204,7 @@
}
// Increment the current time by enough so that an attempt to refresh the time should be
- // made every time refreshIfRequiredAndReschedule() is called.
+ // made every time refreshAndRescheduleIfRequired() is called.
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
// Test multiple follow-up calls.
@@ -195,7 +217,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect a refresh attempt each time as the cached network time is too old.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -221,7 +243,7 @@
}
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_successThenFail_tryAgainTimesZero() {
+ public void engineImpl_refreshAndRescheduleIfRequired_successThenFail_tryAgainTimesZero() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -248,7 +270,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made: there is no cached network time
// initially.
@@ -262,7 +284,7 @@
}
// Increment the current time by enough so that an attempt to refresh the time should be
- // made every time refreshIfRequiredAndReschedule() is called.
+ // made every time refreshAndRescheduleIfRequired() is called.
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
// Test multiple follow-up calls.
@@ -275,7 +297,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect a refresh attempt each time as the cached network time is too old.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -297,7 +319,7 @@
}
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_successThenFail_tryAgainTimesNegative() {
+ public void engineImpl_refreshAndRescheduleIfRequired_successThenFail_tryAgainTimesNegative() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -324,7 +346,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made: there is no cached network time
// initially.
@@ -338,7 +360,7 @@
}
// Increment the current time by enough so that an attempt to refresh the time should be
- // made every time refreshIfRequiredAndReschedule() is called.
+ // made every time refreshAndRescheduleIfRequired() is called.
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
// Test multiple follow-up calls.
@@ -351,7 +373,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect a refresh attempt each time as the cached network time is too old.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -373,7 +395,7 @@
}
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_successFailSuccess() {
+ public void engineImpl_refreshAndRescheduleIfRequired_successFailSuccess() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -398,7 +420,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made: there is no cached network time
// initially.
@@ -413,7 +435,7 @@
}
// Increment the current time by enough so that the cached time result is too old and an
- // attempt to refresh the time should be made every time refreshIfRequiredAndReschedule() is
+ // attempt to refresh the time should be made every time refreshAndRescheduleIfRequired() is
// called.
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
@@ -426,7 +448,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made: the timeResult is too old.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -458,7 +480,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect the refresh attempt to have been made: the timeResult is too old.
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
@@ -473,12 +495,12 @@
}
/**
- * Confirms that if a refreshIfRequiredAndReschedule() call is made, e.g. for reasons besides
+ * Confirms that if a refreshAndRescheduleIfRequired() call is made, e.g. for reasons besides
* scheduled alerts, and the latest time is not too old, then an NTP refresh won't be attempted.
* A suggestion will still be made.
*/
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_noRefreshIfLatestIsFresh() {
+ public void engineImpl_refreshAndRescheduleIfRequired_noRefreshIfLatestIsFresh() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -498,7 +520,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect no refresh attempt to have been made.
verify(mMockNtpTrustedTime, never()).forceRefresh(any());
@@ -516,11 +538,11 @@
}
/**
- * Confirms that if a refreshIfRequiredAndReschedule() call is made, e.g. for reasons besides
+ * Confirms that if a refreshAndRescheduleIfRequired() call is made, e.g. for reasons besides
* scheduled alerts, and the latest time is too old, then an NTP refresh will be attempted.
*/
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_failureHandlingAfterLatestIsTooOld() {
+ public void engineImpl_refreshAndRescheduleIfRequired_failureHandlingAfterLatestIsTooOld() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -541,7 +563,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect a refresh attempt to have been made.
verify(mMockNtpTrustedTime, times(1)).forceRefresh(mDummyNetwork);
@@ -556,11 +578,11 @@
}
/**
- * Confirms that if a refreshIfRequiredAndReschedule() call is made and there was a recently
+ * Confirms that if a refreshAndRescheduleIfRequired() call is made and there was a recently
* failed refresh, then another won't be scheduled too soon.
*/
@Test
- public void engineImpl_refreshIfRequiredAndReschedule_minimumRefreshTimeEnforced() {
+ public void engineImpl_refreshAndRescheduleIfRequired_minimumRefreshTimeEnforced() {
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
int normalPollingIntervalMillis = 7777777;
@@ -574,7 +596,7 @@
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
- // Simulate an initial call to refreshIfRequiredAndReschedule() prime the "last refresh
+ // Simulate an initial call to refreshAndRescheduleIfRequired() prime the "last refresh
// attempt" time. A cached time value is available, but it's too old but the refresh
// attempt will fail.
long lastRefreshAttemptElapsedMillis;
@@ -586,7 +608,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect a refresh attempt to have been made.
verify(mMockNtpTrustedTime, times(1)).forceRefresh(mDummyNetwork);
@@ -606,7 +628,7 @@
reset(mMockNtpTrustedTime);
}
- // Simulate a second call to refreshIfRequiredAndReschedule() very soon after the first, as
+ // Simulate a second call to refreshAndRescheduleIfRequired() very soon after the first, as
// might happen if there were a network state change.
// The cached time value is available, but it's still too old. Because the last call was so
// recent, no refresh should take place and the next scheduled refresh time should be
@@ -619,7 +641,7 @@
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
// Trigger the engine's logic.
- engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+ engine.refreshAndRescheduleIfRequired(mDummyNetwork, "Test", mockCallback);
// Expect no refresh attempt to have been made: time elapsed isn't enough.
verify(mMockNtpTrustedTime, never()).forceRefresh(any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 28e493e..e3cb5fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -145,7 +145,8 @@
public class ActivityStarterTests extends WindowTestsBase {
private static final String ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER =
- "enable_default_rescind_bal_privileges_from_pending_intent_sender";
+ "DefaultRescindBalPrivilegesFromPendingIntentSender__"
+ + "enable_default_rescind_bal_privileges_from_pending_intent_sender";
private static final int PRECONDITION_NO_CALLER_APP = 1;
private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index d4374a9..fd54293 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1049,7 +1049,8 @@
@Override
public int startAssistantActivity(@NonNull IBinder token, @NonNull Intent intent,
- @Nullable String resolvedType, @Nullable String attributionTag) {
+ @Nullable String resolvedType, @NonNull String attributionTag,
+ @NonNull Bundle bundle) {
synchronized (this) {
if (mImpl == null) {
Slog.w(TAG, "startAssistantActivity without running voice interaction service");
@@ -1060,7 +1061,7 @@
final long caller = Binder.clearCallingIdentity();
try {
return mImpl.startAssistantActivityLocked(attributionTag, callingPid,
- callingUid, token, intent, resolvedType);
+ callingUid, token, intent, resolvedType, bundle);
} finally {
Binder.restoreCallingIdentity(caller);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index ad0e921..96b69f8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -29,7 +29,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.ApplicationExitInfo;
@@ -376,7 +375,8 @@
@GuardedBy("this")
public int startAssistantActivityLocked(@Nullable String callingFeatureId, int callingPid,
- int callingUid, IBinder token, Intent intent, String resolvedType) {
+ int callingUid, IBinder token, Intent intent, String resolvedType,
+ @NonNull Bundle bundle) {
try {
if (mActiveSession == null || token != mActiveSession.mToken) {
Slog.w(TAG, "startAssistantActivity does not match active session");
@@ -388,10 +388,10 @@
}
intent = new Intent(intent);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchActivityType(ACTIVITY_TYPE_ASSISTANT);
+ // TODO: make the key public hidden
+ bundle.putInt("android.activity.activityType", ACTIVITY_TYPE_ASSISTANT);
return mAtm.startAssistantActivity(mComponent.getPackageName(), callingFeatureId,
- callingPid, callingUid, intent, resolvedType, options.toBundle(), mUser);
+ callingPid, callingUid, intent, resolvedType, bundle, mUser);
} catch (RemoteException e) {
throw new IllegalStateException("Unexpected remote error", e);
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 707b522..f2ffc19 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -24,7 +24,11 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="run-command" value="settings put system show_touches 1" />
+ <option name="run-command" value="settings put system pointer_location 1" />
<option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
+ <option name="teardown-command" value="settings delete system show_touches" />
+ <option name="teardown-command" value="settings delete system pointer_location" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index a7c5479..a766bd4 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -26,8 +26,8 @@
namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
-static const auto sDevelopmentSdkCodeNames =
- std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
+static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>(
+ {"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake", "VanillaIceCream"});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x021c, 1},
diff --git a/tools/processors/immutability/TEST_MAPPING b/tools/processors/immutability/TEST_MAPPING
deleted file mode 100644
index 4e8e238..0000000
--- a/tools/processors/immutability/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "ImmutabilityAnnotationProcessorUnitTests"
- }
- ]
-}