summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt5
-rw-r--r--media/java/android/media/AudioManager.java91
-rw-r--r--media/java/android/media/IAudioService.aidl17
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java72
-rw-r--r--services/core/java/com/android/server/audio/FocusRequester.java11
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java152
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java11
7 files changed, 1 insertions, 358 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 3a4c3f2b32bd..833d9c6d2420 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1877,8 +1877,6 @@ package android.media {
public class AudioManager {
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int abandonAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String);
- method @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") public boolean enterAudioFocusFreezeForTest(@NonNull java.util.List<java.lang.Integer>);
- method @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") public boolean exitAudioFocusFreezeForTest();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void forceComputeCsdOnAllDevices(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void forceUseFrameworkMel(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat);
@@ -1886,9 +1884,6 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public float getCsd();
method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
- method @NonNull @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public java.util.List<java.lang.Integer> getFocusDuckedUidsForTest();
- method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFocusFadeOutDurationForTest();
- method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFocusUnmuteDelayAfterFadeOutForTest();
method @Nullable public static android.media.AudioHalVersionInfo getHalVersion();
method public static final int[] getPublicStreamTypes();
method @NonNull public java.util.List<java.lang.Integer> getReportedSurroundFormats();
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9b48677ca892..e8c9d0dbd884 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4739,97 +4739,6 @@ public class AudioManager {
/**
* @hide
- * Test method to return the list of UIDs currently marked as ducked because of their
- * audio focus status
- * @return the list of UIDs, can be empty when no app is being ducked.
- */
- @TestApi
- @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
- public @NonNull List<Integer> getFocusDuckedUidsForTest() {
- try {
- return getService().getFocusDuckedUidsForTest();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- * Test method to return the duration of the fade out applied on the players of a focus loser
- * @return the fade out duration in ms
- */
- @TestApi
- @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
- public long getFocusFadeOutDurationForTest() {
- try {
- return getService().getFocusFadeOutDurationForTest();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- * Test method to return the length of time after a fade-out before the focus loser is unmuted
- * (and is faded back in).
- * @return the time gap after a fade-out completion on focus loss, and fade-in start in ms.
- */
- @TestApi
- @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
- public long getFocusUnmuteDelayAfterFadeOutForTest() {
- try {
- return getService().getFocusUnmuteDelayAfterFadeOutForTest();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- * Test method to start preventing applications from requesting audio focus during a test,
- * which could interfere with the functionality/behavior under test.
- * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest}
- * when the testing is done. If this is not the case (e.g. in case of a test crash),
- * a death observer mechanism will ensure the system is not left in a bad state, but this should
- * not be relied on when implementing tests.
- * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance
- * be those of the test runner and other players used in the test, or the "fake" UIDs used
- * for testing with {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}.
- * @return true if the focus freeze mode is successfully entered, false if there was an issue,
- * such as another freeze in place at the time of invocation.
- * A false result should result in a test failure as this would indicate the system is not
- * in a proper state with a predictable behavior for audio focus management.
- */
- @TestApi
- @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- public boolean enterAudioFocusFreezeForTest(@NonNull List<Integer> exemptedUids) {
- Objects.requireNonNull(exemptedUids);
- try {
- final int[] uids = exemptedUids.stream().mapToInt(Integer::intValue).toArray();
- return getService().enterAudioFocusFreezeForTest(mICallBack, uids);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- * Test method to end preventing applications from requesting audio focus during a test.
- * @return true if the focus freeze mode is successfully exited, false if there was an issue,
- * such as the freeze already having ended, or not started.
- */
- @TestApi
- @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- public boolean exitAudioFocusFreezeForTest() {
- try {
- return getService().exitAudioFocusFreezeForTest(mICallBack);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
* Request or lock audio focus.
* This method is to be used by system components that have registered an
* {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 58378941c7ef..b2466e990b8f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -520,23 +520,6 @@ interface IAudioService {
long getFadeOutDurationOnFocusLossMillis(in AudioAttributes aa);
- @EnforcePermission("QUERY_AUDIO_STATE")
- /* Returns a List<Integer> */
- @SuppressWarnings(value = {"untyped-collection"})
- List getFocusDuckedUidsForTest();
-
- @EnforcePermission("QUERY_AUDIO_STATE")
- long getFocusFadeOutDurationForTest();
-
- @EnforcePermission("QUERY_AUDIO_STATE")
- long getFocusUnmuteDelayAfterFadeOutForTest();
-
- @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- boolean enterAudioFocusFreezeForTest(IBinder cb, in int[] uids);
-
- @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- boolean exitAudioFocusFreezeForTest(IBinder cb);
-
void registerModeDispatcher(IAudioModeDispatcher dispatcher);
oneway void unregisterModeDispatcher(IAudioModeDispatcher dispatcher);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b6411191a372..76c4cfe929bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -43,7 +43,6 @@ import static com.android.server.utils.EventLogger.Event.ALOGI;
import static com.android.server.utils.EventLogger.Event.ALOGW;
import android.Manifest;
-import android.annotation.EnforcePermission;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -9999,14 +9998,6 @@ public class AudioService extends IAudioService.Stub
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
}
- /** see {@link AudioManager#getFocusDuckedUidsForTest()} */
- @Override
- @EnforcePermission("QUERY_AUDIO_STATE")
- public @NonNull List<Integer> getFocusDuckedUidsForTest() {
- super.getFocusDuckedUidsForTest_enforcePermission();
- return mPlaybackMonitor.getFocusDuckedUids();
- }
-
public void unregisterAudioFocusClient(String clientId) {
new MediaMetrics.Item(mMetricsId + "focus")
.set(MediaMetrics.Property.CLIENT_NAME, clientId)
@@ -10023,67 +10014,6 @@ public class AudioService extends IAudioService.Stub
return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
}
- /**
- * Test method to return the duration of the fade out applied on the players of a focus loser
- * @see AudioManager#getFocusFadeOutDurationForTest()
- * @return the fade out duration, in ms
- */
- public long getFocusFadeOutDurationForTest() {
- super.getFocusFadeOutDurationForTest_enforcePermission();
- return mMediaFocusControl.getFocusFadeOutDurationForTest();
- }
-
- /**
- * Test method to return the length of time after a fade out before the focus loser is unmuted
- * (and is faded back in).
- * @see AudioManager#getFocusUnmuteDelayAfterFadeOutForTest()
- * @return the time gap after a fade out completion on focus loss, and fade in start, in ms
- */
- @Override
- @EnforcePermission("QUERY_AUDIO_STATE")
- public long getFocusUnmuteDelayAfterFadeOutForTest() {
- super.getFocusUnmuteDelayAfterFadeOutForTest_enforcePermission();
- return mMediaFocusControl.getFocusUnmuteDelayAfterFadeOutForTest();
- }
-
- /**
- * Test method to start preventing applications from requesting audio focus during a test,
- * which could interfere with the testing of the functionality/behavior under test.
- * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest}
- * when the testing is done. If this is not the case (e.g. in case of a test crash),
- * a death observer mechanism will ensure the system is not left in a bad state, but this should
- * not be relied on when implementing tests.
- * @see AudioManager#enterAudioFocusFreezeForTest(List)
- * @param cb IBinder to track the death of the client of this method
- * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance
- * be those of the test runner and other players used in the test
- * @return true if the focus freeze mode is successfully entered, false if there was an issue,
- * such as another freeze currently used.
- */
- @Override
- @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- public boolean enterAudioFocusFreezeForTest(IBinder cb, int[] exemptedUids) {
- super.enterAudioFocusFreezeForTest_enforcePermission();
- Objects.requireNonNull(exemptedUids);
- Objects.requireNonNull(cb);
- return mMediaFocusControl.enterAudioFocusFreezeForTest(cb, exemptedUids);
- }
-
- /**
- * Test method to end preventing applications from requesting audio focus during a test.
- * @see AudioManager#exitAudioFocusFreezeForTest()
- * @param cb IBinder identifying the client of this method
- * @return true if the focus freeze mode is successfully exited, false if there was an issue,
- * such as the freeze already having ended, or not started.
- */
- @Override
- @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- public boolean exitAudioFocusFreezeForTest(IBinder cb) {
- super.exitAudioFocusFreezeForTest_enforcePermission();
- Objects.requireNonNull(cb);
- return mMediaFocusControl.exitAudioFocusFreezeForTest(cb);
- }
-
/** only public for mocking/spying, do not call outside of AudioService */
@VisibleForTesting
public boolean hasAudioFocusUsers() {
@@ -10091,8 +10021,6 @@ public class AudioService extends IAudioService.Stub
}
/** see {@link AudioManager#getFadeOutDurationOnFocusLossMillis(AudioAttributes)} */
- @Override
- @EnforcePermission("QUERY_AUDIO_STATE")
public long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
if (!enforceQueryAudioStateForTest("fade out duration")) {
return 0;
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 010d5f41bc7d..88a4b0531cb1 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -43,7 +43,7 @@ import java.io.PrintWriter;
public class FocusRequester {
// on purpose not using this classe's name, as it will only be used from MediaFocusControl
- private static final String TAG = "FocusRequester";
+ private static final String TAG = "MediaFocusControl";
private static final boolean DEBUG = false;
private AudioFocusDeathHandler mDeathHandler; // may be null
@@ -340,9 +340,6 @@ public class FocusRequester {
@GuardedBy("MediaFocusControl.mAudioFocusLock")
boolean handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck)
{
- if (DEBUG) {
- Log.i(TAG, "handleFocusLossFromGain for " + mClientId + " gain:" + focusGain);
- }
final int focusLoss = focusLossForGainRequest(focusGain);
handleFocusLoss(focusLoss, frWinner, forceDuck);
return (focusLoss == AudioManager.AUDIOFOCUS_LOSS);
@@ -381,9 +378,6 @@ public class FocusRequester {
@GuardedBy("MediaFocusControl.mAudioFocusLock")
void handleFocusLoss(int focusLoss, @Nullable final FocusRequester frWinner, boolean forceDuck)
{
- if (DEBUG) {
- Log.i(TAG, "handleFocusLoss for " + mClientId + " loss:" + focusLoss);
- }
try {
if (focusLoss != mFocusLossReceived) {
mFocusLossReceived = focusLoss;
@@ -433,9 +427,6 @@ public class FocusRequester {
toAudioFocusInfo(), true /* wasDispatched */);
mFocusLossWasNotified = true;
fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
- } else if (DEBUG) {
- Log.i(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
- + " to " + mClientId + " no IAudioFocusDispatcher");
}
}
} catch (android.os.RemoteException e) {
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 65f6c9b8d459..b2180962a96e 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -45,7 +45,6 @@ import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
@@ -123,23 +122,6 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
dumpMultiAudioFocus(pw);
}
- /**
- * Test method to return the duration of the fade out applied on the players of a focus loser
- * @return the fade out duration in ms
- */
- public long getFocusFadeOutDurationForTest() {
- return FadeOutManager.FADE_OUT_DURATION_MS;
- }
-
- /**
- * Test method to return the length of time after a fade out before the focus loser is unmuted
- * (and is faded back in).
- * @return the time gap after a fade out completion on focus loss, and fade in start in ms
- */
- public long getFocusUnmuteDelayAfterFadeOutForTest() {
- return FadeOutManager.DELAY_FADE_IN_OFFENDERS_MS;
- }
-
//=================================================================
// PlayerFocusEnforcer implementation
@Override
@@ -322,26 +304,17 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
@GuardedBy("mAudioFocusLock")
private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,
boolean forceDuck) {
- if (DEBUG) {
- Log.i(TAG, "propagateFocusLossFromGain_syncAf gain:" + focusGain);
- }
final List<String> clientsToRemove = new LinkedList<String>();
// going through the audio focus stack to signal new focus, traversing order doesn't
// matter as all entries respond to the same external focus gain
if (!mFocusStack.empty()) {
for (FocusRequester focusLoser : mFocusStack) {
- if (DEBUG) {
- Log.i(TAG, "propagateFocusLossFromGain_syncAf checking client:"
- + focusLoser.getClientId());
- }
final boolean isDefinitiveLoss =
focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
if (isDefinitiveLoss) {
clientsToRemove.add(focusLoser.getClientId());
}
}
- } else if (DEBUG) {
- Log.i(TAG, "propagateFocusLossFromGain_syncAf empty stack");
}
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
@@ -397,9 +370,6 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
@GuardedBy("mAudioFocusLock")
private void removeFocusStackEntry(String clientToRemove, boolean signal,
boolean notifyFocusFollowers) {
- if (DEBUG) {
- Log.i(TAG, "removeFocusStackEntry client:" + clientToRemove);
- }
AudioFocusInfo abandonSource = null;
// is the current top of the focus stack abandoning focus? (because of request, not death)
if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
@@ -1030,24 +1000,6 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
}
synchronized(mAudioFocusLock) {
- // check whether a focus freeze is in place and filter
- if (isFocusFrozenForTest()) {
- int focusRequesterUid;
- if ((flags & AudioManager.AUDIOFOCUS_FLAG_TEST)
- == AudioManager.AUDIOFOCUS_FLAG_TEST) {
- focusRequesterUid = testUid;
- } else {
- focusRequesterUid = Binder.getCallingUid();
- }
- if (isFocusFrozenForTestForUid(focusRequesterUid)) {
- Log.i(TAG, "requestAudioFocus: focus frozen for test for uid:"
- + focusRequesterUid);
- return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
- }
- Log.i(TAG, "requestAudioFocus: focus frozen for test but uid:" + focusRequesterUid
- + " is exempt");
- }
-
if (mFocusStack.size() > MAX_STACK_SIZE) {
Log.e(TAG, "Max AudioFocus stack size reached, failing requestAudioFocus()");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
@@ -1239,110 +1191,6 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
- /**
- * Reference to the caller of {@link #enterAudioFocusFreezeForTest(IBinder, int[])}
- * Will be null when there is no focus freeze for test
- */
- @GuardedBy("mAudioFocusLock")
- @Nullable
- private IBinder mFocusFreezerForTest = null;
-
- /**
- * The death handler for {@link #mFocusFreezerForTest}
- * Will be null when there is no focus freeze for test
- */
- @GuardedBy("mAudioFocusLock")
- @Nullable
- private IBinder.DeathRecipient mFocusFreezerDeathHandler = null;
-
- /**
- * Array of UIDs exempt from focus freeze when focus is frozen for test, null during normal
- * operations.
- * Will be null when there is no focus freeze for test
- */
- @GuardedBy("mAudioFocusLock")
- @Nullable
- private int[] mFocusFreezeExemptUids = null;
-
- @GuardedBy("mAudioFocusLock")
- private boolean isFocusFrozenForTest() {
- return (mFocusFreezerForTest != null);
- }
-
- /**
- * Checks if the given UID can request focus when a focus freeze is in place for a test.
- * Focus can be requested if focus is not frozen or if it's frozen but the UID is exempt.
- * @param uidToCheck
- * @return true if that UID is barred from requesting focus, false if its focus request
- * can proceed being processed
- */
- @GuardedBy("mAudioFocusLock")
- private boolean isFocusFrozenForTestForUid(int uidToCheck) {
- if (isFocusFrozenForTest()) {
- return false;
- }
- // check the list of exempts (array is not null because we're in a freeze for test
- for (int uid : mFocusFreezeExemptUids) {
- if (uid == uidToCheck) {
- return false;
- }
- }
- // uid was not found in the exempt list, its focus request is denied
- return true;
- }
-
- protected boolean enterAudioFocusFreezeForTest(
- @NonNull IBinder cb, @NonNull int[] exemptedUids) {
- Log.i(TAG, "enterAudioFocusFreezeForTest UIDs exempt:" + Arrays.toString(exemptedUids));
- synchronized (mAudioFocusLock) {
- if (mFocusFreezerForTest != null) {
- Log.e(TAG, "Error enterAudioFocusFreezeForTest: focus already frozen");
- return false;
- }
- // new focus freeze, register death handler
- try {
- mFocusFreezerDeathHandler = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- Log.i(TAG, "Audio focus freezer died, exiting focus freeze for test");
- releaseFocusFreeze();
- }
- };
- cb.linkToDeath(mFocusFreezerDeathHandler, 0);
- mFocusFreezerForTest = cb;
- mFocusFreezeExemptUids = exemptedUids.clone();
- } catch (RemoteException e) {
- // client has already died!
- mFocusFreezerForTest = null;
- mFocusFreezeExemptUids = null;
- return false;
- }
- }
- return true;
- }
-
- protected boolean exitAudioFocusFreezeForTest(@NonNull IBinder cb) {
- synchronized (mAudioFocusLock) {
- if (mFocusFreezerForTest != cb) {
- Log.e(TAG, "Error exitAudioFocusFreezeForTest: "
- + ((mFocusFreezerForTest == null)
- ? "call to exit while not frozen"
- : "call to exit not coming from freeze owner"));
- return false;
- }
- mFocusFreezerForTest.unlinkToDeath(mFocusFreezerDeathHandler, 0);
- releaseFocusFreeze();
- }
- return true;
- }
-
- private void releaseFocusFreeze() {
- synchronized (mAudioFocusLock) {
- mFocusFreezerDeathHandler = null;
- mFocusFreezeExemptUids = null;
- mFocusFreezerForTest = null;
- }
- }
protected void unregisterAudioFocusClient(String clientId) {
synchronized(mAudioFocusLock) {
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 54fa6fbc3bfd..23a0782dc8a3 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -1208,17 +1208,6 @@ public final class PlaybackActivityMonitor
}
}
- protected @NonNull List<Integer> getFocusDuckedUids() {
- final ArrayList<Integer> duckedUids;
- synchronized (mPlayerLock) {
- duckedUids = new ArrayList(mDuckingManager.mDuckers.keySet());
- }
- if (DEBUG) {
- Log.i(TAG, "current ducked UIDs: " + duckedUids);
- }
- return duckedUids;
- }
-
//=================================================================
// For logging
private static final class PlayerEvent extends EventLogger.Event {